Unify selection on mousedown

This commit is contained in:
Jos de Jong 2020-07-15 10:24:39 +02:00
parent 3919585db4
commit f3459430b0
4 changed files with 77 additions and 18 deletions

View File

@ -32,6 +32,8 @@
right: $input-padding; right: $input-padding;
height: $selector-height; height: $selector-height;
box-sizing: border-box; box-sizing: border-box;
padding-left: $indentation-width;
z-index: 1;
.selector { .selector {
margin-top: $selector-height / 2; margin-top: $selector-height / 2;
@ -39,13 +41,13 @@
&:hover { &:hover {
.selector { .selector {
border: 1px dashed $selection-background; border: 1px dashed $theme-color;
} }
} }
&.selected { &.selected {
.selector { .selector {
border: 1px dashed $theme-color; border: 1px dashed $gray;
} }
} }
} }
@ -54,8 +56,12 @@
top: -$selector-height/2 - 1px; top: -$selector-height/2 - 1px;
} }
.after-node-selector { .append-node-selector {
bottom: -$selector-height/2 - 1px; bottom: -$selector-height/2 - 1px;
.selector {
margin-top: $selector-height / 2 - 2px;
}
} }
.header { .header {

View File

@ -14,7 +14,10 @@
import { singleton } from './singleton.js' import { singleton } from './singleton.js'
import { import {
getPlainText, getPlainText,
isChildOfButton, isContentEditableDiv, isAppendNodeSelector,
isBeforeNodeSelector,
isChildOfButton,
isContentEditableDiv,
setPlainText setPlainText
} from './utils/domUtils.js' } from './utils/domUtils.js'
import Icon from 'svelte-awesome' import Icon from 'svelte-awesome'
@ -218,7 +221,27 @@
} }
// 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) || isChildOfButton(event.target)) {
return
}
if (isBeforeNodeSelector(event.target)) {
singleton.mousedown = true
singleton.selectionAnchor = path
singleton.selectionFocus = null
onSelect({
beforePath: path
})
} else if (isAppendNodeSelector(event.target)) {
singleton.mousedown = true
singleton.selectionAnchor = path
singleton.selectionFocus = null
onSelect({
appendPath: path
})
} else {
// initialize dragging a selection // initialize dragging a selection
singleton.mousedown = true singleton.mousedown = true
singleton.selectionAnchor = path singleton.selectionAnchor = path
@ -228,17 +251,18 @@
anchorPath: singleton.selectionAnchor, anchorPath: singleton.selectionAnchor,
focusPath: singleton.selectionFocus focusPath: singleton.selectionFocus
}) })
event.stopPropagation()
} }
event.stopPropagation()
event.preventDefault()
// we attache the mouse up event listener to the global document, // we attache the mouse up event listener to the global document,
// so we will not miss if the mouse up is happening outside of the editor // so we will not miss if the mouse up is happening outside of the editor
document.addEventListener('mouseup', handleMouseUp) document.addEventListener('mouseup', handleMouseUp)
} }
function handleMouseMove (event) { function handleMouseMove (event) {
if (singleton.mousedown) { if (singleton.mousedown) { // TODO: Remove the need for this, only create mousemove handle when mouse is down
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@ -314,10 +338,10 @@
on:mousemove={handleMouseMove} on:mousemove={handleMouseMove}
> >
<div <div
data-type="before-node-selector"
class="before-node-selector" class="before-node-selector"
class:selected={selectedBefore} class:selected={selectedBefore}
style={indentationStyle} style={indentationStyle}
on:click={handleSelectBefore}
> >
<div class="selector"></div> <div class="selector"></div>
</div> </div>
@ -372,10 +396,10 @@
/> />
{/each} {/each}
<div <div
data-type="append-node-selector"
class="append-node-selector" class="append-node-selector"
class:selected={selectedAppend} class:selected={selectedAppend}
style={indentationStyle} style={indentationStyle}
on:click={handleSelectAfter}
> >
<div class="selector"></div> <div class="selector"></div>
</div> </div>
@ -440,10 +464,10 @@
/> />
{/each} {/each}
<div <div
data-type="append-node-selector"
class="append-node-selector" class="append-node-selector"
class:selected={selectedAppend} class:selected={selectedAppend}
style={indentationStyle} style={indentationStyle}
on:click={handleSelectAfter}
> >
<div class="selector"></div> <div class="selector"></div>
</div> </div>

View File

@ -21,6 +21,7 @@ $highlight-active-hover-color: #f3cd00;
$warning-color: #FBB917; $warning-color: #FBB917;
$error-background-color: #ffef8b; $error-background-color: #ffef8b;
$error-border-color: #ffd700; $error-border-color: #ffd700;
$dark-gray: #656565;
$gray: #9d9d9d; $gray: #9d9d9d;
$gray-icon: $gray; $gray-icon: $gray;
$light-gray: #c0c0c0; $light-gray: #c0c0c0;

View File

@ -181,16 +181,44 @@ export function traverseInnerText (element, buffer) {
// test whether a DOM element is a child of a button // test whether a DOM element is a child of a button
export function isChildOfButton (element) { export function isChildOfButton (element) {
let e = element return isChildOf(element, e => e.nodeName === 'BUTTON')
while (e && e.nodeName !== 'BUTTON') {
e = e.parentNode
}
return e && e.nodeName === 'BUTTON'
} }
// test whether a DOM element is a content editable div // test whether a DOM element is a content editable div
export function isContentEditableDiv (element) { 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) {
return typeof element.getAttribute === 'function' && element.getAttribute(name) === value
}
/**
* Test if the element or one of it's parents has a certain predicate
* Can be use for example to check whether the element or it's parent has
* a specific attribute or nodeName.
* @param {HTMLElement} element
* @param {function (element: HTMLElement) : boolean} predicate
* @returns {*}
*/
export function isChildOf (element, predicate) {
let e = element
while (e && !predicate(e)) {
e = e.parentNode
}
return e && predicate(e)
}