mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-11 15:14:31 +08:00
fix(composer): Refactor header actions, clean up layout
Summary: WIP Remove the mode prop from everywhere, use NylasEnv.isComposerWindow() instead Test Plan: Run updated tests Reviewers: drew, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2766
This commit is contained in:
parent
400ccb1cdb
commit
b5fe01e5d0
9 changed files with 219 additions and 157 deletions
55
internal_packages/composer/lib/composer-header-actions.cjsx
Normal file
55
internal_packages/composer/lib/composer-header-actions.cjsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
React = require 'react'
|
||||||
|
Fields = require './fields'
|
||||||
|
{Actions} = require 'nylas-exports'
|
||||||
|
{RetinaImg} = require 'nylas-component-kit'
|
||||||
|
|
||||||
|
module.exports =
|
||||||
|
class ComposerHeaderActions extends React.Component
|
||||||
|
@displayName: 'ComposerHeaderActions'
|
||||||
|
|
||||||
|
@propTypes:
|
||||||
|
draftClientId: React.PropTypes.string.isRequired
|
||||||
|
focusedField: React.PropTypes.string
|
||||||
|
enabledFields: React.PropTypes.array.isRequired
|
||||||
|
onAdjustEnabledFields: React.PropTypes.func.isRequired
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
items = []
|
||||||
|
|
||||||
|
if @props.focusedField in Fields.ParticipantFields
|
||||||
|
if Fields.Cc not in @props.enabledFields
|
||||||
|
items.push(
|
||||||
|
<span className="action show-cc" key="cc"
|
||||||
|
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Cc]) }>Cc</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
if Fields.Bcc not in @props.enabledFields
|
||||||
|
items.push(
|
||||||
|
<span className="action show-bcc" key="bcc"
|
||||||
|
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Bcc]) }>Bcc</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
if Fields.Subject not in @props.enabledFields
|
||||||
|
items.push(
|
||||||
|
<span className="action show-subject" key="subject"
|
||||||
|
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Subject]) }>Subject</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
unless NylasEnv.isComposerWindow()
|
||||||
|
items.push(
|
||||||
|
<span className="action show-popout" key="popout"
|
||||||
|
title="Popout composer…"
|
||||||
|
style={paddingLeft: "1.5em"}
|
||||||
|
onClick={@_onPopoutComposer}>
|
||||||
|
<RetinaImg name="composer-popout.png"
|
||||||
|
mode={RetinaImg.Mode.ContentIsMask}
|
||||||
|
style={{position: "relative", top: "-2px"}}/>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
<div className="composer-header-actions">
|
||||||
|
{items}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
_onPopoutComposer: =>
|
||||||
|
Actions.composePopoutDraft(@props.draftClientId)
|
|
@ -26,6 +26,7 @@ FileUpload = require './file-upload'
|
||||||
ImageFileUpload = require './image-file-upload'
|
ImageFileUpload = require './image-file-upload'
|
||||||
|
|
||||||
ComposerEditor = require './composer-editor'
|
ComposerEditor = require './composer-editor'
|
||||||
|
ComposerHeaderActions = require './composer-header-actions'
|
||||||
SendActionButton = require './send-action-button'
|
SendActionButton = require './send-action-button'
|
||||||
ExpandedParticipants = require './expanded-participants'
|
ExpandedParticipants = require './expanded-participants'
|
||||||
CollapsedParticipants = require './collapsed-participants'
|
CollapsedParticipants = require './collapsed-participants'
|
||||||
|
@ -43,9 +44,6 @@ class ComposerView extends React.Component
|
||||||
@propTypes:
|
@propTypes:
|
||||||
draftClientId: React.PropTypes.string
|
draftClientId: React.PropTypes.string
|
||||||
|
|
||||||
# Either "inline" or "fullwindow"
|
|
||||||
mode: React.PropTypes.string
|
|
||||||
|
|
||||||
# If this composer is part of an existing thread (like inline
|
# If this composer is part of an existing thread (like inline
|
||||||
# composers) the threadId will be handed down
|
# composers) the threadId will be handed down
|
||||||
threadId: React.PropTypes.string
|
threadId: React.PropTypes.string
|
||||||
|
@ -207,37 +205,46 @@ class ComposerView extends React.Component
|
||||||
</DropZone>
|
</DropZone>
|
||||||
|
|
||||||
_renderScrollRegion: ->
|
_renderScrollRegion: ->
|
||||||
if @props.mode is "inline"
|
if NylasEnv.isComposerWindow()
|
||||||
@_renderContent()
|
|
||||||
else
|
|
||||||
<ScrollRegion className="compose-body-scroll" ref="scrollregion">
|
<ScrollRegion className="compose-body-scroll" ref="scrollregion">
|
||||||
{@_renderContent()}
|
{@_renderContent()}
|
||||||
</ScrollRegion>
|
</ScrollRegion>
|
||||||
|
else
|
||||||
|
@_renderContent()
|
||||||
|
|
||||||
_renderContent: =>
|
_renderContent: =>
|
||||||
<div className="composer-centered">
|
<div className="composer-centered">
|
||||||
{if @state.focusedField in Fields.ParticipantFields
|
<div className="composer-header">
|
||||||
<ExpandedParticipants
|
{if @state.draftReady
|
||||||
to={@state.to} cc={@state.cc} bcc={@state.bcc}
|
<ComposerHeaderActions
|
||||||
from={@state.from}
|
draftClientId={@props.draftClientId}
|
||||||
ref="expandedParticipants"
|
focusedField={@state.focusedField}
|
||||||
mode={@props.mode}
|
enabledFields={@state.enabledFields}
|
||||||
accounts={@state.accounts}
|
onAdjustEnabledFields={@_onAdjustEnabledFields}
|
||||||
draftReady={@state.draftReady}
|
/>
|
||||||
focusedField={@state.focusedField}
|
}
|
||||||
enabledFields={@state.enabledFields}
|
{if @state.focusedField in Fields.ParticipantFields
|
||||||
onPopoutComposer={@_onPopoutComposer}
|
<ExpandedParticipants
|
||||||
onChangeParticipants={@_onChangeParticipants}
|
to={@state.to} cc={@state.cc} bcc={@state.bcc}
|
||||||
onChangeFocusedField={@_onChangeFocusedField}
|
from={@state.from}
|
||||||
onAdjustEnabledFields={@_onAdjustEnabledFields} />
|
ref="expandedParticipants"
|
||||||
else
|
accounts={@state.accounts}
|
||||||
<CollapsedParticipants
|
draftReady={@state.draftReady}
|
||||||
to={@state.to} cc={@state.cc} bcc={@state.bcc}
|
focusedField={@state.focusedField}
|
||||||
onClick={@_onExpandParticipantFields} />
|
enabledFields={@state.enabledFields}
|
||||||
}
|
onPopoutComposer={@_onPopoutComposer}
|
||||||
|
onChangeParticipants={@_onChangeParticipants}
|
||||||
{@_renderSubject()}
|
onChangeFocusedField={@_onChangeFocusedField}
|
||||||
|
onAdjustEnabledFields={@_onAdjustEnabledFields} />
|
||||||
|
else
|
||||||
|
<CollapsedParticipants
|
||||||
|
to={@state.to} cc={@state.cc} bcc={@state.bcc}
|
||||||
|
onPopoutComposer={@_onPopoutComposer}
|
||||||
|
onClick={@_onExpandParticipantFields} />
|
||||||
|
}
|
||||||
|
|
||||||
|
{@_renderSubject()}
|
||||||
|
</div>
|
||||||
<div className="compose-body"
|
<div className="compose-body"
|
||||||
ref="composeBody"
|
ref="composeBody"
|
||||||
onMouseUp={@_onMouseUpComposerBody}
|
onMouseUp={@_onMouseUpComposerBody}
|
||||||
|
@ -247,10 +254,6 @@ class ComposerView extends React.Component
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
_onPopoutComposer: =>
|
|
||||||
return unless @state.draftReady
|
|
||||||
Actions.composePopoutDraft @props.draftClientId
|
|
||||||
|
|
||||||
_onKeyDown: (event) =>
|
_onKeyDown: (event) =>
|
||||||
if event.key is "Tab"
|
if event.key is "Tab"
|
||||||
@_onTabDown(event)
|
@_onTabDown(event)
|
||||||
|
@ -430,17 +433,22 @@ class ComposerView extends React.Component
|
||||||
_renderActionsRegion: =>
|
_renderActionsRegion: =>
|
||||||
return <div></div> unless @props.draftClientId
|
return <div></div> unless @props.draftClientId
|
||||||
<div className="composer-action-bar-content">
|
<div className="composer-action-bar-content">
|
||||||
<InjectedComponentSet className="composer-action-bar-plugins"
|
<InjectedComponentSet
|
||||||
matching={role: "Composer:ActionButton"}
|
className="composer-action-bar-plugins"
|
||||||
exposedProps={draftClientId:@props.draftClientId, threadId: @props.threadId}></InjectedComponentSet>
|
matching={role: "Composer:ActionButton"}
|
||||||
|
exposedProps={draftClientId: @props.draftClientId, threadId: @props.threadId} />
|
||||||
|
|
||||||
<button className="btn btn-toolbar btn-trash" style={order: 100}
|
<button className="btn btn-toolbar btn-trash" style={order: 100}
|
||||||
title="Delete draft"
|
title="Delete draft"
|
||||||
onClick={@_destroyDraft}><RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
|
onClick={@_destroyDraft}>
|
||||||
|
<RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
|
||||||
<button className="btn btn-toolbar btn-attach" style={order: 50}
|
<button className="btn btn-toolbar btn-attach" style={order: 50}
|
||||||
title="Attach file"
|
title="Attach file"
|
||||||
onClick={@_selectAttachment}><RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
|
onClick={@_selectAttachment}>
|
||||||
|
<RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
|
||||||
<div style={order: 0, flex: 1} />
|
<div style={order: 0, flex: 1} />
|
||||||
|
|
||||||
|
@ -522,7 +530,7 @@ class ComposerView extends React.Component
|
||||||
return Fields.To if draft.to.length is 0
|
return Fields.To if draft.to.length is 0
|
||||||
return Fields.Subject if (draft.subject ? "").trim().length is 0
|
return Fields.Subject if (draft.subject ? "").trim().length is 0
|
||||||
|
|
||||||
shouldFocusBody = @props.mode isnt 'inline' or draft.pristine or
|
shouldFocusBody = NylasEnv.isComposerWindow() or draft.pristine or
|
||||||
(FocusedContentStore.didFocusUsingClick('thread') is true)
|
(FocusedContentStore.didFocusUsingClick('thread') is true)
|
||||||
return Fields.Body if shouldFocusBody
|
return Fields.Body if shouldFocusBody
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -35,9 +35,6 @@ class ExpandedParticipants extends React.Component
|
||||||
# The account to which the current draft belongs
|
# The account to which the current draft belongs
|
||||||
accounts: React.PropTypes.array
|
accounts: React.PropTypes.array
|
||||||
|
|
||||||
# Either "fullwindow" or "inline"
|
|
||||||
mode: React.PropTypes.string
|
|
||||||
|
|
||||||
# The field that should be focused
|
# The field that should be focused
|
||||||
focusedField: React.PropTypes.string
|
focusedField: React.PropTypes.string
|
||||||
|
|
||||||
|
@ -74,8 +71,7 @@ class ExpandedParticipants extends React.Component
|
||||||
@_applyFocusedField()
|
@_applyFocusedField()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
<div className="expanded-participants"
|
<div className="expanded-participants" ref="participantWrap">
|
||||||
ref="participantWrap">
|
|
||||||
{@_renderFields()}
|
{@_renderFields()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -92,43 +88,15 @@ class ExpandedParticipants extends React.Component
|
||||||
# If they're hidden, shift-tab between fields breaks.
|
# If they're hidden, shift-tab between fields breaks.
|
||||||
fields = []
|
fields = []
|
||||||
fields.push(
|
fields.push(
|
||||||
<div key="to">
|
<ParticipantsTextField
|
||||||
<div className="composer-participant-actions">
|
ref={Fields.To}
|
||||||
{if Fields.Cc not in @props.enabledFields
|
key="to"
|
||||||
<span className="header-action show-cc"
|
field='to'
|
||||||
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Cc]) }>Cc</span>
|
change={@props.onChangeParticipants}
|
||||||
}
|
className="composer-participant-field to-field"
|
||||||
|
draftReady={@props.draftReady}
|
||||||
{ if Fields.Bcc not in @props.enabledFields
|
onFocus={ => @props.onChangeFocusedField(Fields.To) }
|
||||||
<span className="header-action show-bcc"
|
participants={to: @props['to'], cc: @props['cc'], bcc: @props['bcc']} />
|
||||||
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Bcc]) }>Bcc</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
{ if Fields.Subject not in @props.enabledFields
|
|
||||||
<span className="header-action show-subject"
|
|
||||||
onClick={ => @props.onAdjustEnabledFields(show: [Fields.Subject]) }>Subject</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
{ if @props.mode is "inline"
|
|
||||||
<span className="header-action show-popout"
|
|
||||||
title="Popout composer…"
|
|
||||||
style={paddingLeft: "1.5em"}
|
|
||||||
onClick={@props.onPopoutComposer}>
|
|
||||||
<RetinaImg name="composer-popout.png"
|
|
||||||
mode={RetinaImg.Mode.ContentIsMask}
|
|
||||||
style={{position: "relative", top: "-2px"}}/>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<ParticipantsTextField
|
|
||||||
ref={Fields.To}
|
|
||||||
field='to'
|
|
||||||
change={@props.onChangeParticipants}
|
|
||||||
className="composer-participant-field to-field"
|
|
||||||
draftReady={@props.draftReady}
|
|
||||||
onFocus={ => @props.onChangeFocusedField(Fields.To) }
|
|
||||||
participants={to: @props['to'], cc: @props['cc'], bcc: @props['bcc']} />
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if Fields.Cc in @props.enabledFields
|
if Fields.Cc in @props.enabledFields
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ComposerWithWindowProps extends React.Component
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
<div className="composer-full-window">
|
<div className="composer-full-window">
|
||||||
<ComposerView mode="fullwindow" draftClientId={@state.draftClientId} />
|
<ComposerView draftClientId={@state.draftClientId} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
_showInitialErrorDialog: (msg) ->
|
_showInitialErrorDialog: (msg) ->
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
React = require 'react'
|
||||||
|
ComposerHeaderActions = require '../lib/composer-header-actions'
|
||||||
|
Fields = require '../lib/fields'
|
||||||
|
ReactTestUtils = React.addons.TestUtils
|
||||||
|
{Actions} = require 'nylas-exports'
|
||||||
|
|
||||||
|
describe "ComposerHeaderActions", ->
|
||||||
|
makeField = (props = {}) ->
|
||||||
|
@onChangeParticipants = jasmine.createSpy("onChangeParticipants")
|
||||||
|
@onAdjustEnabledFields = jasmine.createSpy("onAdjustEnabledFields")
|
||||||
|
props.onChangeParticipants = @onChangeParticipants
|
||||||
|
props.onAdjustEnabledFields = @onAdjustEnabledFields
|
||||||
|
props.enabledFields ?= []
|
||||||
|
props.draftClientId = 'a'
|
||||||
|
@component = ReactTestUtils.renderIntoDocument(
|
||||||
|
<ComposerHeaderActions {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
|
it "renders all 'show' fields when the focused field is one of the participant fields", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
showCc = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-cc")
|
||||||
|
showBcc = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-bcc")
|
||||||
|
showSubject = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-subject")
|
||||||
|
expect(showCc).toBeDefined()
|
||||||
|
expect(showBcc).toBeDefined()
|
||||||
|
expect(showSubject).toBeDefined()
|
||||||
|
|
||||||
|
it "does not render the 'show' fields when the focused field is outside the participant fields", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.Subject})
|
||||||
|
showCc = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-cc")
|
||||||
|
showBcc = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-bcc")
|
||||||
|
showSubject = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-subject")
|
||||||
|
expect(showCc.length).toBe 0
|
||||||
|
expect(showBcc.length).toBe 0
|
||||||
|
expect(showSubject.length).toBe 0
|
||||||
|
|
||||||
|
it "hides show cc if it's enabled", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To, enabledFields: [Fields.Cc]})
|
||||||
|
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-cc")
|
||||||
|
expect(els.length).toBe 0
|
||||||
|
|
||||||
|
it "hides show bcc if it's enabled", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To, enabledFields: [Fields.Bcc]})
|
||||||
|
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-bcc")
|
||||||
|
expect(els.length).toBe 0
|
||||||
|
|
||||||
|
it "hides show subject if it's enabled", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To, enabledFields: [Fields.Subject]})
|
||||||
|
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-subject")
|
||||||
|
expect(els.length).toBe 0
|
||||||
|
|
||||||
|
it "renders 'popout composer' in the inline mode", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-popout")
|
||||||
|
expect(els.length).toBe 1
|
||||||
|
|
||||||
|
it "doesn't render 'popout composer' if in a composer window", ->
|
||||||
|
spyOn(NylasEnv, 'isComposerWindow').andReturn(true)
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-popout")
|
||||||
|
expect(els.length).toBe 0
|
||||||
|
|
||||||
|
it "pops out the composer when clicked", ->
|
||||||
|
spyOn(Actions, "composePopoutDraft")
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-popout")
|
||||||
|
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
||||||
|
expect(Actions.composePopoutDraft).toHaveBeenCalled()
|
||||||
|
|
||||||
|
it "shows and focuses cc when clicked", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-cc")
|
||||||
|
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
||||||
|
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Cc]
|
||||||
|
|
||||||
|
it "shows and focuses bcc when clicked", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-bcc")
|
||||||
|
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
||||||
|
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Bcc]
|
||||||
|
|
||||||
|
it "shows subject when clicked", ->
|
||||||
|
makeField.call(@, {focusedField: Fields.To})
|
||||||
|
el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-subject")
|
||||||
|
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
||||||
|
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Subject]
|
|
@ -262,19 +262,21 @@ describe "ComposerView", ->
|
||||||
|
|
||||||
it "focuses the body if the composer is not inline", ->
|
it "focuses the body if the composer is not inline", ->
|
||||||
useDraft.call @, to: [u1], subject: "Yo"
|
useDraft.call @, to: [u1], subject: "Yo"
|
||||||
makeComposer.call @, {mode: 'fullWindow'}
|
spyOn(NylasEnv, 'isComposerWindow').andReturn(true)
|
||||||
|
makeComposer.call @
|
||||||
expect(@composer.state.focusedField).toBe Fields.Body
|
expect(@composer.state.focusedField).toBe Fields.Body
|
||||||
|
|
||||||
it "focuses the body if the composer is inline and the thread was focused via a click", ->
|
it "focuses the body if the composer is inline and the thread was focused via a click", ->
|
||||||
spyOn(FocusedContentStore, 'didFocusUsingClick').andReturn true
|
spyOn(FocusedContentStore, 'didFocusUsingClick').andReturn true
|
||||||
useDraft.call @, to: [u1], subject: "Yo"
|
useDraft.call @, to: [u1], subject: "Yo"
|
||||||
makeComposer.call @, {mode: 'inline'}
|
makeComposer.call @
|
||||||
expect(@composer.state.focusedField).toBe Fields.Body
|
expect(@composer.state.focusedField).toBe Fields.Body
|
||||||
|
|
||||||
it "does not focus any field if the composer is inline and the thread was not focused via a click", ->
|
it "does not focus any field if the composer is inline and the thread was not focused via a click", ->
|
||||||
spyOn(FocusedContentStore, 'didFocusUsingClick').andReturn false
|
spyOn(FocusedContentStore, 'didFocusUsingClick').andReturn false
|
||||||
|
spyOn(NylasEnv, 'isComposerWindow').andReturn(false)
|
||||||
useDraft.call @, to: [u1], subject: "Yo"
|
useDraft.call @, to: [u1], subject: "Yo"
|
||||||
makeComposer.call @, {mode: 'inline'}
|
makeComposer.call @
|
||||||
expect(@composer.state.focusedField).toBe null
|
expect(@composer.state.focusedField).toBe null
|
||||||
|
|
||||||
describe "when deciding whether or not to enable the subject", ->
|
describe "when deciding whether or not to enable the subject", ->
|
||||||
|
|
|
@ -36,67 +36,6 @@ describe "ExpandedParticipants", ->
|
||||||
el = ReactTestUtils.findRenderedComponentWithType(@fields, AccountContactField)
|
el = ReactTestUtils.findRenderedComponentWithType(@fields, AccountContactField)
|
||||||
expect(el).toBeDefined()
|
expect(el).toBeDefined()
|
||||||
|
|
||||||
it "renders all 'show' fields", ->
|
|
||||||
makeField.call(@)
|
|
||||||
showCc = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-cc")
|
|
||||||
showBcc = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-bcc")
|
|
||||||
showSubject = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-subject")
|
|
||||||
expect(showCc).toBeDefined()
|
|
||||||
expect(showBcc).toBeDefined()
|
|
||||||
expect(showSubject).toBeDefined()
|
|
||||||
|
|
||||||
it "hides show cc if it's enabled", ->
|
|
||||||
makeField.call(@, enabledFields: [Fields.Cc])
|
|
||||||
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "show-cc")
|
|
||||||
expect(els.length).toBe 0
|
|
||||||
|
|
||||||
it "hides show bcc if it's enabled", ->
|
|
||||||
makeField.call(@, enabledFields: [Fields.Bcc])
|
|
||||||
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "show-bcc")
|
|
||||||
expect(els.length).toBe 0
|
|
||||||
|
|
||||||
it "hides show subject if it's enabled", ->
|
|
||||||
makeField.call(@, enabledFields: [Fields.Subject])
|
|
||||||
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "show-subject")
|
|
||||||
expect(els.length).toBe 0
|
|
||||||
|
|
||||||
it "renders popout composer in the inline mode", ->
|
|
||||||
makeField.call(@, mode: "inline")
|
|
||||||
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "show-popout")
|
|
||||||
expect(els.length).toBe 1
|
|
||||||
|
|
||||||
it "doesn't render popout composer in the fullwindow mode", ->
|
|
||||||
makeField.call(@, mode: "fullwindow")
|
|
||||||
els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "show-popout")
|
|
||||||
expect(els.length).toBe 0
|
|
||||||
|
|
||||||
it "pops out the composer when clicked", ->
|
|
||||||
spyOn(Actions, "composePopoutDraft")
|
|
||||||
onPopoutComposer = jasmine.createSpy('onPopoutComposer')
|
|
||||||
makeField.call(@, mode: "inline", onPopoutComposer: onPopoutComposer)
|
|
||||||
el = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-popout")
|
|
||||||
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
|
||||||
expect(onPopoutComposer).toHaveBeenCalled()
|
|
||||||
expect(onPopoutComposer.calls.length).toBe 1
|
|
||||||
|
|
||||||
it "shows and focuses cc when clicked", ->
|
|
||||||
makeField.call(@)
|
|
||||||
el = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-cc")
|
|
||||||
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
|
||||||
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Cc]
|
|
||||||
|
|
||||||
it "shows and focuses bcc when clicked", ->
|
|
||||||
makeField.call(@)
|
|
||||||
el = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-bcc")
|
|
||||||
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
|
||||||
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Bcc]
|
|
||||||
|
|
||||||
it "shows subject when clicked", ->
|
|
||||||
makeField.call(@)
|
|
||||||
el = ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "show-subject")
|
|
||||||
ReactTestUtils.Simulate.click(React.findDOMNode(el))
|
|
||||||
expect(@onAdjustEnabledFields).toHaveBeenCalledWith show: [Fields.Subject]
|
|
||||||
|
|
||||||
it "empties cc and focuses on to field", ->
|
it "empties cc and focuses on to field", ->
|
||||||
makeField.call(@, enabledFields: [Fields.Cc, Fields.Bcc, Fields.Subject])
|
makeField.call(@, enabledFields: [Fields.Cc, Fields.Bcc, Fields.Subject])
|
||||||
@fields.refs[Fields.Cc].props.onEmptied()
|
@fields.refs[Fields.Cc].props.onEmptied()
|
||||||
|
|
|
@ -127,19 +127,7 @@ body.platform-win32 {
|
||||||
top: -3px;
|
top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-action {
|
.composer-header-actions {
|
||||||
color: @text-color-very-subtle;
|
|
||||||
img.content-mask { background-color: @text-color-very-subtle; }
|
|
||||||
font-size: @font-size-small;
|
|
||||||
padding-left: 1em;
|
|
||||||
&:hover {
|
|
||||||
color: @text-color-link;
|
|
||||||
img.content-mask { background-color: @text-color-link; }
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.composer-participant-actions {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
float: right;
|
float: right;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
@ -147,6 +135,18 @@ body.platform-win32 {
|
||||||
padding-right: @spacing-standard + @spacing-half;
|
padding-right: @spacing-standard + @spacing-half;
|
||||||
padding-left: @spacing-standard;
|
padding-left: @spacing-standard;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
color: @text-color-very-subtle;
|
||||||
|
img.content-mask { background-color: @text-color-very-subtle; }
|
||||||
|
font-size: @font-size-small;
|
||||||
|
padding-left: 1em;
|
||||||
|
&:hover {
|
||||||
|
color: @text-color-link;
|
||||||
|
img.content-mask { background-color: @text-color-link; }
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input, textarea {
|
input, textarea {
|
||||||
|
|
|
@ -19,6 +19,10 @@ class DestroyDraftTask extends BaseDraftTask
|
||||||
@refreshDraftReference().then =>
|
@refreshDraftReference().then =>
|
||||||
DatabaseStore.inTransaction (t) =>
|
DatabaseStore.inTransaction (t) =>
|
||||||
t.unpersistModel(@draft)
|
t.unpersistModel(@draft)
|
||||||
|
.catch (err) =>
|
||||||
|
if err instanceof BaseDraftTask.DraftNotFoundError
|
||||||
|
return Promise.resolve()
|
||||||
|
Promsie.reject(err)
|
||||||
|
|
||||||
performRemote: ->
|
performRemote: ->
|
||||||
# We don't need to do anything if we weren't able to find the draft
|
# We don't need to do anything if we weren't able to find the draft
|
||||||
|
|
Loading…
Add table
Reference in a new issue