Update search results on patch/undo/redo

This commit is contained in:
jos 2018-10-03 12:32:48 +02:00
parent 7012de59d6
commit 21d8db13d0
6 changed files with 49 additions and 76 deletions

View File

@ -61,7 +61,7 @@ import {
immutableESONPatch,
nextSearchResult,
previousSearchResult,
search,
applySearch,
SELECTION,
syncEson
} from '../eson'
@ -142,8 +142,8 @@ export default class TreeMode extends PureComponent {
options: {},
showSearch: false,
searchText: '',
searchResult: {
text: '',
matches: null,
active: null // active search result
},
@ -327,7 +327,7 @@ export default class TreeMode extends PureComponent {
key: 'search',
ref: 'search',
text: this.state.searchResult.text,
text: this.state.searchText,
resultCount: this.state.searchResult.matches
? this.state.searchResult.matches.length
@ -736,12 +736,12 @@ export default class TreeMode extends PureComponent {
}
}
handleSearch = (text) => {
// FIXME: also apply search when eson is changed
const { eson, searchResult } = search(this.state.eson, text)
handleSearch = (searchText) => {
const { eson, searchResult } = applySearch(this.state.eson, searchText)
if (searchResult.matches.length > 0) {
this.setState({
eson: expandPath(eson, initial(searchResult.active.path)),
searchText,
searchResult
})
@ -751,6 +751,7 @@ export default class TreeMode extends PureComponent {
else {
this.setState({
eson: eson,
searchText,
searchResult
})
}
@ -818,11 +819,13 @@ export default class TreeMode extends PureComponent {
}
handleCloseSearch = () => {
const { eson, searchResult } = search(this.state.eson, '')
const searchText = ''
const { eson, searchResult } = applySearch(this.state.eson, searchText)
this.setState({
showSearch: false,
eson,
searchText,
searchResult
})
}
@ -997,30 +1000,6 @@ export default class TreeMode extends PureComponent {
}
}
/**
* Get selection from an JSONPointer
* @param {ESONPointer} pointer
* @return {Selection}
*/
selectionFromJSONPointer (pointer) {
// FIXME: does pointer have .area === 'after' ? if so adjust type defs
if (pointer.area === 'after') {
return {after: pointer.path}
}
else if (pointer.area === 'inside') {
return {inside: pointer.path}
}
else if (pointer.area === 'empty') {
return {empty: pointer.path}
}
else if (pointer.area === 'emptyBefore') {
return {emptyBefore: pointer.path}
}
else {
return {start: pointer.path, end: pointer.path}
}
}
/**
* Scroll the window vertically to the node with given path
* @param {Path} path
@ -1090,19 +1069,23 @@ export default class TreeMode extends PureComponent {
const historyIndex = this.state.historyIndex
const historyItem = history[historyIndex]
const jsonResult = immutableJSONPatch(this.state.json, historyItem.undo)
const { json } = immutableJSONPatch(this.state.json, historyItem.undo)
const esonResult = immutableESONPatch(this.state.eson, historyItem.undo)
// FIXME: apply search
const { eson, searchResult } = (this.state.searchText)
? applySearch(esonResult.json, this.state.searchText)
: { eson: esonResult.json, searchResult: null }
this.setState({
json: jsonResult.json,
eson: esonResult.json,
json,
eson,
searchResult,
selection: historyItem.selectionBefore,
history,
historyIndex: historyIndex + 1
})
this.emitOnChange(historyItem.undo, historyItem.redo, jsonResult.json)
this.emitOnChange(historyItem.undo, historyItem.redo, json)
}
}
@ -1112,19 +1095,23 @@ export default class TreeMode extends PureComponent {
const historyIndex = this.state.historyIndex - 1
const historyItem = history[historyIndex]
const jsonResult = immutableJSONPatch(this.state.json, historyItem.redo)
const { json } = immutableJSONPatch(this.state.json, historyItem.redo)
const esonResult = immutableESONPatch(this.state.eson, historyItem.redo)
// FIXME: apply search
const { eson, searchResult } = (this.state.searchText)
? applySearch(esonResult.json, this.state.searchText)
: { eson: esonResult.json, searchResult: null }
this.setState({
json: jsonResult.json,
eson: esonResult.json,
json,
eson,
searchResult,
selection: historyItem.selectionAfter,
history,
historyIndex
})
this.emitOnChange(historyItem.redo, historyItem.undo, jsonResult.json)
this.emitOnChange(historyItem.redo, historyItem.undo, json)
}
}
@ -1149,6 +1136,10 @@ export default class TreeMode extends PureComponent {
const jsonResult = immutableJSONPatch(this.state.json, operations)
const esonResult = immutableESONPatch(this.state.eson, operations)
const { eson, searchResult } = (this.state.searchText)
? applySearch(esonResult.json, this.state.searchText)
: { eson: esonResult.json, searchResult: null }
if (this.props.history !== false) {
// update data and store history
const historyItem = {
@ -1162,10 +1153,10 @@ export default class TreeMode extends PureComponent {
.concat(this.state.history.slice(this.state.historyIndex))
.slice(0, MAX_HISTORY_ITEMS)
// FIXME: apply search
this.setState({
json: jsonResult.json,
eson: esonResult.json,
eson,
searchResult,
selection: selectionAfter,
history,
historyIndex: 0
@ -1173,10 +1164,10 @@ export default class TreeMode extends PureComponent {
}
else {
// update data and don't store history
// FIXME: apply search
this.setState({
json: jsonResult.json,
eson: esonResult.json,
eson,
searchResult,
selection: selectionAfter
})
}

View File

@ -340,22 +340,6 @@ div.jsoneditor-node-container {
}
}
&.jsoneditor-hover {
> .jsoneditor-node > .jsoneditor-button-container,
> .jsoneditor-node > .jsoneditor-button-placeholder {
background-color: $hoverColor;
}
> .jsoneditor-list {
border-left-color: $hoverColor;
}
> .jsoneditor-delimiter-end {
//padding-left: $line-height + $input-padding + 2px;
border-left-color: $hoverColor;
}
}
div.jsoneditor-floating-menu {
position: absolute;
bottom: 100%;

View File

@ -9,9 +9,7 @@ $theme-color: #3883fa;
$theme-color-light: lighten($theme-color, 5);
$floating-menu-background: #4d4d4d;
$floating-menu-color: #fff;
$selectedColor: #ffed99;
$hoverColor: #d3d3d3;
$hoverAndSelectedColor: #ffdb80;
$selectedColor: #d3d3d3;
$warning-color: #FBB917;
$gray: #9d9d9d;
$gray-icon: $gray;

View File

@ -208,12 +208,12 @@ export function cleanupMetaData(eson, symbol, ignorePaths = []) {
/**
* Search some text in all properties and values
* @param {ESON} eson
* @param {String} text Search text
* @return {SearchResult} Returns search result:
* @param {string} searchText
* @return {{eson: ESON, searchText: string, searchResult: SearchResult}} Returns search result:
* An updated eson object containing the search results,
* and an array with the paths of all matches
*/
export function search (eson, text) {
export function applySearch (eson, searchText) {
let matches = []
// TODO: keep active result from previous search if any?
@ -224,7 +224,7 @@ export function search (eson, text) {
// check property name
const prop = last(path)
if (text !== '' && containsCaseInsensitive(prop, text) &&
if (searchText !== '' && containsCaseInsensitive(prop, searchText) &&
getIn(eson, initial(path))[TYPE] === 'object') { // parent must be an Object
matches.push({path, area: 'property'})
updatedValue = setIn(updatedValue, [SEARCH_PROPERTY], 'normal')
@ -234,7 +234,7 @@ export function search (eson, text) {
}
// check value
if (value[TYPE] === 'value' && text !== '' && containsCaseInsensitive(value[VALUE], text)) {
if (value[TYPE] === 'value' && searchText !== '' && containsCaseInsensitive(value[VALUE], searchText)) {
matches.push({path, area: 'value'})
updatedValue = setIn(updatedValue, [SEARCH_VALUE], 'normal')
}
@ -271,8 +271,8 @@ export function search (eson, text) {
return {
eson: updatedEson,
searchText,
searchResult: {
text,
matches,
active
}

View File

@ -9,7 +9,7 @@ import {
nextSearchResult,
pathsFromSelection,
previousSearchResult,
search, SEARCH_PROPERTY, SEARCH_VALUE,
applySearch, SEARCH_PROPERTY, SEARCH_VALUE,
SELECTED,
SELECTED_END,
SELECTED_FIRST,
@ -223,7 +223,7 @@ test('search', () => {
"nill": null,
"bool": false
})
const result = search(eson, 'L')
const result = applySearch(eson, 'L')
const esonWithSearch = result.eson
const matches = result.searchResult.matches
const active = result.searchResult.active
@ -254,7 +254,7 @@ test('search number', () => {
"2": "two",
"arr": ["a", "b", "c", "2"]
})
const result = search(eson, '2')
const result = applySearch(eson, '2')
const matches = result.searchResult.matches
// should not match an array index, only props and values
@ -273,7 +273,7 @@ test('nextSearchResult', () => {
"nill": null,
"bool": false
})
const first = search(eson, 'A')
const first = applySearch(eson, 'A')
expect(first.searchResult.matches).toEqual([
{path: ['bool'], area: 'value'},
@ -314,7 +314,7 @@ test('previousSearchResult', () => {
"nill": null,
"bool": false
})
const init = search(eson, 'A')
const init = applySearch(eson, 'A')
expect(init.searchResult.matches).toEqual([
{path: ['bool'], area: 'value'},

View File

@ -45,7 +45,7 @@
*/
/**
* @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult
* @typedef {{matches: ESONPointer[], active: ESONPointer}} SearchResult
*/
/**