Move logic of search into `search.js`
This commit is contained in:
parent
be87b1e4cd
commit
7d67ecc4bc
|
@ -32,9 +32,9 @@
|
|||
} from './utils/immutabilityHelpers.js'
|
||||
import { compileJSONPointer, parseJSONPointer } from './utils/jsonPointer.js'
|
||||
import { keyComboFromEvent } from './utils/keyBindings.js'
|
||||
import { flattenSearch, search } from './utils/search.js'
|
||||
import { search, searchNext, searchPrevious } from './utils/search.js'
|
||||
import { immutableJSONPatch } from './utils/immutableJSONPatch'
|
||||
import { isEqual, isNumber, initial, last, cloneDeep, first } from 'lodash-es'
|
||||
import { isNumber, initial, last, cloneDeep } from 'lodash-es'
|
||||
import jump from './assets/jump.js/src/jump.js'
|
||||
import { syncState } from './utils/syncState.js'
|
||||
import { getNextKeys, patchProps } from './utils/updateProps.js'
|
||||
|
@ -42,12 +42,13 @@
|
|||
let divContents
|
||||
let domHiddenInput
|
||||
|
||||
export let doc = {}
|
||||
let state = undefined
|
||||
let selection = null
|
||||
|
||||
export let onChangeJson = () => {}
|
||||
|
||||
export let doc = {}
|
||||
let state = undefined
|
||||
let searchResult = undefined
|
||||
|
||||
let selection = null
|
||||
let clipboard = null
|
||||
$: hasSelectionContents = selection != null && selection.paths != null
|
||||
$: hasClipboardContents = clipboard != null && selection != null
|
||||
|
@ -78,6 +79,7 @@
|
|||
|
||||
export function set(newDocument) {
|
||||
doc = newDocument
|
||||
searchResult = undefined
|
||||
state = undefined
|
||||
history.clear()
|
||||
}
|
||||
|
@ -98,6 +100,7 @@
|
|||
|
||||
doc = documentPatchResult.json
|
||||
state = patchProps(statePatchResult.json, operations)
|
||||
searchResult = search(doc, searchText, searchResult)
|
||||
if (newSelection) {
|
||||
selection = newSelection
|
||||
}
|
||||
|
@ -222,6 +225,7 @@
|
|||
if (item) {
|
||||
doc = immutableJSONPatch(doc, item.undo).json
|
||||
state = item.prevState
|
||||
searchResult = search(doc, searchText, searchResult)
|
||||
selection = item.prevSelection
|
||||
|
||||
console.log('undo', { item, doc, state, selection })
|
||||
|
@ -237,6 +241,7 @@
|
|||
if (item) {
|
||||
doc = immutableJSONPatch(doc, item.redo).json
|
||||
state = item.state
|
||||
searchResult = search(doc, searchText, searchResult)
|
||||
selection = item.selection
|
||||
|
||||
console.log('redo', { item, doc, state, selection })
|
||||
|
@ -246,49 +251,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: refactor the search solution and move it in a separate component
|
||||
// in: doc, searchText, activeSearchResultIndex
|
||||
// out: searchResultWithActive
|
||||
// callbacks: change searchText, change doc, change activeSearchResultIndex
|
||||
let searchResult
|
||||
let activeSearchResult = undefined
|
||||
let activeSearchResultIndex
|
||||
let flatSearchResult
|
||||
let searchResultWithActive
|
||||
$: searchResult = searchText ? search(doc, searchText) : undefined
|
||||
$: flatSearchResult = flattenSearch(searchResult)
|
||||
|
||||
$: {
|
||||
if (!activeSearchResult || !existsIn(searchResult, activeSearchResult.path.concat(activeSearchResult.what))) {
|
||||
activeSearchResult = flatSearchResult[0]
|
||||
focusActiveSearchResult()
|
||||
}
|
||||
function changeSearchText (text) {
|
||||
searchText = text
|
||||
searchResult = search(doc, searchText, searchResult)
|
||||
}
|
||||
|
||||
$: activeSearchResultIndex = flatSearchResult.findIndex(item => isEqual(item, activeSearchResult))
|
||||
$: searchResultWithActive = searchResult
|
||||
? activeSearchResult
|
||||
? setIn(searchResult, activeSearchResult.path.concat(activeSearchResult.what), 'search active')
|
||||
: searchResult
|
||||
: undefined
|
||||
|
||||
function nextSearchResult () {
|
||||
activeSearchResult = flatSearchResult[activeSearchResultIndex + 1] || first(flatSearchResult)
|
||||
focusActiveSearchResult()
|
||||
searchResult = searchNext(searchResult)
|
||||
focusActiveSearchResult(searchResult && searchResult.activeItem)
|
||||
}
|
||||
|
||||
function previousSearchResult () {
|
||||
activeSearchResult = flatSearchResult[activeSearchResultIndex - 1] || last(flatSearchResult)
|
||||
focusActiveSearchResult()
|
||||
searchResult = searchPrevious(searchResult)
|
||||
focusActiveSearchResult(searchResult && searchResult.activeItem)
|
||||
}
|
||||
|
||||
async function focusActiveSearchResult () {
|
||||
if (activeSearchResult) {
|
||||
expandPath(activeSearchResult.path)
|
||||
async function focusActiveSearchResult (activeItem) {
|
||||
if (activeItem) {
|
||||
expandPath(activeItem.path)
|
||||
|
||||
await tick()
|
||||
|
||||
scrollTo(activeSearchResult.path.concat(activeSearchResult.what))
|
||||
scrollTo(activeItem.path.concat(activeItem.what))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,9 +533,9 @@
|
|||
<div class="search-box-container">
|
||||
<SearchBox
|
||||
text={searchText}
|
||||
resultCount={flatSearchResult.length}
|
||||
activeIndex={activeSearchResultIndex}
|
||||
onChange={(text) => searchText = text}
|
||||
resultCount={searchResult ? searchResult.count : 0}
|
||||
activeIndex={searchResult ? searchResult.activeIndex : 0}
|
||||
onChange={changeSearchText}
|
||||
onNext={nextSearchResult}
|
||||
onPrevious={previousSearchResult}
|
||||
onClose={() => {
|
||||
|
@ -574,7 +558,7 @@
|
|||
value={doc}
|
||||
path={[]}
|
||||
state={state}
|
||||
searchResult={searchResultWithActive}
|
||||
searchResult={searchResult && searchResult.itemsWithActive}
|
||||
onPatch={handlePatch}
|
||||
onUpdateKey={handleUpdateKey}
|
||||
onExpand={handleExpand}
|
||||
|
|
18
src/types.js
18
src/types.js
|
@ -54,16 +54,24 @@
|
|||
* paths: Path[],
|
||||
* pathsMap: Object<string, boolean>
|
||||
* }} MultiSelection
|
||||
*
|
||||
* @typedef {{beforePath: Path}} BeforeSelection
|
||||
*
|
||||
* @typedef {{appendPath: Path}} AppendSelection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{beforePath: Path}} BeforeSelection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{appendPath: Path}} AppendSelection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {MultiSelection | BeforeSelection | AppendSelection} Selection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{anchorPath: Path, focusPath: Path}} MultiSelectionSchema
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {MultiSelectionSchema | BeforeSelection | AppendSelection} SelectionSchema
|
||||
*/
|
||||
|
|
|
@ -1,9 +1,103 @@
|
|||
import { isNumber } from 'lodash-es'
|
||||
import { isEqual, isNumber } from 'lodash-es'
|
||||
import { STATE_SEARCH_PROPERTY, STATE_SEARCH_VALUE } from '../constants.js'
|
||||
import { existsIn, setIn } from './immutabilityHelpers.js'
|
||||
import { valueType } from './typeUtils.js'
|
||||
|
||||
export function search (doc, searchText) {
|
||||
return searchRecursive(null, doc, searchText)
|
||||
|
||||
/**
|
||||
* @typedef {{path: Path, what: Symbol}} SearchItem
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResult
|
||||
* @property {Object} items
|
||||
* @property {Object} itemsWithActive
|
||||
* @property {SearchItem[]} flatItems
|
||||
* @property {SearchItem} activeItem
|
||||
* @property {number} activeIndex
|
||||
* @property {number} count
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {JSON} doc
|
||||
* @param {string} searchText
|
||||
* @param {SearchResult} [previousResult]
|
||||
* @returns {SearchResult}
|
||||
*/
|
||||
export function search (doc, searchText, previousResult) {
|
||||
if (!searchText || searchText === '') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const items = searchRecursive(null, doc, searchText)
|
||||
|
||||
const flatItems = flattenSearch(items)
|
||||
|
||||
const activeItem = (previousResult && previousResult.activeItem &&
|
||||
existsIn(items, previousResult.activeItem.path.concat(previousResult.activeItem.what)))
|
||||
? previousResult.activeItem
|
||||
: flatItems[0]
|
||||
|
||||
const activeIndex = flatItems.findIndex(item => isEqual(item, activeItem))
|
||||
|
||||
const itemsWithActive = (items && activeItem)
|
||||
? setIn(items, activeItem.path.concat(activeItem.what), 'search active')
|
||||
: items
|
||||
|
||||
return {
|
||||
items,
|
||||
itemsWithActive,
|
||||
flatItems,
|
||||
count: flatItems.length,
|
||||
activeItem,
|
||||
activeIndex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SearchResult} searchResult
|
||||
* @return {SearchResult} nextResult
|
||||
*/
|
||||
export function searchNext (searchResult) {
|
||||
const nextActiveIndex = searchResult.activeIndex < searchResult.flatItems.length - 1
|
||||
? searchResult.activeIndex + 1
|
||||
: 0
|
||||
|
||||
const nextActiveItem = searchResult.flatItems[nextActiveIndex]
|
||||
|
||||
const itemsWithActive = nextActiveItem
|
||||
? setIn(searchResult.items, nextActiveItem.path.concat(nextActiveItem.what), 'search active')
|
||||
: searchResult.items
|
||||
|
||||
return {
|
||||
...searchResult,
|
||||
itemsWithActive,
|
||||
activeItem: nextActiveItem,
|
||||
activeIndex: nextActiveIndex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SearchResult} searchResult
|
||||
* @return {SearchResult} nextResult
|
||||
*/
|
||||
export function searchPrevious (searchResult) {
|
||||
const previousActiveIndex = searchResult.activeIndex > 0
|
||||
? searchResult.activeIndex - 1
|
||||
: searchResult.flatItems.length - 1
|
||||
|
||||
const previousActiveItem = searchResult.flatItems[previousActiveIndex]
|
||||
|
||||
const itemsWithActive = previousActiveItem
|
||||
? setIn(searchResult.items, previousActiveItem.path.concat(previousActiveItem.what), 'search active')
|
||||
: searchResult.items
|
||||
|
||||
return {
|
||||
...searchResult,
|
||||
itemsWithActive,
|
||||
activeItem: previousActiveItem,
|
||||
activeIndex: previousActiveIndex
|
||||
}
|
||||
}
|
||||
|
||||
function searchRecursive (key, doc, searchText) {
|
||||
|
@ -37,7 +131,7 @@ function searchRecursive (key, doc, searchText) {
|
|||
return results
|
||||
}
|
||||
|
||||
export function flattenSearch (searchResult) {
|
||||
function flattenSearch (searchResult) {
|
||||
const resultArray = []
|
||||
|
||||
function _flattenSearch (value, path) {
|
||||
|
|
Loading…
Reference in New Issue