From 0f24a9204fa54b595217c7df45a036bf97b16c8a Mon Sep 17 00:00:00 2001 From: jos Date: Wed, 26 Sep 2018 17:40:44 +0200 Subject: [PATCH] Implemented `findSelectionPointerFromEvent` (WIP) --- src/jsoneditor/components/TreeMode.js | 89 ++++++++++++++++++++++++--- src/jsoneditor/eson.js | 2 +- src/jsoneditor/types.js | 2 +- src/jsoneditor/utils/domUtils.js | 4 ++ 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/jsoneditor/components/TreeMode.js b/src/jsoneditor/components/TreeMode.js index 39d8348..3f4d04d 100644 --- a/src/jsoneditor/components/TreeMode.js +++ b/src/jsoneditor/components/TreeMode.js @@ -52,6 +52,7 @@ import { expand, EXPANDED, expandPath, + findSharedPath, immutableESONPatch, nextSearchResult, pathsFromSelection, @@ -62,7 +63,7 @@ import { } from '../eson' import TreeModeMenu from './menu/TreeModeMenu' import Search from './menu/Search' -import { findParentWithAttribute } from '../utils/domUtils' +import { findParentWithAttribute, toArray } from '../utils/domUtils' const AJV_OPTIONS = { allErrors: true, @@ -248,7 +249,7 @@ export default class TreeMode extends PureComponent { }, h(Hammer, { id: this.id, - direction: 'DIRECTION_VERTICAL', + direction: 'DIRECTION_ALL', onPan: this.handlePan, onPanEnd: this.handlePanEnd }, @@ -783,9 +784,7 @@ export default class TreeMode extends PureComponent { return } - const selectionPointer = this.findSelectionPointerFromEvent(event) - - console.log('touchStart selectionPointer=', selectionPointer) + this.selectionStartPointer = this.findSelectionPointerFromEvent(event.target, event.clientY) const pointer = this.findJSONPointerFromElement(event.target) const clickedOnEmptySpace = (event.target.nodeName === 'DIV') && @@ -804,6 +803,11 @@ export default class TreeMode extends PureComponent { } handlePan = (event) => { + this.selectionEndPointer = this.findSelectionPointerFromEvent(event.target, event.center.y) + + const selection2 = this.findSelectionFromPointers(this.selectionStartPointer, this.selectionEndPointer) + console.log('selection', JSON.stringify(selection2)) + const selection = this.state.selection const path = this.findDataPathFromElement(event.target.firstChild) if (path && selection && !isEqual(path, selection.end)) { @@ -864,16 +868,17 @@ export default class TreeMode extends PureComponent { /** * Find JSON pointer from an HTML element - * @param {Event} event + * @param {Element} element + * @param {number} y * @return {SelectionPointer | null} */ - findSelectionPointerFromEvent (event) { - const areaParent = findParentWithAttribute(event.target, 'data-selection-area') + findSelectionPointerFromEvent (element, y) { + const areaParent = findParentWithAttribute(element, 'data-selection-area') const area = areaParent ? areaParent.getAttribute('data-selection-area') : undefined const base = (area === 'left') - ? document.elementFromPoint(event.target.getBoundingClientRect().right - 1, event.clientY) - : event.target + ? document.elementFromPoint(element.getBoundingClientRect().right - 1, y) + : element const pathParent = findParentWithAttribute(base, 'data-path') const path = pathParent ? pathParent.getAttribute('data-path') : undefined @@ -881,6 +886,70 @@ export default class TreeMode extends PureComponent { return (area !== undefined && path !== undefined) ? { area, path } : null } + /** + * @param {SelectionPointer} start + * @param {SelectionPointer} end + */ + findSelectionFromPointers (start, end) { + if (start && end) { + const startPath = parseJSONPointer(start.path) + const endPath = parseJSONPointer(end.path) + + const sharedPath = findSharedPath(startPath, endPath) + const startChildPath = startPath.slice(0, sharedPath.length + 1) + const endChildPath = endPath.slice(0, sharedPath.length + 1) + + if (isEqual(startChildPath, sharedPath) || isEqual(endChildPath, sharedPath)) { + // one element + if (start.area === 'right' && end.area === 'right' && start.path === end.path) { + return { type: 'after', after: compileJSONPointer(sharedPath) } + } + + if (start.path !== end.path || start.area !== end.area || start.area === 'contents' || end.area === 'contents') { + return { type: 'multi', multi: [ compileJSONPointer(sharedPath) ] } + } + } + else { + // multiple elements + // find all nodes in between using the DOM + const startElement = this.refs.contents.querySelector(`div[data-path="${compileJSONPointer(startChildPath)}"]`) + const endElement = this.refs.contents.querySelector(`div[data-path="${compileJSONPointer(endChildPath)}"]`) + + const childs = toArray(startElement.parentNode.childNodes) + const startIndex = childs.indexOf(startElement) + const endIndex = childs.indexOf(endElement) + + const first = startIndex < endIndex ? start : end + const last = startIndex < endIndex ? end : start + const includeFirst = first.area !== 'right' || parseJSONPointer(first.path).length > sharedPath.length + 1 + const includeLast = last.area !== 'left' || parseJSONPointer(last.path).length > sharedPath.length + 1 + + const firstIndex = Math.min(startIndex, endIndex) + (includeFirst ? 0 : 1) + const lastIndex = Math.max(startIndex, endIndex) + (includeLast ? 1 : 0) + + if (firstIndex < lastIndex) { + return { + type: 'multi', + multi: childs + .slice(firstIndex, lastIndex) + .map(element => element.getAttribute('data-path')) + } + } + else { + // selection starts after first node and ends before last node + return { + type: 'after', + path: first.path + } + } + } + } + + return { + type: 'none' + } + } + /** * Get selection from an JSONPointer * @param {ESONPointer} pointer diff --git a/src/jsoneditor/eson.js b/src/jsoneditor/eson.js index bc61266..c541ef5 100644 --- a/src/jsoneditor/eson.js +++ b/src/jsoneditor/eson.js @@ -495,7 +495,7 @@ export function findRootPath(selection) { * @param {Path} path2 * @return {Path} */ -function findSharedPath (path1, path2) { +export function findSharedPath (path1, path2) { let i = 0; while (i < path1.length && path1[i] === path2[i]) { i++; diff --git a/src/jsoneditor/types.js b/src/jsoneditor/types.js index 44a7627..7b0f056 100644 --- a/src/jsoneditor/types.js +++ b/src/jsoneditor/types.js @@ -40,7 +40,7 @@ /** * @typedef {{ * area: 'left' | 'contents' | 'after', - * path: Path + * path: string * }} SelectionPointer */ diff --git a/src/jsoneditor/utils/domUtils.js b/src/jsoneditor/utils/domUtils.js index f9952c2..65ff05c 100644 --- a/src/jsoneditor/utils/domUtils.js +++ b/src/jsoneditor/utils/domUtils.js @@ -176,6 +176,10 @@ export function insideRect (parent, child, margin = 0) { && child.bottom + margin <= parent.bottom } +export function toArray(nodes) { + return Array.prototype.slice.call(nodes) +} + /** * Returns the version of Internet Explorer or a -1 * (indicating the use of another browser).