diff --git a/src/components/TreeMode.js b/src/components/TreeMode.js index ed796ca..9c7c443 100644 --- a/src/components/TreeMode.js +++ b/src/components/TreeMode.js @@ -1,12 +1,13 @@ import { createElement as h, Component } from 'react' import Ajv from 'ajv' +import isEqual from 'lodash/isEqual' import { updateIn, getIn, setIn } from '../utils/immutabilityHelpers' import { parseJSON } from '../utils/jsonUtils' import { enrichSchemaError } from '../utils/schemaUtils' import { jsonToData, dataToJson, toDataPath, patchData, pathExists, - expand, addErrors, search, addSearchResults, addFocus + expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult } from '../jsonData' import { duplicate, insert, append, remove, @@ -54,7 +55,7 @@ export default class TreeMode extends Component { search: { text: '', - selectedPath: null + active: null // active search result } } } @@ -114,14 +115,8 @@ export default class TreeMode extends Component { // enrich the data with search results const searchResults = this.state.search.text ? search(data, this.state.search.text) : null - if (searchResults && searchResults.length > 0) { - const activeSearchResult = searchResults[0] // TODO: store active search result in state - - data = addSearchResults(data, searchResults, activeSearchResult) - - // TODO: highlight - - // data = addFocus(data, searchResults[0]) // TODO: change to using focus from state + if (searchResults) { + data = addSearchResults(data, searchResults, this.state.search.active) } // console.log('data', data) @@ -316,19 +311,42 @@ export default class TreeMode extends Component { /** @private */ 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 */ handleNext = () => { // 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 */ handlePrevious = () => { // TODO: implement select 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 + } } /** diff --git a/src/components/menu/Search.js b/src/components/menu/Search.js index c3c7a41..2ca851a 100644 --- a/src/components/menu/Search.js +++ b/src/components/menu/Search.js @@ -36,14 +36,14 @@ export default class Search extends Component { type: 'button', className: 'jsoneditor-search-next', title: 'Next result', - onClick: this.props.onPrevious + onClick: this.props.onNext }), h('input', { key: 'previous', type: 'button', className: 'jsoneditor-search-previous', title: 'Previous result', - onClick: this.props.onNext + onClick: this.props.onPrevious }) ]) ]) diff --git a/src/jsonData.js b/src/jsonData.js index 27072b8..797fec4 100644 --- a/src/jsonData.js +++ b/src/jsonData.js @@ -9,7 +9,7 @@ import { setIn, updateIn, getIn, deleteIn, insertAt } from './utils/immutability import { isObject } from './utils/typeUtils' import isEqual from 'lodash/isEqual' -import type {SearchResult} from './types' +import type {JSONData, SearchResult} from './types' /** * Expand function which will expand all nodes @@ -508,12 +508,8 @@ export function addErrors (data, errors) { /** * 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[] = [] traverse(data, function (value, path) { @@ -593,25 +589,23 @@ export function previousSearchResult (searchResults: SearchResult[], current: Se /** * 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 - if (searchResults) { - searchResults.forEach(function (searchResult) { - if (searchResult.type === 'value') { - const dataPath = toDataPath(data, searchResult.dataPath).concat('searchResult') - const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' - updatedData = setIn(updatedData, dataPath, value) - } + searchResults.forEach(function (searchResult) { + if (searchResult.type === 'value') { + const dataPath = toDataPath(data, searchResult.dataPath).concat('searchResult') + const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' + updatedData = setIn(updatedData, dataPath, value) + } - if (searchResult.type === 'property') { - const valueDataPath = toDataPath(data, searchResult.dataPath) - const propertyDataPath = allButLast(valueDataPath).concat('searchResult') - const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' - updatedData = setIn(updatedData, propertyDataPath, value) - } - }) - } + if (searchResult.type === 'property') { + const valueDataPath = toDataPath(data, searchResult.dataPath) + const propertyDataPath = allButLast(valueDataPath).concat('searchResult') + const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal' + updatedData = setIn(updatedData, propertyDataPath, value) + } + }) return updatedData } @@ -623,7 +617,7 @@ export function addSearchResults (data, searchResults: SearchResult[], activeSea * @param {SearchResult} focusOn * @return {JSONData} Returns an updated copy of data */ -export function addFocus (data, focusOn) { +export function addFocus (data: JSONData, focusOn: SearchResult) { if (focusOn.value) { const dataPath = toDataPath(data, focusOn.dataPath).concat('focusValue') return setIn(data, dataPath, true)