mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 02:06:29 +00:00
Merge pull request #954 from asmsuechan/improve-searching
Improve searching
This commit is contained in:
@@ -2,15 +2,16 @@ import _ from 'lodash'
|
|||||||
|
|
||||||
export default function searchFromNotes (notes, search) {
|
export default function searchFromNotes (notes, search) {
|
||||||
if (search.trim().length === 0) return []
|
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) => {
|
searchBlocks.forEach((block) => {
|
||||||
|
foundNotes = findByWord(foundNotes, block)
|
||||||
if (block.match(/^#.+/)) {
|
if (block.match(/^#.+/)) {
|
||||||
notes = findByTag(notes, block)
|
foundNotes = foundNotes.concat(findByTag(notes, block))
|
||||||
} else {
|
|
||||||
notes = findByWord(notes, block)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return notes
|
return foundNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
function findByTag (notes, block) {
|
function findByTag (notes, block) {
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ class NoteList extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.contextNotes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -90,6 +92,7 @@ class NoteList extends React.Component {
|
|||||||
|
|
||||||
if (this.notes.length > 0 && location.query.key == null) {
|
if (this.notes.length > 0 && location.query.key == null) {
|
||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
|
if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes()
|
||||||
router.replace({
|
router.replace({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {
|
query: {
|
||||||
@@ -234,48 +237,50 @@ class NoteList extends React.Component {
|
|||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
|
|
||||||
if (location.pathname.match(/\/home/)) {
|
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/)) {
|
if (location.pathname.match(/\/starred/)) {
|
||||||
return data.starredSet.toJS()
|
const starredNotes = data.starredSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
this.contextNotes = starredNotes
|
||||||
|
return starredNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/searched/)) {
|
if (location.pathname.match(/\/searched/)) {
|
||||||
const searchInputText = document.getElementsByClassName('searchInput')[0].value
|
const searchInputText = document.getElementsByClassName('searchInput')[0].value
|
||||||
if (searchInputText === '') {
|
if (searchInputText === '') {
|
||||||
router.push('/home')
|
return this.contextNotes
|
||||||
}
|
}
|
||||||
return searchFromNotes(this.notes, searchInputText)
|
return searchFromNotes(this.contextNotes, searchInputText)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/trashed/)) {
|
if (location.pathname.match(/\/trashed/)) {
|
||||||
return data.trashedSet.toJS()
|
const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
this.contextNotes = trashedNotes
|
||||||
|
return trashedNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
let storageKey = params.storageKey
|
return this.getContextNotes()
|
||||||
let folderKey = params.folderKey
|
}
|
||||||
let storage = data.storageMap.get(storageKey)
|
|
||||||
if (storage == null) return []
|
|
||||||
|
|
||||||
let folder = _.find(storage.folders, {key: folderKey})
|
// get notes in the current folder
|
||||||
if (folder == null) {
|
getContextNotes () {
|
||||||
let storageNoteSet = data.storageNoteMap
|
const { data, params } = this.props
|
||||||
.get(storage.key)
|
const storageKey = params.storageKey
|
||||||
if (storageNoteSet == null) storageNoteSet = []
|
const folderKey = params.folderKey
|
||||||
return storageNoteSet
|
const storage = data.storageMap.get(storageKey)
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
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
|
const folderNoteKeyList = data.folderNoteMap.get(`${storage.key}-${folder.key}`) || []
|
||||||
.get(storage.key + '-' + folder.key)
|
return folderNoteKeyList.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
|
|
||||||
return folderNoteKeyList != null
|
|
||||||
? folderNoteKeyList
|
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
|
||||||
: []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNoteClick (e, uniqueKey) {
|
handleNoteClick (e, uniqueKey) {
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ class TopBar extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
search: '',
|
search: '',
|
||||||
searchOptions: [],
|
searchOptions: [],
|
||||||
isSearching: false
|
isSearching: false,
|
||||||
|
isAlphabet: false,
|
||||||
|
isIME: false,
|
||||||
|
isConfirmTranslation: false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focusSearchHandler = () => {
|
this.focusSearchHandler = () => {
|
||||||
@@ -34,9 +37,52 @@ class TopBar extends React.Component {
|
|||||||
ee.off('top:focus-search', this.focusSearchHandler)
|
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) {
|
handleSearchChange (e) {
|
||||||
let { router } = this.context
|
const { router } = this.context
|
||||||
router.push('/searched')
|
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
|
||||||
|
router.push('/searched')
|
||||||
|
} else {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
search: this.refs.searchInput.value
|
search: this.refs.searchInput.value
|
||||||
})
|
})
|
||||||
@@ -93,6 +139,8 @@ class TopBar extends React.Component {
|
|||||||
ref='searchInput'
|
ref='searchInput'
|
||||||
value={this.state.search}
|
value={this.state.search}
|
||||||
onChange={(e) => this.handleSearchChange(e)}
|
onChange={(e) => this.handleSearchChange(e)}
|
||||||
|
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||||
|
onKeyUp={(e) => this.handleKeyUp(e)}
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
type='text'
|
type='text'
|
||||||
className='searchInput'
|
className='searchInput'
|
||||||
|
|||||||
@@ -6,26 +6,30 @@ import _ from 'lodash'
|
|||||||
const pickContents = (notes) => notes.map((note) => { return note.content })
|
const pickContents = (notes) => notes.map((note) => { return note.content })
|
||||||
|
|
||||||
let notes = []
|
let notes = []
|
||||||
let note1, note2
|
let note1, note2, note3
|
||||||
|
|
||||||
test.before(t => {
|
test.before(t => {
|
||||||
const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] }
|
const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] }
|
||||||
const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] }
|
const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] }
|
||||||
|
const data3 = { type: 'MARKDOWN_NOTE', content: '#content4', tags: ['tag1'] }
|
||||||
|
|
||||||
note1 = dummyNote(data1)
|
note1 = dummyNote(data1)
|
||||||
note2 = dummyNote(data2)
|
note2 = dummyNote(data2)
|
||||||
|
note3 = dummyNote(data3)
|
||||||
|
|
||||||
notes = [note1, note2]
|
notes = [note1, note2, note3]
|
||||||
})
|
})
|
||||||
|
|
||||||
test('it can find notes by tags or words', t => {
|
test('it can find notes by tags or words', t => {
|
||||||
// [input, expected content (Array)]
|
// [input, expected content (Array)]
|
||||||
const testCases = [
|
const testCases = [
|
||||||
['#tag1', [note1.content, note2.content]],
|
['#tag1', [note1.content, note2.content, note3.content]],
|
||||||
['#tag1 #tag2', [note2.content]],
|
['#tag1 #tag2', [note2.content]],
|
||||||
['#tag1 #tag2 #tag3', []],
|
['#tag1 #tag2 #tag3', []],
|
||||||
['content1', [note1.content, note2.content]],
|
['content1', [note1.content, note2.content]],
|
||||||
['content1 content2', [note2.content]],
|
['content1 content2', [note2.content]],
|
||||||
['content1 content2 content3', []]
|
['content1 content2 content3', []],
|
||||||
|
['#content4', [note3.content]]
|
||||||
]
|
]
|
||||||
|
|
||||||
testCases.forEach((testCase) => {
|
testCases.forEach((testCase) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user