From aaa498b4eccce43c0e775bc57565ad4fb8d13461 Mon Sep 17 00:00:00 2001 From: jos Date: Wed, 26 Sep 2018 11:32:40 +0200 Subject: [PATCH] Implemented `findSelectionPointerFromEvent` --- src/demo/Demo.css | 3 + src/demo/Demo.scss | 4 + src/jsoneditor/components/JSONNode.js | 104 +++++++++++++++++--------- src/jsoneditor/components/TreeMode.js | 29 ++++++- src/jsoneditor/types.js | 7 ++ 5 files changed, 108 insertions(+), 39 deletions(-) diff --git a/src/demo/Demo.css b/src/demo/Demo.css index aaf992d..bb10f39 100644 --- a/src/demo/Demo.css +++ b/src/demo/Demo.css @@ -2,6 +2,9 @@ body, input, select { font-family: sans-serif; font-size: 11pt; } +body { + height: 2000px; } + .demo .menu { margin: 20px 0; } .demo .menu button, .demo .menu label { diff --git a/src/demo/Demo.scss b/src/demo/Demo.scss index 4a2388b..5faa279 100644 --- a/src/demo/Demo.scss +++ b/src/demo/Demo.scss @@ -4,6 +4,10 @@ body, input, select { font-size: 11pt; } +body { + height: 2000px; +} + .demo { .menu { margin: 20px 0; diff --git a/src/jsoneditor/components/JSONNode.js b/src/jsoneditor/components/JSONNode.js index 252e7a0..7b35234 100644 --- a/src/jsoneditor/components/JSONNode.js +++ b/src/jsoneditor/components/JSONNode.js @@ -89,10 +89,11 @@ export default class JSONNode extends PureComponent { const jsonPropsCount = jsonProps.length const nodeStart = h('div', { - key: 'node', - onKeyDown: this.handleKeyDown, - className: 'jsoneditor-node jsoneditor-object' - }, [ + key: 'node', + onKeyDown: this.handleKeyDown, + 'data-selection-area': 'contents', + className: 'jsoneditor-node jsoneditor-object' + }, [ this.renderExpandButton(), // this.renderDelimiter('\u2610'), this.renderProperty(), @@ -121,24 +122,39 @@ export default class JSONNode extends PureComponent { options: this.props.options })) - childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, propsChilds) + childs = h('div', { + key: 'childs', + 'data-selection-area': 'left', + className: 'jsoneditor-list' + }, propsChilds) } else { - childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'}, - this.renderAppend('(empty object)') + childs = h('div', { + key: 'childs', + className: 'jsoneditor-list', + 'data-area': 'emptyBefore', // TODO: remove + 'data-selection-area': 'left' + }, + this.renderEmpty('(empty object)') ) } } const nodeEnd = this.props.eson[EXPANDED] - ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ - this.renderDelimiter('}', 'jsoneditor-delimiter-end') + ? h('div', { + key: 'node-end', + className: 'jsoneditor-node-end', + 'data-selection-area': 'right', + 'data-area': 'empty', // TODO: remove + }, [ + this.renderDelimiter('}', 'jsoneditor-delimiter-end', 'left') ]) : null return h('div', { 'data-path': compileJSONPointer(this.state.path), - 'data-area': 'empty', + 'data-area': 'empty', // TODO: remove + 'data-selection-area': 'right', className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover), // onMouseOver: this.handleMouseOver, // onMouseLeave: this.handleMouseLeave @@ -151,6 +167,7 @@ export default class JSONNode extends PureComponent { const nodeStart = h('div', { key: 'node', onKeyDown: this.handleKeyDown, + 'data-selection-area': 'contents', className: 'jsoneditor-node jsoneditor-array' }, [ this.renderExpandButton(), @@ -180,24 +197,34 @@ export default class JSONNode extends PureComponent { findKeyBinding: this.props.findKeyBinding })) - childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, items) + childs = h('div', { + key: 'childs', + 'data-selection-area': 'left', + className: 'jsoneditor-list' + }, items) } else { - childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'}, - this.renderAppend('(empty array)') + childs = h('div', { + key: 'childs', + className: 'jsoneditor-list', + 'data-selection-area': 'left', + 'data-area': 'emptyBefore' // TODO: remove data-area + }, + this.renderEmpty('(empty array)') ) } } const nodeEnd = this.props.eson[EXPANDED] - ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ - this.renderDelimiter(']', 'jsoneditor-delimiter-end') + ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ // TODO: remove data-area + this.renderDelimiter(']', 'jsoneditor-delimiter-end', 'left') ]) : null return h('div', { 'data-path': compileJSONPointer(this.state.path), - 'data-area': 'empty', + 'data-area': 'empty', // TODO: remove data-area + 'data-selection-area': 'right', className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover), // onMouseOver: this.handleMouseOver, // onMouseLeave: this.handleMouseLeave @@ -208,6 +235,7 @@ export default class JSONNode extends PureComponent { const node = h('div', { key: 'node', onKeyDown: this.handleKeyDown, + 'data-selection-area': 'contents', className: 'jsoneditor-node' }, [ this.renderPlaceholder(), @@ -221,7 +249,8 @@ export default class JSONNode extends PureComponent { return h('div', { 'data-path': compileJSONPointer(this.state.path), - 'data-area': 'empty', + 'data-area': 'empty', // TODO: remove + 'data-selection-area': 'right', className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover), // onMouseOver: this.handleMouseOver, // onMouseLeave: this.handleMouseLeave @@ -233,22 +262,27 @@ export default class JSONNode extends PureComponent { * @param {string} text * @return {*} */ - renderAppend (text) { + renderEmpty (text) { return h('div', { - 'data-path': compileJSONPointer(this.state.path) + '/-', - 'data-area': 'empty', - className: 'jsoneditor-node', - onKeyDown: this.handleKeyDownAppend - }, [ - this.renderPlaceholder('inside'), + 'data-path': compileJSONPointer(this.state.path) + '/-', + 'data-area': 'empty', // TODO: remove + 'data-selection-area': 'right', + className: 'jsoneditor-node-container' + }, h('div', { + className: 'jsoneditor-node', + 'data-selection-area': 'contents', + onKeyDown: this.handleKeyDownAppend + }, [ + this.renderPlaceholder(), this.renderReadonly(text) - ]) + ])) } - renderPlaceholder (dataArea = 'value') { + renderPlaceholder () { return h('div', { key: 'placeholder', - 'data-area': dataArea, + // 'data-area': dataArea, // TODO: remove + 'data-selection-area': 'left', className: 'jsoneditor-button-placeholder' }) } @@ -256,7 +290,7 @@ export default class JSONNode extends PureComponent { renderReadonly (text, title = null, dataArea = 'inside') { return h('div', { key: 'readonly', - 'data-area': dataArea, + 'data-area': dataArea, // TODO: remove className: 'jsoneditor-readonly', title }, text) @@ -320,14 +354,15 @@ export default class JSONNode extends PureComponent { return h('div', { key: 'separator', className: 'jsoneditor-delimiter', - 'data-area': 'value' + 'data-area': 'value' // TODO: remove }, ':') } - renderDelimiter (text, className = '') { + renderDelimiter (text, className = '', dataArea) { return h('div', { key: text, - 'data-area': 'value', + 'data-area': 'value', // TODO: remove + 'data-selection-area': dataArea, className: 'jsoneditor-delimiter ' + className }, text) } @@ -520,6 +555,7 @@ export default class JSONNode extends PureComponent { return h('div', {key: 'expand', className: 'jsoneditor-button-container'}, h('button', { + 'data-selection-area': 'left', className: className, onClick: this.handleExpand, title: @@ -561,12 +597,6 @@ export default class JSONNode extends PureComponent { this.setState({hover: null}) } - static getRootName (value, options) { - return typeof options.name === 'string' - ? options.name - : value[TYPE] - } - /** @private */ handleChangeProperty = (event) => { const parentPath = initial(this.state.path) diff --git a/src/jsoneditor/components/TreeMode.js b/src/jsoneditor/components/TreeMode.js index 4ed7178..39d8348 100644 --- a/src/jsoneditor/components/TreeMode.js +++ b/src/jsoneditor/components/TreeMode.js @@ -57,10 +57,12 @@ import { pathsFromSelection, previousSearchResult, search, + SELECTION, syncEson } from '../eson' import TreeModeMenu from './menu/TreeModeMenu' import Search from './menu/Search' +import { findParentWithAttribute } from '../utils/domUtils' const AJV_OPTIONS = { allErrors: true, @@ -254,9 +256,9 @@ export default class TreeMode extends PureComponent { onMouseDown: this.handleTouchStart, onTouchStart: this.handleTouchStart, className: 'jsoneditor-list jsoneditor-root' + - (/*eson[META].selected*/ false ? ' jsoneditor-selected' : '')}, // FIXME + (eson[SELECTION] !== false ? ' jsoneditor-selected' : '')}, h(Node, { - path: [], + parentPath: null, eson, emit: this.emitter.emit, findKeyBinding: this.findKeyBinding, @@ -781,6 +783,10 @@ export default class TreeMode extends PureComponent { return } + const selectionPointer = this.findSelectionPointerFromEvent(event) + + console.log('touchStart selectionPointer=', selectionPointer) + const pointer = this.findJSONPointerFromElement(event.target) const clickedOnEmptySpace = (event.target.nodeName === 'DIV') && (event.target.contentEditable !== 'true') && @@ -856,6 +862,25 @@ export default class TreeMode extends PureComponent { return path ? { path, area } : null } + /** + * Find JSON pointer from an HTML element + * @param {Event} event + * @return {SelectionPointer | null} + */ + findSelectionPointerFromEvent (event) { + const areaParent = findParentWithAttribute(event.target, '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 + + const pathParent = findParentWithAttribute(base, 'data-path') + const path = pathParent ? pathParent.getAttribute('data-path') : undefined + + return (area !== undefined && path !== undefined) ? { area, path } : null + } + /** * Get selection from an JSONPointer * @param {ESONPointer} pointer diff --git a/src/jsoneditor/types.js b/src/jsoneditor/types.js index 68f4e3d..44a7627 100644 --- a/src/jsoneditor/types.js +++ b/src/jsoneditor/types.js @@ -37,6 +37,13 @@ * }} Selection */ +/** + * @typedef {{ + * area: 'left' | 'contents' | 'after', + * path: Path + * }} SelectionPointer + */ + /** * @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult */