Changed the structure of SearchResult. Highlight active search result
This commit is contained in:
parent
95f0a31731
commit
aa4b963592
|
@ -295,7 +295,7 @@ export default class JSONNode extends Component {
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {boolean} isUrl
|
* @param {boolean} isUrl
|
||||||
* @param {boolean} isEmpty
|
* @param {boolean} isEmpty
|
||||||
* @param {boolean} [searchValue]
|
* @param {'normal' | 'active'} [searchValue]
|
||||||
* @return {string}
|
* @return {string}
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -304,7 +304,9 @@ export default class JSONNode extends Component {
|
||||||
'jsoneditor-' + type +
|
'jsoneditor-' + type +
|
||||||
(isUrl ? ' jsoneditor-url' : '') +
|
(isUrl ? ' jsoneditor-url' : '') +
|
||||||
(isEmpty ? ' jsoneditor-empty' : '') +
|
(isEmpty ? ' jsoneditor-empty' : '') +
|
||||||
(searchValue ? ' jsoneditor-highlight' : '')
|
(searchValue === 'active'
|
||||||
|
? ' jsoneditor-highlight-active'
|
||||||
|
: (searchValue ? ' jsoneditor-highlight' : ''))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -372,16 +374,19 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps, prevState) {
|
componentDidUpdate (prevProps, prevState) {
|
||||||
// TODO: focus to input field
|
if (this.props.data.focusProperty && !prevProps.data.focusProperty) {
|
||||||
// if (this.props.data.focusProperty && !prevProps.data.focusProperty) {
|
console.log('focus property', this.getPath()) // TODO: cleanup
|
||||||
// console.log('focus property', this.getPath())
|
if (this.refs.property) {
|
||||||
// this.refs.property.focus()
|
this.refs.property.focus()
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// if (this.props.data.focusValue && !prevProps.data.focusValue) {
|
|
||||||
// console.log('focus value', this.getPath())
|
if (this.props.data.focusValue && !prevProps.data.focusValue) {
|
||||||
// this.refs.value.focus()
|
console.log('focus value', this.getPath()) // TODO: cleanup
|
||||||
// }
|
if (this.refs.value) {
|
||||||
|
this.refs.value.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRootName (data, options) {
|
static getRootName (data, options) {
|
||||||
|
|
|
@ -115,11 +115,16 @@ 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 && searchResults.length > 0) {
|
||||||
data = addSearchResults(data, searchResults)
|
const activeSearchResult = searchResults[0] // TODO: store active search result in state
|
||||||
|
|
||||||
data = addFocus(data, searchResults[0]) // TODO: change to using focus from state
|
data = addSearchResults(data, searchResults, activeSearchResult)
|
||||||
|
|
||||||
|
// TODO: highlight
|
||||||
|
|
||||||
|
// data = addFocus(data, searchResults[0]) // TODO: change to using focus from state
|
||||||
}
|
}
|
||||||
// TODO: pass number of search results to search box in top menu
|
|
||||||
|
console.log('data', data)
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
className: `jsoneditor jsoneditor-mode-${props.mode}`,
|
className: `jsoneditor jsoneditor-mode-${props.mode}`,
|
||||||
|
|
|
@ -54,12 +54,14 @@ export default class Search extends Component {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultsCount == 0) {
|
if (resultsCount === 0) {
|
||||||
return h('div', {key: 'count', className: 'jsoneditor-results'}, '(no results)')
|
return h('div', {key: 'count', className: 'jsoneditor-results'}, '(no results)')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultsCount > 0) {
|
if (resultsCount > 0) {
|
||||||
return h('div', {key: 'count', className: 'jsoneditor-results'}, this.props.resultsCount + ' results')
|
const suffix = resultsCount === 1 ? ' result' : ' results'
|
||||||
|
|
||||||
|
return h('div', {key: 'count', className: 'jsoneditor-results'}, this.props.resultsCount + suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// @flow weak
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains functions to act on a JSONData object.
|
* This file contains functions to act on a JSONData object.
|
||||||
* All functions are pure and don't mutate the JSONData.
|
* All functions are pure and don't mutate the JSONData.
|
||||||
|
@ -7,6 +9,8 @@ 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'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand function which will expand all nodes
|
* Expand function which will expand all nodes
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
|
@ -509,16 +513,16 @@ export function addErrors (data, errors) {
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @return {SearchResult[]} Returns a list with search results
|
* @return {SearchResult[]} Returns a list with search results
|
||||||
*/
|
*/
|
||||||
export function search (data, text) {
|
export function search (data, text): SearchResult[] {
|
||||||
let results = []
|
let results: SearchResult[] = []
|
||||||
|
|
||||||
traverse(data, function (value, path) {
|
traverse(data, function (value, path, root) {
|
||||||
// search in values
|
// search in values
|
||||||
if (value.type === 'value') {
|
if (value.type === 'value') {
|
||||||
if (containsCaseInsensitive(value.value, text)) {
|
if (containsCaseInsensitive(value.value, text)) {
|
||||||
results.push({
|
results.push({
|
||||||
dataPath: path,
|
dataPath: path,
|
||||||
value: true
|
type: 'value'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,7 +533,7 @@ export function search (data, text) {
|
||||||
if (containsCaseInsensitive(prop.name, text)) {
|
if (containsCaseInsensitive(prop.name, text)) {
|
||||||
results.push({
|
results.push({
|
||||||
dataPath: path.concat(prop.name),
|
dataPath: path.concat(prop.name),
|
||||||
property: true
|
type: 'property'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -541,24 +545,22 @@ export function search (data, text) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge searchResults into the data
|
* Merge searchResults into the data
|
||||||
*
|
|
||||||
* @param {JSONData} data
|
|
||||||
* @param {SearchResult[]} searchResults
|
|
||||||
* @return {JSONData} Returns an updated copy of data
|
|
||||||
*/
|
*/
|
||||||
export function addSearchResults (data, searchResults) {
|
export function addSearchResults (data, searchResults: SearchResult[], activeSearchResult: SearchResult) {
|
||||||
let updatedData = data
|
let updatedData = data
|
||||||
|
|
||||||
if (searchResults) {
|
if (searchResults) {
|
||||||
searchResults.forEach(function (searchResult) {
|
searchResults.forEach(function (searchResult) {
|
||||||
if (searchResult.value) {
|
if (searchResult.type === 'value') {
|
||||||
const dataPath = toDataPath(data, searchResult.dataPath).concat('searchValue')
|
const dataPath = toDataPath(data, searchResult.dataPath).concat('searchValue')
|
||||||
updatedData = setIn(updatedData, dataPath, true)
|
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
||||||
|
updatedData = setIn(updatedData, dataPath, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchResult.property) {
|
if (searchResult.type === 'property') {
|
||||||
const dataPath = toDataPath(data, searchResult.dataPath).concat('searchProperty')
|
const dataPath = toDataPath(data, searchResult.dataPath).concat('searchProperty')
|
||||||
updatedData = setIn(updatedData, dataPath, true)
|
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
||||||
|
updatedData = setIn(updatedData, dataPath, value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,8 +260,16 @@ div.jsoneditor-value.jsoneditor-empty::after {
|
||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-highlight-primary {
|
.jsoneditor-highlight:hover {
|
||||||
background-color: #FF9632;
|
background-color: #f0f000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jsoneditor-highlight-active {
|
||||||
|
background-color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jsoneditor-highlight-active:hover {
|
||||||
|
background-color: #f3cd00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-button-placeholder {
|
.jsoneditor-button-placeholder {
|
||||||
|
|
|
@ -71,6 +71,11 @@ type JSONArrayType = Array<JSON>;
|
||||||
|
|
||||||
export type Path = string[]
|
export type Path = string[]
|
||||||
|
|
||||||
|
export type SearchResult = {
|
||||||
|
dataPath: Path,
|
||||||
|
type: 'value' | 'property'
|
||||||
|
}
|
||||||
|
|
||||||
export type SetOptions = {
|
export type SetOptions = {
|
||||||
expand?: (path: Path) => boolean
|
expand?: (path: Path) => boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,7 +278,7 @@ const JSON_DATA_EXAMPLE_SEARCH_L = {
|
||||||
value: {
|
value: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
value: 4,
|
value: 4,
|
||||||
searchProperty: true
|
searchProperty: 'normal'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -294,7 +294,7 @@ const JSON_DATA_EXAMPLE_SEARCH_L = {
|
||||||
value: {
|
value: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
value: 'hello world',
|
value: 'hello world',
|
||||||
searchValue: true
|
searchValue: 'normal'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -302,8 +302,8 @@ const JSON_DATA_EXAMPLE_SEARCH_L = {
|
||||||
value: {
|
value: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
value: null,
|
value: null,
|
||||||
searchProperty: true,
|
searchProperty: 'active',
|
||||||
searchValue: true
|
searchValue: 'normal'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -311,8 +311,8 @@ const JSON_DATA_EXAMPLE_SEARCH_L = {
|
||||||
value: {
|
value: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
value: false,
|
value: false,
|
||||||
searchProperty: true,
|
searchProperty: 'normal',
|
||||||
searchValue: true
|
searchValue: 'normal'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -925,16 +925,17 @@ test('search', t => {
|
||||||
// console.log(searchResults)
|
// console.log(searchResults)
|
||||||
|
|
||||||
t.deepEqual(searchResults, [
|
t.deepEqual(searchResults, [
|
||||||
{dataPath: ['nill'], property: true},
|
{dataPath: ['nill'], type: 'property'},
|
||||||
{dataPath: ['bool'], property: true},
|
{dataPath: ['bool'], type: 'property'},
|
||||||
{dataPath: ['obj', 'arr', '2', 'last'], property: true},
|
{dataPath: ['obj', 'arr', '2', 'last'], type: 'property'},
|
||||||
{dataPath: ['str'], value: true},
|
{dataPath: ['str'], type: 'value'},
|
||||||
{dataPath: ['nill'], value: true},
|
{dataPath: ['nill'], type: 'value'},
|
||||||
{dataPath: ['bool'], value: true}
|
{dataPath: ['bool'], type: 'value'}
|
||||||
])
|
])
|
||||||
|
|
||||||
const updatedData = addSearchResults(JSON_DATA_EXAMPLE, searchResults)
|
const activeSearchResult = searchResults[0]
|
||||||
// console.log(JSON.stringify(updatedData, null, 2))
|
const updatedData = addSearchResults(JSON_DATA_EXAMPLE, searchResults, activeSearchResult)
|
||||||
|
//console.log(JSON.stringify(updatedData, null, 2))
|
||||||
|
|
||||||
t.deepEqual(updatedData, JSON_DATA_EXAMPLE_SEARCH_L)
|
t.deepEqual(updatedData, JSON_DATA_EXAMPLE_SEARCH_L)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue