mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-22 00:06:06 +08:00
fix(composer): tokenizing text field trigger logic moved to composer
This commit is contained in:
parent
83f455f031
commit
b540bbb601
|
@ -97,21 +97,31 @@ describe 'ParticipantsTextField', ->
|
|||
|
||||
it "should use the name of an existing contact in the ContactStore if possible", ->
|
||||
spyOn(ContactStore, 'searchContacts').andCallFake (val, options={}) ->
|
||||
return Promise.resolve([participant3]) if val is participant3.email
|
||||
return Promise.resolve([participant3]) if val is participant3.name
|
||||
return Promise.resolve([])
|
||||
|
||||
@expectInputToYield participant3.email,
|
||||
@expectInputToYield participant3.name,
|
||||
to: [participant1, participant2, participant3]
|
||||
cc: []
|
||||
bcc: []
|
||||
|
||||
it "should not allow the same contact to appear multiple times", ->
|
||||
it "should use the plain email if that's what's entered", ->
|
||||
spyOn(ContactStore, 'searchContacts').andCallFake (val, options={}) ->
|
||||
return Promise.resolve([participant2]) if val is participant2.email
|
||||
return Promise.resolve([participant3]) if val is participant3.email
|
||||
return Promise.resolve([])
|
||||
|
||||
@expectInputToYield participant2.email,
|
||||
to: [participant1, participant2]
|
||||
@expectInputToYield participant3.email,
|
||||
to: [participant1, participant2, new Contact(email: "evan@nylas.com")]
|
||||
cc: []
|
||||
bcc: []
|
||||
|
||||
it "should not have the same contact auto-picked multiple times", ->
|
||||
spyOn(ContactStore, 'searchContacts').andCallFake (val, options={}) ->
|
||||
return Promise.resolve([participant2]) if val is participant2.name
|
||||
return Promise.resolve([])
|
||||
|
||||
@expectInputToYield participant2.name,
|
||||
to: [participant1, participant2, new Contact(email: participant2.name, name: participant2.name)]
|
||||
cc: [participant3]
|
||||
bcc: []
|
||||
|
||||
|
|
|
@ -211,11 +211,6 @@ describe 'TokenizingTextField', ->
|
|||
ReactTestUtils.Simulate.mouseDown(ReactDOM.findDOMNode(menuItem))
|
||||
expect(@propAdd).toHaveBeenCalledWith([participant4])
|
||||
|
||||
it "manually enters whatever's in the field when the user presses the space bar as long as it looks like an email", ->
|
||||
ReactTestUtils.Simulate.change(@renderedInput, {target: {value: 'abc@foo.com '}})
|
||||
advanceClock(10)
|
||||
expect(@propAdd).toHaveBeenCalledWith("abc@foo.com", skipNameLookup: true)
|
||||
|
||||
it "doesn't sumbmit if it looks like an email but has no space at the end", ->
|
||||
ReactTestUtils.Simulate.change(@renderedInput, {target: {value: 'abc@foo.com'}})
|
||||
advanceClock(10)
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import _ from 'underscore';
|
||||
|
||||
import {remote, clipboard} from 'electron';
|
||||
import {Utils, Contact, ContactStore} from 'nylas-exports';
|
||||
import {Utils, Contact, ContactStore, RegExpUtils} from 'nylas-exports';
|
||||
import {TokenizingTextField, Menu, InjectedComponent, InjectedComponentSet} from 'nylas-component-kit';
|
||||
|
||||
const TokenRenderer = (props) => {
|
||||
|
@ -182,6 +182,21 @@ export default class ParticipantsTextField extends React.Component {
|
|||
menu.popup(remote.getCurrentWindow());
|
||||
}
|
||||
|
||||
_onInputTrySubmit = (inputValue, completions = [], selectedItem) => {
|
||||
if (RegExpUtils.emailRegex().test(inputValue)) {
|
||||
return inputValue // no token default to raw value.
|
||||
}
|
||||
return selectedItem || completions[0] // first completion if any
|
||||
}
|
||||
|
||||
_shouldBreakOnKeydown = (event) => {
|
||||
const val = event.target.value.trim();
|
||||
if (RegExpUtils.emailRegex().test(val) && event.key === " ") {
|
||||
return true
|
||||
}
|
||||
return [",", ";"].includes(event.key)
|
||||
}
|
||||
|
||||
render() {
|
||||
const classSet = {
|
||||
[this.props.field]: true,
|
||||
|
@ -202,6 +217,8 @@ export default class ParticipantsTextField extends React.Component {
|
|||
tokenIsValid: (p) => ContactStore.isValidContact(p),
|
||||
tokenRenderer: TokenRenderer,
|
||||
onRequestCompletions: (input) => ContactStore.searchContacts(input),
|
||||
shouldBreakOnKeydown: this._shouldBreakOnKeydown,
|
||||
onInputTrySubmit: this._onInputTrySubmit,
|
||||
completionNode: this._completionNode,
|
||||
onAdd: this._add,
|
||||
onRemove: this._remove,
|
||||
|
|
|
@ -229,6 +229,18 @@ class TokenizingTextField extends React.Component
|
|||
# updates this component's `tokens` prop.
|
||||
onAdd: React.PropTypes.func.isRequired
|
||||
|
||||
# This gets fired when people try and submit a query with a break
|
||||
# character (tab, comma, semicolon, etc). It lets us the caller
|
||||
# determine how to best deal with available options.
|
||||
#
|
||||
# If this method is not implemented we'll pick the first available
|
||||
# option in the completions
|
||||
onInputTrySubmit: React.PropTypes.func
|
||||
|
||||
# If implemented lets the caller determine when to cut a token based
|
||||
# on the current input value and the current keydown.
|
||||
shouldBreakOnKeydown: React.PropTypes.func
|
||||
|
||||
# Gets called when we remove a token
|
||||
#
|
||||
# It's passed an array of objects (the same ones used to render
|
||||
|
@ -414,7 +426,11 @@ class TokenizingTextField extends React.Component
|
|||
else if event.key in ["Tab", "Enter"]
|
||||
@_onInputTrySubmit(event)
|
||||
|
||||
else if event.keyCode is 188 # comma
|
||||
if @props.shouldBreakOnKeydown
|
||||
if @props.shouldBreakOnKeydown(event)
|
||||
event.preventDefault()
|
||||
@_onInputTrySubmit(event)
|
||||
else if event.key is "," # comma
|
||||
event.preventDefault() # never allow commas in the field
|
||||
@_onInputTrySubmit(event)
|
||||
|
||||
|
@ -422,8 +438,17 @@ class TokenizingTextField extends React.Component
|
|||
return if (@state.inputValue ? "").trim().length is 0
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
if @state.completions.length > 0
|
||||
@_addToken(@refs.completions.getSelectedItem() || @state.completions[0])
|
||||
|
||||
token = null
|
||||
if @props.onInputTrySubmit
|
||||
token = @props.onInputTrySubmit(@state.inputValue, @state.completions, @refs.completions.getSelectedItem())
|
||||
if (typeof token is 'string')
|
||||
return @_addInputValue(token, skipNameLookup: true)
|
||||
else if @state.completions.length > 0
|
||||
token = @refs.completions.getSelectedItem() || @state.completions[0]
|
||||
|
||||
if token
|
||||
@_addToken(token)
|
||||
else
|
||||
@_addInputValue()
|
||||
|
||||
|
@ -432,14 +457,7 @@ class TokenizingTextField extends React.Component
|
|||
@setState
|
||||
selectedTokenKey: null
|
||||
inputValue: val
|
||||
|
||||
# If it looks like an email, and the last character entered was a
|
||||
# space, then let's add the input value.
|
||||
# TODO WHY IS THIS EMAIL RELATED?
|
||||
if RegExpUtils.emailRegex().test(val) and _.last(val) is " "
|
||||
@_addInputValue(val[0...-1], skipNameLookup: true)
|
||||
else
|
||||
@_refreshCompletions(val)
|
||||
@_refreshCompletions(val)
|
||||
|
||||
_onInputBlurred: (event) =>
|
||||
# Not having a relatedTarget can happen when the whole app blurs. When
|
||||
|
|
Loading…
Reference in a new issue