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,10 +12,20 @@
box-sizing: border-box; box-sizing: border-box;
} }
&.selected .header, &.hovered {
&.selected .contents, .header,
&.selected .footer { .contents,
background-color: $selection-background; .footer {
background-color: $hovered-background;
}
}
&.selected {
.header,
.contents,
.footer {
background-color: $selection-background;
}
} }
$selector-height: 8px; // must be about half a line height $selector-height: 8px; // must be about half a line height

View File

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

View File

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

View File

@ -179,9 +179,12 @@ export function traverseInnerText (element, buffer) {
return '' return ''
} }
// test whether a DOM element is a child of a button export function isChildOfNodeName (element, nodeName) {
export function isChildOfButton (element) { return isChildOf(element, e => e.nodeName.toUpperCase() === nodeName.toUpperCase())
return isChildOf(element, e => e.nodeName === 'BUTTON') }
export function isChildOfAttribute (element, name, value) {
return isChildOf(element, e => hasAttribute(e, name, value))
} }
// test whether a DOM element is a content editable div // 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') 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) { function hasAttribute(element, name, value) {
return typeof element.getAttribute === 'function' && element.getAttribute(name) === value return typeof element.getAttribute === 'function' && element.getAttribute(name) === value
} }