Implemented highlighting prev/next search result

This commit is contained in:
jos 2016-12-30 14:41:37 +01:00
parent 6ba53f7364
commit fec1bb8f23
3 changed files with 49 additions and 37 deletions

View File

@ -1,12 +1,13 @@
import { createElement as h, Component } from 'react' import { createElement as h, Component } from 'react'
import Ajv from 'ajv' import Ajv from 'ajv'
import isEqual from 'lodash/isEqual'
import { updateIn, getIn, setIn } from '../utils/immutabilityHelpers' import { updateIn, getIn, setIn } from '../utils/immutabilityHelpers'
import { parseJSON } from '../utils/jsonUtils' import { parseJSON } from '../utils/jsonUtils'
import { enrichSchemaError } from '../utils/schemaUtils' import { enrichSchemaError } from '../utils/schemaUtils'
import { import {
jsonToData, dataToJson, toDataPath, patchData, pathExists, jsonToData, dataToJson, toDataPath, patchData, pathExists,
expand, addErrors, search, addSearchResults, addFocus expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult
} from '../jsonData' } from '../jsonData'
import { import {
duplicate, insert, append, remove, duplicate, insert, append, remove,
@ -54,7 +55,7 @@ export default class TreeMode extends Component {
search: { search: {
text: '', text: '',
selectedPath: null active: null // active search result
} }
} }
} }
@ -114,14 +115,8 @@ export default class TreeMode extends Component {
// enrich the data with search results // enrich the data with search results
const searchResults = this.state.search.text ? search(data, this.state.search.text) : null const searchResults = this.state.search.text ? search(data, this.state.search.text) : null
if (searchResults && searchResults.length > 0) { if (searchResults) {
const activeSearchResult = searchResults[0] // TODO: store active search result in state data = addSearchResults(data, searchResults, this.state.search.active)
data = addSearchResults(data, searchResults, activeSearchResult)
// TODO: highlight
// data = addFocus(data, searchResults[0]) // TODO: change to using focus from state
} }
// console.log('data', data) // console.log('data', data)
@ -316,19 +311,42 @@ export default class TreeMode extends Component {
/** @private */ /** @private */
handleSearch = (text) => { handleSearch = (text) => {
this.setState(setIn(this.state, ['search', 'text'], text)) const searchResults = search(this.state.data, text)
this.setState(setIn(this.state, ['search'], {
text,
active: searchResults[0] || null
}))
// TODO: focus on the active result
} }
/** @private */ /** @private */
handleNext = () => { handleNext = () => {
// TODO: implement select next search result // TODO: implement select next search result
console.log('next search result...') const searchResults = search(this.state.data, this.state.search.text)
if (searchResults) {
const next = nextSearchResult(searchResults, this.state.search.active)
this.setState(setIn(this.state, ['search', 'active'], next))
// TODO: focus on the active result
}
} }
/** @private */ /** @private */
handlePrevious = () => { handlePrevious = () => {
// TODO: implement select previous search result // TODO: implement select previous search result
console.log('previous search result...') console.log('previous search result...')
const searchResults = search(this.state.data, this.state.search.text)
if (searchResults) {
const previous = previousSearchResult(searchResults, this.state.search.active)
this.setState(setIn(this.state, ['search', 'active'], previous))
// TODO: focus on the active result
}
} }
/** /**

View File

@ -36,14 +36,14 @@ export default class Search extends Component {
type: 'button', type: 'button',
className: 'jsoneditor-search-next', className: 'jsoneditor-search-next',
title: 'Next result', title: 'Next result',
onClick: this.props.onPrevious onClick: this.props.onNext
}), }),
h('input', { h('input', {
key: 'previous', key: 'previous',
type: 'button', type: 'button',
className: 'jsoneditor-search-previous', className: 'jsoneditor-search-previous',
title: 'Previous result', title: 'Previous result',
onClick: this.props.onNext onClick: this.props.onPrevious
}) })
]) ])
]) ])

View File

@ -9,7 +9,7 @@ import { setIn, updateIn, getIn, deleteIn, insertAt } from './utils/immutability
import { isObject } from './utils/typeUtils' import { isObject } from './utils/typeUtils'
import isEqual from 'lodash/isEqual' import isEqual from 'lodash/isEqual'
import type {SearchResult} from './types' import type {JSONData, SearchResult} from './types'
/** /**
* Expand function which will expand all nodes * Expand function which will expand all nodes
@ -508,12 +508,8 @@ export function addErrors (data, errors) {
/** /**
* Search some text in all properties and values * Search some text in all properties and values
*
* @param {JSONData} data
* @param {string} text
* @return {SearchResult[]} Returns a list with search results
*/ */
export function search (data, text): SearchResult[] { export function search (data: JSONData, text: string): SearchResult[] {
let results: SearchResult[] = [] let results: SearchResult[] = []
traverse(data, function (value, path) { traverse(data, function (value, path) {
@ -593,25 +589,23 @@ export function previousSearchResult (searchResults: SearchResult[], current: Se
/** /**
* Merge searchResults into the data * Merge searchResults into the data
*/ */
export function addSearchResults (data, searchResults: SearchResult[], activeSearchResult: SearchResult) { export function addSearchResults (data: JSONData, searchResults: SearchResult[], activeSearchResult: SearchResult) {
let updatedData = data let updatedData = data
if (searchResults) { searchResults.forEach(function (searchResult) {
searchResults.forEach(function (searchResult) { if (searchResult.type === 'value') {
if (searchResult.type === 'value') { const dataPath = toDataPath(data, searchResult.dataPath).concat('searchResult')
const dataPath = toDataPath(data, searchResult.dataPath).concat('searchResult') const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' updatedData = setIn(updatedData, dataPath, value)
updatedData = setIn(updatedData, dataPath, value) }
}
if (searchResult.type === 'property') { if (searchResult.type === 'property') {
const valueDataPath = toDataPath(data, searchResult.dataPath) const valueDataPath = toDataPath(data, searchResult.dataPath)
const propertyDataPath = allButLast(valueDataPath).concat('searchResult') const propertyDataPath = allButLast(valueDataPath).concat('searchResult')
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
updatedData = setIn(updatedData, propertyDataPath, value) updatedData = setIn(updatedData, propertyDataPath, value)
} }
}) })
}
return updatedData return updatedData
} }
@ -623,7 +617,7 @@ export function addSearchResults (data, searchResults: SearchResult[], activeSea
* @param {SearchResult} focusOn * @param {SearchResult} focusOn
* @return {JSONData} Returns an updated copy of data * @return {JSONData} Returns an updated copy of data
*/ */
export function addFocus (data, focusOn) { export function addFocus (data: JSONData, focusOn: SearchResult) {
if (focusOn.value) { if (focusOn.value) {
const dataPath = toDataPath(data, focusOn.dataPath).concat('focusValue') const dataPath = toDataPath(data, focusOn.dataPath).concat('focusValue')
return setIn(data, dataPath, true) return setIn(data, dataPath, true)