Highlight object when hovering, select node only when clicking inside one of the selectable areas

This commit is contained in:
Jos de Jong 2020-08-13 15:29:51 +02:00
parent 22845a0cc8
commit 1477aaaa4b
4 changed files with 54 additions and 46 deletions

View File

@ -12,11 +12,21 @@
box-sizing: border-box;
}
&.selected .header,
&.selected .contents,
&.selected .footer {
&.hovered {
.header,
.contents,
.footer {
background-color: $hovered-background;
}
}
&.selected {
.header,
.contents,
.footer {
background-color: $selection-background;
}
}
$selector-height: 8px; // must be about half a line height

View File

@ -15,9 +15,8 @@
} from '../constants.js'
import {
getPlainText,
isAppendNodeSelector,
isBeforeNodeSelector,
isChildOfButton,
isChildOfAttribute,
isChildOfNodeName,
isContentEditableDiv,
setPlainText
} from '../utils/domUtils.js'
@ -51,6 +50,7 @@
let domKey
let domValue
let hovered = false
$: type = valueType (value)
@ -224,11 +224,11 @@
}
// check if the mouse down is not happening in the key or value input fields or on a button
if (isContentEditableDiv(event.target) || isChildOfButton(event.target)) {
if (isContentEditableDiv(event.target) || isChildOfNodeName(event.target, 'BUTTON')) {
return
}
if (isBeforeNodeSelector(event.target)) {
if (isChildOfAttribute(event.target, 'data-type', 'before-node-selector')) {
singleton.mousedown = true
singleton.selectionAnchor = path
singleton.selectionFocus = null
@ -236,7 +236,7 @@
onSelect({
beforePath: path
})
} else if (isAppendNodeSelector(event.target)) {
} else if (isChildOfAttribute(event.target, 'data-type', 'append-node-selector')) {
singleton.mousedown = true
singleton.selectionAnchor = path
singleton.selectionFocus = null
@ -248,13 +248,16 @@
// initialize dragging a selection
singleton.mousedown = true
singleton.selectionAnchor = path
singleton.selectionFocus = path
singleton.selectionFocus = null
if (isChildOfAttribute(event.target, 'data-type', 'selectable-area')) {
// select current node
onSelect({
anchorPath: singleton.selectionAnchor,
focusPath: singleton.selectionFocus
anchorPath: path,
focusPath: path
})
}
}
event.stopPropagation()
// IMPORTANT: do not use event.preventDefault() here,
@ -299,21 +302,20 @@
document.removeEventListener('mouseup', handleMouseUp)
}
function handleSelectBefore (event) {
function handleMouseOver (event) {
event.stopPropagation()
onSelect({
beforePath: path
})
if (
isChildOfAttribute(event.target, 'data-type', 'selectable-area') &&
!isContentEditableDiv(event.target)
) {
hovered = true
}
}
function handleSelectAfter (event) {
event.preventDefault()
function handleMouseOut (event) {
event.stopPropagation()
onSelect({
appendPath: path
})
hovered = false
}
// FIXME: this is not efficient. Create a nested object with the selection and pass that
@ -336,8 +338,11 @@
class='json-node'
class:root={path.length === 0}
class:selected={selected}
class:hovered={hovered}
on:mousedown={handleMouseDown}
on:mousemove={handleMouseMove}
on:mouseover={handleMouseOver}
on:mouseout={handleMouseOut}
>
<div
data-type="before-node-selector"
@ -348,7 +353,8 @@
<div class="selector"></div>
</div>
{#if type === 'array'}
<div class='header' style={indentationStyle}>
<div
data-type="selectable-area" class='header' style={indentationStyle} >
<button
class='expand'
on:click={toggleExpand}
@ -422,12 +428,12 @@
</div>
{/if}
</div>
<div class="footer" style={indentationStyle}>
<div data-type="selectable-area" class="footer" style={indentationStyle} >
<span class="delimiter">]</span>
</div>
{/if}
{:else if type === 'object'}
<div class='header' style={indentationStyle}>
<div data-type="selectable-area" class="header" style={indentationStyle} >
<button
class='expand'
on:click={toggleExpand}
@ -496,12 +502,12 @@
<div class="selector"></div>
</div>
</div>
<div class="footer" style={indentationStyle}>
<div data-type="selectable-area" class="footer" style={indentationStyle} >
<span class="delimiter">&rbrace;</span>
</div>
{/if}
{:else}
<div class="contents" style={indentationStyle}>
<div data-type="selectable-area" class="contents" style={indentationStyle} >
{#if typeof key === 'string'}
<div
class={keyClass}

View File

@ -25,6 +25,7 @@ $gray: #9d9d9d;
$gray-icon: $gray;
$light-gray: #c0c0c0;
$selection-background: #e0e0e0;
$hovered-background: #f0f0f0;
$background-gray: #f5f5f5;
$line-height: 18px;

View File

@ -179,9 +179,12 @@ export function traverseInnerText (element, buffer) {
return ''
}
// test whether a DOM element is a child of a button
export function isChildOfButton (element) {
return isChildOf(element, e => e.nodeName === 'BUTTON')
export function isChildOfNodeName (element, nodeName) {
return isChildOf(element, e => e.nodeName.toUpperCase() === nodeName.toUpperCase())
}
export function isChildOfAttribute (element, name, value) {
return isChildOf(element, e => hasAttribute(e, name, value))
}
// test whether a DOM element is a content editable div
@ -189,18 +192,6 @@ export function isContentEditableDiv (element) {
return (element.nodeName === 'DIV' && element.contentEditable === 'true')
}
export function isBeforeNodeSelector (element) {
return isChildOf(element, e => {
return hasAttribute(e, 'data-type', 'before-node-selector')
})
}
export function isAppendNodeSelector (element) {
return isChildOf(element, e => {
return hasAttribute(e, 'data-type', 'append-node-selector')
})
}
function hasAttribute(element, name, value) {
return typeof element.getAttribute === 'function' && element.getAttribute(name) === value
}