Update search results on patch/undo/redo
This commit is contained in:
parent
7012de59d6
commit
21d8db13d0
|
@ -61,7 +61,7 @@ import {
|
||||||
immutableESONPatch,
|
immutableESONPatch,
|
||||||
nextSearchResult,
|
nextSearchResult,
|
||||||
previousSearchResult,
|
previousSearchResult,
|
||||||
search,
|
applySearch,
|
||||||
SELECTION,
|
SELECTION,
|
||||||
syncEson
|
syncEson
|
||||||
} from '../eson'
|
} from '../eson'
|
||||||
|
@ -142,8 +142,8 @@ export default class TreeMode extends PureComponent {
|
||||||
options: {},
|
options: {},
|
||||||
|
|
||||||
showSearch: false,
|
showSearch: false,
|
||||||
|
searchText: '',
|
||||||
searchResult: {
|
searchResult: {
|
||||||
text: '',
|
|
||||||
matches: null,
|
matches: null,
|
||||||
active: null // active search result
|
active: null // active search result
|
||||||
},
|
},
|
||||||
|
@ -327,7 +327,7 @@ export default class TreeMode extends PureComponent {
|
||||||
key: 'search',
|
key: 'search',
|
||||||
ref: 'search',
|
ref: 'search',
|
||||||
|
|
||||||
text: this.state.searchResult.text,
|
text: this.state.searchText,
|
||||||
|
|
||||||
resultCount: this.state.searchResult.matches
|
resultCount: this.state.searchResult.matches
|
||||||
? this.state.searchResult.matches.length
|
? this.state.searchResult.matches.length
|
||||||
|
@ -736,12 +736,12 @@ export default class TreeMode extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearch = (text) => {
|
handleSearch = (searchText) => {
|
||||||
// FIXME: also apply search when eson is changed
|
const { eson, searchResult } = applySearch(this.state.eson, searchText)
|
||||||
const { eson, searchResult } = search(this.state.eson, text)
|
|
||||||
if (searchResult.matches.length > 0) {
|
if (searchResult.matches.length > 0) {
|
||||||
this.setState({
|
this.setState({
|
||||||
eson: expandPath(eson, initial(searchResult.active.path)),
|
eson: expandPath(eson, initial(searchResult.active.path)),
|
||||||
|
searchText,
|
||||||
searchResult
|
searchResult
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -751,6 +751,7 @@ export default class TreeMode extends PureComponent {
|
||||||
else {
|
else {
|
||||||
this.setState({
|
this.setState({
|
||||||
eson: eson,
|
eson: eson,
|
||||||
|
searchText,
|
||||||
searchResult
|
searchResult
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -818,11 +819,13 @@ export default class TreeMode extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCloseSearch = () => {
|
handleCloseSearch = () => {
|
||||||
const { eson, searchResult } = search(this.state.eson, '')
|
const searchText = ''
|
||||||
|
const { eson, searchResult } = applySearch(this.state.eson, searchText)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
showSearch: false,
|
showSearch: false,
|
||||||
eson,
|
eson,
|
||||||
|
searchText,
|
||||||
searchResult
|
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
|
* Scroll the window vertically to the node with given path
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
|
@ -1090,19 +1069,23 @@ export default class TreeMode extends PureComponent {
|
||||||
const historyIndex = this.state.historyIndex
|
const historyIndex = this.state.historyIndex
|
||||||
const historyItem = history[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)
|
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({
|
this.setState({
|
||||||
json: jsonResult.json,
|
json,
|
||||||
eson: esonResult.json,
|
eson,
|
||||||
|
searchResult,
|
||||||
selection: historyItem.selectionBefore,
|
selection: historyItem.selectionBefore,
|
||||||
history,
|
history,
|
||||||
historyIndex: historyIndex + 1
|
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 historyIndex = this.state.historyIndex - 1
|
||||||
const historyItem = history[historyIndex]
|
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)
|
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({
|
this.setState({
|
||||||
json: jsonResult.json,
|
json,
|
||||||
eson: esonResult.json,
|
eson,
|
||||||
|
searchResult,
|
||||||
selection: historyItem.selectionAfter,
|
selection: historyItem.selectionAfter,
|
||||||
history,
|
history,
|
||||||
historyIndex
|
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 jsonResult = immutableJSONPatch(this.state.json, operations)
|
||||||
const esonResult = immutableESONPatch(this.state.eson, 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) {
|
if (this.props.history !== false) {
|
||||||
// update data and store history
|
// update data and store history
|
||||||
const historyItem = {
|
const historyItem = {
|
||||||
|
@ -1162,10 +1153,10 @@ export default class TreeMode extends PureComponent {
|
||||||
.concat(this.state.history.slice(this.state.historyIndex))
|
.concat(this.state.history.slice(this.state.historyIndex))
|
||||||
.slice(0, MAX_HISTORY_ITEMS)
|
.slice(0, MAX_HISTORY_ITEMS)
|
||||||
|
|
||||||
// FIXME: apply search
|
|
||||||
this.setState({
|
this.setState({
|
||||||
json: jsonResult.json,
|
json: jsonResult.json,
|
||||||
eson: esonResult.json,
|
eson,
|
||||||
|
searchResult,
|
||||||
selection: selectionAfter,
|
selection: selectionAfter,
|
||||||
history,
|
history,
|
||||||
historyIndex: 0
|
historyIndex: 0
|
||||||
|
@ -1173,10 +1164,10 @@ export default class TreeMode extends PureComponent {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// update data and don't store history
|
// update data and don't store history
|
||||||
// FIXME: apply search
|
|
||||||
this.setState({
|
this.setState({
|
||||||
json: jsonResult.json,
|
json: jsonResult.json,
|
||||||
eson: esonResult.json,
|
eson,
|
||||||
|
searchResult,
|
||||||
selection: selectionAfter
|
selection: selectionAfter
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
div.jsoneditor-floating-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 100%;
|
bottom: 100%;
|
||||||
|
|
|
@ -9,9 +9,7 @@ $theme-color: #3883fa;
|
||||||
$theme-color-light: lighten($theme-color, 5);
|
$theme-color-light: lighten($theme-color, 5);
|
||||||
$floating-menu-background: #4d4d4d;
|
$floating-menu-background: #4d4d4d;
|
||||||
$floating-menu-color: #fff;
|
$floating-menu-color: #fff;
|
||||||
$selectedColor: #ffed99;
|
$selectedColor: #d3d3d3;
|
||||||
$hoverColor: #d3d3d3;
|
|
||||||
$hoverAndSelectedColor: #ffdb80;
|
|
||||||
$warning-color: #FBB917;
|
$warning-color: #FBB917;
|
||||||
$gray: #9d9d9d;
|
$gray: #9d9d9d;
|
||||||
$gray-icon: $gray;
|
$gray-icon: $gray;
|
||||||
|
|
|
@ -208,12 +208,12 @@ export function cleanupMetaData(eson, symbol, ignorePaths = []) {
|
||||||
/**
|
/**
|
||||||
* Search some text in all properties and values
|
* Search some text in all properties and values
|
||||||
* @param {ESON} eson
|
* @param {ESON} eson
|
||||||
* @param {String} text Search text
|
* @param {string} searchText
|
||||||
* @return {SearchResult} Returns search result:
|
* @return {{eson: ESON, searchText: string, searchResult: SearchResult}} Returns search result:
|
||||||
* An updated eson object containing the search results,
|
* An updated eson object containing the search results,
|
||||||
* and an array with the paths of all matches
|
* and an array with the paths of all matches
|
||||||
*/
|
*/
|
||||||
export function search (eson, text) {
|
export function applySearch (eson, searchText) {
|
||||||
let matches = []
|
let matches = []
|
||||||
|
|
||||||
// TODO: keep active result from previous search if any?
|
// TODO: keep active result from previous search if any?
|
||||||
|
@ -224,7 +224,7 @@ export function search (eson, text) {
|
||||||
|
|
||||||
// check property name
|
// check property name
|
||||||
const prop = last(path)
|
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
|
getIn(eson, initial(path))[TYPE] === 'object') { // parent must be an Object
|
||||||
matches.push({path, area: 'property'})
|
matches.push({path, area: 'property'})
|
||||||
updatedValue = setIn(updatedValue, [SEARCH_PROPERTY], 'normal')
|
updatedValue = setIn(updatedValue, [SEARCH_PROPERTY], 'normal')
|
||||||
|
@ -234,7 +234,7 @@ export function search (eson, text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check value
|
// 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'})
|
matches.push({path, area: 'value'})
|
||||||
updatedValue = setIn(updatedValue, [SEARCH_VALUE], 'normal')
|
updatedValue = setIn(updatedValue, [SEARCH_VALUE], 'normal')
|
||||||
}
|
}
|
||||||
|
@ -271,8 +271,8 @@ export function search (eson, text) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
eson: updatedEson,
|
eson: updatedEson,
|
||||||
|
searchText,
|
||||||
searchResult: {
|
searchResult: {
|
||||||
text,
|
|
||||||
matches,
|
matches,
|
||||||
active
|
active
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
nextSearchResult,
|
nextSearchResult,
|
||||||
pathsFromSelection,
|
pathsFromSelection,
|
||||||
previousSearchResult,
|
previousSearchResult,
|
||||||
search, SEARCH_PROPERTY, SEARCH_VALUE,
|
applySearch, SEARCH_PROPERTY, SEARCH_VALUE,
|
||||||
SELECTED,
|
SELECTED,
|
||||||
SELECTED_END,
|
SELECTED_END,
|
||||||
SELECTED_FIRST,
|
SELECTED_FIRST,
|
||||||
|
@ -223,7 +223,7 @@ test('search', () => {
|
||||||
"nill": null,
|
"nill": null,
|
||||||
"bool": false
|
"bool": false
|
||||||
})
|
})
|
||||||
const result = search(eson, 'L')
|
const result = applySearch(eson, 'L')
|
||||||
const esonWithSearch = result.eson
|
const esonWithSearch = result.eson
|
||||||
const matches = result.searchResult.matches
|
const matches = result.searchResult.matches
|
||||||
const active = result.searchResult.active
|
const active = result.searchResult.active
|
||||||
|
@ -254,7 +254,7 @@ test('search number', () => {
|
||||||
"2": "two",
|
"2": "two",
|
||||||
"arr": ["a", "b", "c", "2"]
|
"arr": ["a", "b", "c", "2"]
|
||||||
})
|
})
|
||||||
const result = search(eson, '2')
|
const result = applySearch(eson, '2')
|
||||||
const matches = result.searchResult.matches
|
const matches = result.searchResult.matches
|
||||||
|
|
||||||
// should not match an array index, only props and values
|
// should not match an array index, only props and values
|
||||||
|
@ -273,7 +273,7 @@ test('nextSearchResult', () => {
|
||||||
"nill": null,
|
"nill": null,
|
||||||
"bool": false
|
"bool": false
|
||||||
})
|
})
|
||||||
const first = search(eson, 'A')
|
const first = applySearch(eson, 'A')
|
||||||
|
|
||||||
expect(first.searchResult.matches).toEqual([
|
expect(first.searchResult.matches).toEqual([
|
||||||
{path: ['bool'], area: 'value'},
|
{path: ['bool'], area: 'value'},
|
||||||
|
@ -314,7 +314,7 @@ test('previousSearchResult', () => {
|
||||||
"nill": null,
|
"nill": null,
|
||||||
"bool": false
|
"bool": false
|
||||||
})
|
})
|
||||||
const init = search(eson, 'A')
|
const init = applySearch(eson, 'A')
|
||||||
|
|
||||||
expect(init.searchResult.matches).toEqual([
|
expect(init.searchResult.matches).toEqual([
|
||||||
{path: ['bool'], area: 'value'},
|
{path: ['bool'], area: 'value'},
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult
|
* @typedef {{matches: ESONPointer[], active: ESONPointer}} SearchResult
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue