Move logic of search into `search.js`

This commit is contained in:
Jos de Jong 2020-07-22 16:53:18 +02:00
parent be87b1e4cd
commit 7d67ecc4bc
3 changed files with 137 additions and 51 deletions

View File

@ -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}

View File

@ -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
*/

View File

@ -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) {