fix(composer): tokenizing text field trigger logic moved to composer

This commit is contained in:
Evan Morikawa 2016-09-30 20:16:13 -05:00
parent 83f455f031
commit b540bbb601
4 changed files with 63 additions and 23 deletions

View file

@ -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: []

View file

@ -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)

View file

@ -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,

View file

@ -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