Implemented `findSelectionPointerFromEvent`

This commit is contained in:
jos 2018-09-26 11:32:40 +02:00
parent 6c17d6256c
commit aaa498b4ec
5 changed files with 108 additions and 39 deletions

View File

@ -2,6 +2,9 @@ body, input, select {
font-family: sans-serif; font-family: sans-serif;
font-size: 11pt; } font-size: 11pt; }
body {
height: 2000px; }
.demo .menu { .demo .menu {
margin: 20px 0; } margin: 20px 0; }
.demo .menu button, .demo .menu label { .demo .menu button, .demo .menu label {

View File

@ -4,6 +4,10 @@ body, input, select {
font-size: 11pt; font-size: 11pt;
} }
body {
height: 2000px;
}
.demo { .demo {
.menu { .menu {
margin: 20px 0; margin: 20px 0;

View File

@ -89,10 +89,11 @@ export default class JSONNode extends PureComponent {
const jsonPropsCount = jsonProps.length const jsonPropsCount = jsonProps.length
const nodeStart = h('div', { const nodeStart = h('div', {
key: 'node', key: 'node',
onKeyDown: this.handleKeyDown, onKeyDown: this.handleKeyDown,
className: 'jsoneditor-node jsoneditor-object' 'data-selection-area': 'contents',
}, [ className: 'jsoneditor-node jsoneditor-object'
}, [
this.renderExpandButton(), this.renderExpandButton(),
// this.renderDelimiter('\u2610'), // this.renderDelimiter('\u2610'),
this.renderProperty(), this.renderProperty(),
@ -121,24 +122,39 @@ export default class JSONNode extends PureComponent {
options: this.props.options 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 { else {
childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'}, childs = h('div', {
this.renderAppend('(empty object)') key: 'childs',
className: 'jsoneditor-list',
'data-area': 'emptyBefore', // TODO: remove
'data-selection-area': 'left'
},
this.renderEmpty('(empty object)')
) )
} }
} }
const nodeEnd = this.props.eson[EXPANDED] const nodeEnd = this.props.eson[EXPANDED]
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ ? h('div', {
this.renderDelimiter('}', 'jsoneditor-delimiter-end') key: 'node-end',
className: 'jsoneditor-node-end',
'data-selection-area': 'right',
'data-area': 'empty', // TODO: remove
}, [
this.renderDelimiter('}', 'jsoneditor-delimiter-end', 'left')
]) ])
: null : null
return h('div', { return h('div', {
'data-path': compileJSONPointer(this.state.path), '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), className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
@ -151,6 +167,7 @@ export default class JSONNode extends PureComponent {
const nodeStart = h('div', { const nodeStart = h('div', {
key: 'node', key: 'node',
onKeyDown: this.handleKeyDown, onKeyDown: this.handleKeyDown,
'data-selection-area': 'contents',
className: 'jsoneditor-node jsoneditor-array' className: 'jsoneditor-node jsoneditor-array'
}, [ }, [
this.renderExpandButton(), this.renderExpandButton(),
@ -180,24 +197,34 @@ export default class JSONNode extends PureComponent {
findKeyBinding: this.props.findKeyBinding 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 { else {
childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'}, childs = h('div', {
this.renderAppend('(empty array)') 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] const nodeEnd = this.props.eson[EXPANDED]
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [ // TODO: remove data-area
this.renderDelimiter(']', 'jsoneditor-delimiter-end') this.renderDelimiter(']', 'jsoneditor-delimiter-end', 'left')
]) ])
: null : null
return h('div', { return h('div', {
'data-path': compileJSONPointer(this.state.path), '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), className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
@ -208,6 +235,7 @@ export default class JSONNode extends PureComponent {
const node = h('div', { const node = h('div', {
key: 'node', key: 'node',
onKeyDown: this.handleKeyDown, onKeyDown: this.handleKeyDown,
'data-selection-area': 'contents',
className: 'jsoneditor-node' className: 'jsoneditor-node'
}, [ }, [
this.renderPlaceholder(), this.renderPlaceholder(),
@ -221,7 +249,8 @@ export default class JSONNode extends PureComponent {
return h('div', { return h('div', {
'data-path': compileJSONPointer(this.state.path), '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), className: this.getContainerClassName(this.props.eson[SELECTION], this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
@ -233,22 +262,27 @@ export default class JSONNode extends PureComponent {
* @param {string} text * @param {string} text
* @return {*} * @return {*}
*/ */
renderAppend (text) { renderEmpty (text) {
return h('div', { return h('div', {
'data-path': compileJSONPointer(this.state.path) + '/-', 'data-path': compileJSONPointer(this.state.path) + '/-',
'data-area': 'empty', 'data-area': 'empty', // TODO: remove
className: 'jsoneditor-node', 'data-selection-area': 'right',
onKeyDown: this.handleKeyDownAppend className: 'jsoneditor-node-container'
}, [ }, h('div', {
this.renderPlaceholder('inside'), className: 'jsoneditor-node',
'data-selection-area': 'contents',
onKeyDown: this.handleKeyDownAppend
}, [
this.renderPlaceholder(),
this.renderReadonly(text) this.renderReadonly(text)
]) ]))
} }
renderPlaceholder (dataArea = 'value') { renderPlaceholder () {
return h('div', { return h('div', {
key: 'placeholder', key: 'placeholder',
'data-area': dataArea, // 'data-area': dataArea, // TODO: remove
'data-selection-area': 'left',
className: 'jsoneditor-button-placeholder' className: 'jsoneditor-button-placeholder'
}) })
} }
@ -256,7 +290,7 @@ export default class JSONNode extends PureComponent {
renderReadonly (text, title = null, dataArea = 'inside') { renderReadonly (text, title = null, dataArea = 'inside') {
return h('div', { return h('div', {
key: 'readonly', key: 'readonly',
'data-area': dataArea, 'data-area': dataArea, // TODO: remove
className: 'jsoneditor-readonly', className: 'jsoneditor-readonly',
title title
}, text) }, text)
@ -320,14 +354,15 @@ export default class JSONNode extends PureComponent {
return h('div', { return h('div', {
key: 'separator', key: 'separator',
className: 'jsoneditor-delimiter', className: 'jsoneditor-delimiter',
'data-area': 'value' 'data-area': 'value' // TODO: remove
}, ':') }, ':')
} }
renderDelimiter (text, className = '') { renderDelimiter (text, className = '', dataArea) {
return h('div', { return h('div', {
key: text, key: text,
'data-area': 'value', 'data-area': 'value', // TODO: remove
'data-selection-area': dataArea,
className: 'jsoneditor-delimiter ' + className className: 'jsoneditor-delimiter ' + className
}, text) }, text)
} }
@ -520,6 +555,7 @@ export default class JSONNode extends PureComponent {
return h('div', {key: 'expand', className: 'jsoneditor-button-container'}, return h('div', {key: 'expand', className: 'jsoneditor-button-container'},
h('button', { h('button', {
'data-selection-area': 'left',
className: className, className: className,
onClick: this.handleExpand, onClick: this.handleExpand,
title: title:
@ -561,12 +597,6 @@ export default class JSONNode extends PureComponent {
this.setState({hover: null}) this.setState({hover: null})
} }
static getRootName (value, options) {
return typeof options.name === 'string'
? options.name
: value[TYPE]
}
/** @private */ /** @private */
handleChangeProperty = (event) => { handleChangeProperty = (event) => {
const parentPath = initial(this.state.path) const parentPath = initial(this.state.path)

View File

@ -57,10 +57,12 @@ import {
pathsFromSelection, pathsFromSelection,
previousSearchResult, previousSearchResult,
search, search,
SELECTION,
syncEson syncEson
} from '../eson' } from '../eson'
import TreeModeMenu from './menu/TreeModeMenu' import TreeModeMenu from './menu/TreeModeMenu'
import Search from './menu/Search' import Search from './menu/Search'
import { findParentWithAttribute } from '../utils/domUtils'
const AJV_OPTIONS = { const AJV_OPTIONS = {
allErrors: true, allErrors: true,
@ -254,9 +256,9 @@ export default class TreeMode extends PureComponent {
onMouseDown: this.handleTouchStart, onMouseDown: this.handleTouchStart,
onTouchStart: this.handleTouchStart, onTouchStart: this.handleTouchStart,
className: 'jsoneditor-list jsoneditor-root' + className: 'jsoneditor-list jsoneditor-root' +
(/*eson[META].selected*/ false ? ' jsoneditor-selected' : '')}, // FIXME (eson[SELECTION] !== false ? ' jsoneditor-selected' : '')},
h(Node, { h(Node, {
path: [], parentPath: null,
eson, eson,
emit: this.emitter.emit, emit: this.emitter.emit,
findKeyBinding: this.findKeyBinding, findKeyBinding: this.findKeyBinding,
@ -781,6 +783,10 @@ export default class TreeMode extends PureComponent {
return return
} }
const selectionPointer = this.findSelectionPointerFromEvent(event)
console.log('touchStart selectionPointer=', selectionPointer)
const pointer = this.findJSONPointerFromElement(event.target) const pointer = this.findJSONPointerFromElement(event.target)
const clickedOnEmptySpace = (event.target.nodeName === 'DIV') && const clickedOnEmptySpace = (event.target.nodeName === 'DIV') &&
(event.target.contentEditable !== 'true') && (event.target.contentEditable !== 'true') &&
@ -856,6 +862,25 @@ export default class TreeMode extends PureComponent {
return path ? { path, area } : null 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 * Get selection from an JSONPointer
* @param {ESONPointer} pointer * @param {ESONPointer} pointer

View File

@ -37,6 +37,13 @@
* }} Selection * }} Selection
*/ */
/**
* @typedef {{
* area: 'left' | 'contents' | 'after',
* path: Path
* }} SelectionPointer
*/
/** /**
* @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult * @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult
*/ */