diff --git a/browser/lib/search.js b/browser/lib/search.js index 1914bb81..d102e381 100644 --- a/browser/lib/search.js +++ b/browser/lib/search.js @@ -2,15 +2,16 @@ import _ from 'lodash' export default function searchFromNotes (notes, search) { if (search.trim().length === 0) return [] - let searchBlocks = search.split(' ') + const searchBlocks = search.split(' ').filter(block => { return block !== '' }) + + let foundNotes = findByWord(notes, searchBlocks[0]) searchBlocks.forEach((block) => { + foundNotes = findByWord(foundNotes, block) if (block.match(/^#.+/)) { - notes = findByTag(notes, block) - } else { - notes = findByWord(notes, block) + foundNotes = foundNotes.concat(findByTag(notes, block)) } }) - return notes + return foundNotes } function findByTag (notes, block) { diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 682c755d..6f3860eb 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -52,6 +52,8 @@ class NoteList extends React.Component { this.state = { } + + this.contextNotes = [] } componentDidMount () { @@ -90,6 +92,7 @@ class NoteList extends React.Component { if (this.notes.length > 0 && location.query.key == null) { let { router } = this.context + if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes() router.replace({ pathname: location.pathname, query: { @@ -234,48 +237,50 @@ class NoteList extends React.Component { let { router } = this.context if (location.pathname.match(/\/home/)) { - return data.noteMap.map((note) => note) + const allNotes = data.noteMap.map((note) => note) + this.contextNotes = allNotes + return allNotes } if (location.pathname.match(/\/starred/)) { - return data.starredSet.toJS() - .map((uniqueKey) => data.noteMap.get(uniqueKey)) + const starredNotes = data.starredSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey)) + this.contextNotes = starredNotes + return starredNotes } if (location.pathname.match(/\/searched/)) { const searchInputText = document.getElementsByClassName('searchInput')[0].value if (searchInputText === '') { - router.push('/home') + return this.contextNotes } - return searchFromNotes(this.notes, searchInputText) + return searchFromNotes(this.contextNotes, searchInputText) } if (location.pathname.match(/\/trashed/)) { - return data.trashedSet.toJS() - .map((uniqueKey) => data.noteMap.get(uniqueKey)) + const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey)) + this.contextNotes = trashedNotes + return trashedNotes } - let storageKey = params.storageKey - let folderKey = params.folderKey - let storage = data.storageMap.get(storageKey) - if (storage == null) return [] + return this.getContextNotes() + } - let folder = _.find(storage.folders, {key: folderKey}) - if (folder == null) { - let storageNoteSet = data.storageNoteMap - .get(storage.key) - if (storageNoteSet == null) storageNoteSet = [] - return storageNoteSet - .map((uniqueKey) => data.noteMap.get(uniqueKey)) + // get notes in the current folder + getContextNotes () { + const { data, params } = this.props + const storageKey = params.storageKey + const folderKey = params.folderKey + const storage = data.storageMap.get(storageKey) + if (storage === undefined) return [] + + const folder = _.find(storage.folders, {key: folderKey}) + if (folder === undefined) { + const storageNoteSet = data.storageNoteMap.get(storage.key) || [] + return storageNoteSet.map((uniqueKey) => data.noteMap.get(uniqueKey)) } - let folderNoteKeyList = data.folderNoteMap - .get(storage.key + '-' + folder.key) - - return folderNoteKeyList != null - ? folderNoteKeyList - .map((uniqueKey) => data.noteMap.get(uniqueKey)) - : [] + const folderNoteKeyList = data.folderNoteMap.get(`${storage.key}-${folder.key}`) || [] + return folderNoteKeyList.map((uniqueKey) => data.noteMap.get(uniqueKey)) } handleNoteClick (e, uniqueKey) { diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js index c469adb4..2c34ebf2 100644 --- a/browser/main/TopBar/index.js +++ b/browser/main/TopBar/index.js @@ -18,7 +18,10 @@ class TopBar extends React.Component { this.state = { search: '', searchOptions: [], - isSearching: false + isSearching: false, + isAlphabet: false, + isIME: false, + isConfirmTranslation: false } this.focusSearchHandler = () => { @@ -34,9 +37,52 @@ class TopBar extends React.Component { ee.off('top:focus-search', this.focusSearchHandler) } + handleKeyDown (e) { + // reset states + this.setState({ + isAlphabet: false, + isIME: false + }) + + // When the key is an alphabet, del, enter or ctr + if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) { + this.setState({ + isAlphabet: true + }) + // When the key is an IME input (Japanese, Chinese) + } else if (e.keyCode === 229) { + this.setState({ + isIME: true + }) + } + } + + handleKeyUp (e) { + const { router } = this.context + // reset states + this.setState({ + isConfirmTranslation: false + }) + + // When the key is translation confirmation (Enter, Space) + if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) { + this.setState({ + isConfirmTranslation: true + }) + router.push('/searched') + this.setState({ + search: this.refs.searchInput.value + }) + } + } + handleSearchChange (e) { - let { router } = this.context - router.push('/searched') + const { router } = this.context + if (this.state.isAlphabet || this.state.isConfirmTranslation) { + router.push('/searched') + } else { + e.preventDefault() + } this.setState({ search: this.refs.searchInput.value }) @@ -93,6 +139,8 @@ class TopBar extends React.Component { ref='searchInput' value={this.state.search} onChange={(e) => this.handleSearchChange(e)} + onKeyDown={(e) => this.handleKeyDown(e)} + onKeyUp={(e) => this.handleKeyUp(e)} placeholder='Search' type='text' className='searchInput' diff --git a/tests/lib/search-test.js b/tests/lib/search-test.js index e99a3612..1550a08f 100644 --- a/tests/lib/search-test.js +++ b/tests/lib/search-test.js @@ -6,26 +6,30 @@ import _ from 'lodash' const pickContents = (notes) => notes.map((note) => { return note.content }) let notes = [] -let note1, note2 +let note1, note2, note3 test.before(t => { const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] } const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] } + const data3 = { type: 'MARKDOWN_NOTE', content: '#content4', tags: ['tag1'] } + note1 = dummyNote(data1) note2 = dummyNote(data2) + note3 = dummyNote(data3) - notes = [note1, note2] + notes = [note1, note2, note3] }) test('it can find notes by tags or words', t => { // [input, expected content (Array)] const testCases = [ - ['#tag1', [note1.content, note2.content]], + ['#tag1', [note1.content, note2.content, note3.content]], ['#tag1 #tag2', [note2.content]], ['#tag1 #tag2 #tag3', []], ['content1', [note1.content, note2.content]], ['content1 content2', [note2.content]], - ['content1 content2 content3', []] + ['content1 content2 content3', []], + ['#content4', [note3.content]] ] testCases.forEach((testCase) => {