Implemented top/bottom positioning of ActionMenu
This commit is contained in:
parent
ccf89162b7
commit
d73b79cb4e
|
@ -6,22 +6,46 @@ import FloatingMenu from './menu/FloatingMenu'
|
||||||
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
||||||
import { getInnerText, insideRect } from '../utils/domUtils'
|
import { getInnerText, insideRect } from '../utils/domUtils'
|
||||||
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
||||||
import { compileJSONPointer, META, SELECTED, SELECTED_END, SELECTED_AFTER, SELECTED_BEFORE } from '../eson'
|
import {
|
||||||
|
compileJSONPointer,
|
||||||
|
META,
|
||||||
|
SELECTED, SELECTED_START, SELECTED_END, SELECTED_AFTER, SELECTED_BEFORE, SELECTED_FIRST, SELECTED_LAST
|
||||||
|
} from '../eson'
|
||||||
|
|
||||||
// TODO: rename SELECTED, SELECTED_END, etc to AREA_*? It's used for both selection and hovering
|
const MENU_ITEMS_OBJECT = [
|
||||||
const SELECTED_CLASS_NAMES = {
|
{type: 'sort'},
|
||||||
[SELECTED]: ' jsoneditor-selected',
|
{type: 'duplicate'},
|
||||||
[SELECTED_END]: ' jsoneditor-selected jsoneditor-selected-end',
|
{type: 'cut'},
|
||||||
[SELECTED_AFTER]: ' jsoneditor-selected jsoneditor-selected-insert-area',
|
{type: 'copy'},
|
||||||
[SELECTED_BEFORE]: ' jsoneditor-selected jsoneditor-selected-insert-area',
|
{type: 'paste'},
|
||||||
}
|
{type: 'remove'}
|
||||||
|
]
|
||||||
|
|
||||||
const HOVERED_CLASS_NAMES = {
|
const MENU_ITEMS_ARRAY = [
|
||||||
[SELECTED]: ' jsoneditor-hover',
|
{type: 'sort'},
|
||||||
[SELECTED_END]: ' jsoneditor-hover jsoneditor-hover-end',
|
{type: 'duplicate'},
|
||||||
[SELECTED_AFTER]: ' jsoneditor-hover jsoneditor-hover-insert-area',
|
{type: 'cut'},
|
||||||
[SELECTED_BEFORE]: ' jsoneditor-hover jsoneditor-hover-insert-area',
|
{type: 'copy'},
|
||||||
}
|
{type: 'paste'},
|
||||||
|
{type: 'remove'}
|
||||||
|
]
|
||||||
|
|
||||||
|
const MENU_ITEMS_VALUE = [
|
||||||
|
// {text: 'String', onClick: this.props.emit('changeType', {type: 'checkbox', checked: false}}),
|
||||||
|
{type: 'duplicate'},
|
||||||
|
{type: 'cut'},
|
||||||
|
{type: 'copy'},
|
||||||
|
{type: 'paste'},
|
||||||
|
{type: 'remove'}
|
||||||
|
]
|
||||||
|
|
||||||
|
const MENU_ITEMS_INSERT_BEFORE = [
|
||||||
|
{type: 'insertStructure'},
|
||||||
|
{type: 'insertValue'},
|
||||||
|
{type: 'insertObject'},
|
||||||
|
{type: 'insertArray'},
|
||||||
|
{type: 'paste'},
|
||||||
|
]
|
||||||
|
|
||||||
export default class JSONNode extends PureComponent {
|
export default class JSONNode extends PureComponent {
|
||||||
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
||||||
|
@ -46,7 +70,7 @@ export default class JSONNode extends PureComponent {
|
||||||
state = {
|
state = {
|
||||||
menu: null, // can contain object {anchor, root}
|
menu: null, // can contain object {anchor, root}
|
||||||
appendMenu: null, // can contain object {anchor, root}
|
appendMenu: null, // can contain object {anchor, root}
|
||||||
hover: false
|
hover: null
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -104,17 +128,7 @@ export default class JSONNode extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const floatingMenu = (meta.selected === SELECTED_END)
|
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_OBJECT, meta.selected)
|
||||||
? this.renderFloatingMenu([
|
|
||||||
{type: 'sort'},
|
|
||||||
{type: 'duplicate'},
|
|
||||||
{type: 'cut'},
|
|
||||||
{type: 'copy'},
|
|
||||||
{type: 'paste'},
|
|
||||||
{type: 'remove'}
|
|
||||||
])
|
|
||||||
: null
|
|
||||||
|
|
||||||
const insertArea = this.renderInsertBeforeArea()
|
const insertArea = this.renderInsertBeforeArea()
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
|
@ -159,17 +173,7 @@ export default class JSONNode extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const floatingMenu = (meta.selected === SELECTED_END)
|
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_ARRAY, meta.selected)
|
||||||
? this.renderFloatingMenu([
|
|
||||||
{type: 'sort'},
|
|
||||||
{type: 'duplicate'},
|
|
||||||
{type: 'cut'},
|
|
||||||
{type: 'copy'},
|
|
||||||
{type: 'paste'},
|
|
||||||
{type: 'remove'}
|
|
||||||
])
|
|
||||||
: null
|
|
||||||
|
|
||||||
const insertArea = this.renderInsertBeforeArea()
|
const insertArea = this.renderInsertBeforeArea()
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
|
@ -194,16 +198,7 @@ export default class JSONNode extends PureComponent {
|
||||||
this.renderError(meta.error)
|
this.renderError(meta.error)
|
||||||
])
|
])
|
||||||
|
|
||||||
const floatingMenu = (meta.selected === SELECTED_END)
|
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_VALUE, meta.selected)
|
||||||
? this.renderFloatingMenu([
|
|
||||||
// {text: 'String', onClick: this.props.emit('changeType', {type: 'checkbox', checked: false}}),
|
|
||||||
{type: 'duplicate'},
|
|
||||||
{type: 'cut'},
|
|
||||||
{type: 'copy'},
|
|
||||||
{type: 'paste'},
|
|
||||||
{type: 'remove'}
|
|
||||||
])
|
|
||||||
: null
|
|
||||||
|
|
||||||
const insertArea = this.renderInsertBeforeArea()
|
const insertArea = this.renderInsertBeforeArea()
|
||||||
|
|
||||||
|
@ -216,14 +211,9 @@ export default class JSONNode extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInsertBeforeArea () {
|
renderInsertBeforeArea () {
|
||||||
const floatingMenu = (this.props.value[META].selected === SELECTED_BEFORE)
|
const floatingMenu = ((this.props.value[META].selected & SELECTED_BEFORE) !== 0)
|
||||||
? this.renderFloatingMenu([
|
? this.renderFloatingMenu(MENU_ITEMS_INSERT_BEFORE,
|
||||||
{type: 'insertStructure'},
|
SELECTED + SELECTED_END + SELECTED_FIRST)
|
||||||
{type: 'insertValue'},
|
|
||||||
{type: 'insertObject'},
|
|
||||||
{type: 'insertArray'},
|
|
||||||
{type: 'paste'},
|
|
||||||
])
|
|
||||||
: null
|
: null
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
|
@ -356,9 +346,23 @@ export default class JSONNode extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getContainerClassName (selected, hover) {
|
getContainerClassName (selected, hover) {
|
||||||
return 'jsoneditor-node-container' +
|
let classNames = ['jsoneditor-node-container']
|
||||||
(hover ? (HOVERED_CLASS_NAMES[hover]) : '') +
|
|
||||||
(selected ? (SELECTED_CLASS_NAMES[selected]) : '')
|
if ((selected & SELECTED) !== 0) { classNames.push('jsoneditor-selected') }
|
||||||
|
if ((selected & SELECTED_START) !== 0) { classNames.push('jsoneditor-selected-start') }
|
||||||
|
if ((selected & SELECTED_END) !== 0) { classNames.push('jsoneditor-selected-end') }
|
||||||
|
if ((selected & SELECTED_FIRST) !== 0) { classNames.push('jsoneditor-selected-first') }
|
||||||
|
if ((selected & SELECTED_LAST) !== 0) { classNames.push('jsoneditor-selected-last') }
|
||||||
|
if ((selected & SELECTED_BEFORE) !== 0) { classNames.push('jsoneditor-selected-insert-area-before') }
|
||||||
|
if ((selected & SELECTED_AFTER) !== 0) { classNames.push('jsoneditor-selected-insert-area-after') }
|
||||||
|
|
||||||
|
if ((hover & SELECTED) !== 0) { classNames.push('jsoneditor-hover') }
|
||||||
|
if ((hover & SELECTED_START) !== 0) { classNames.push('jsoneditor-hover-start') }
|
||||||
|
if ((hover & SELECTED_END) !== 0) { classNames.push('jsoneditor-hover-end') }
|
||||||
|
if ((hover & SELECTED_BEFORE) !== 0) { classNames.push('jsoneditor-hover-insert-area-before') }
|
||||||
|
if ((hover & SELECTED_AFTER) !== 0) { classNames.push('jsoneditor-hover-insert-area-after') }
|
||||||
|
|
||||||
|
return classNames.join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -473,12 +477,20 @@ export default class JSONNode extends PureComponent {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFloatingMenu (items) {
|
renderFloatingMenu (items, selected) {
|
||||||
|
if ((selected & SELECTED_END) === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLastOfMultiple = ((selected & SELECTED_LAST) !== 0) &&
|
||||||
|
((selected & SELECTED_FIRST) === 0)
|
||||||
|
|
||||||
return h(FloatingMenu, {
|
return h(FloatingMenu, {
|
||||||
key: 'floating-menu',
|
key: 'floating-menu',
|
||||||
path: this.props.value[META].path,
|
path: this.props.value[META].path,
|
||||||
emit: this.props.emit,
|
emit: this.props.emit,
|
||||||
items
|
items,
|
||||||
|
position: isLastOfMultiple ? 'bottom' : 'top'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +499,7 @@ export default class JSONNode extends PureComponent {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|
||||||
const hover = (event.target.className.indexOf('jsoneditor-insert-area') !== -1)
|
const hover = (event.target.className.indexOf('jsoneditor-insert-area') !== -1)
|
||||||
? SELECTED_AFTER
|
? (SELECTED + SELECTED_AFTER)
|
||||||
: SELECTED
|
: SELECTED
|
||||||
|
|
||||||
if (hoveredNode && hoveredNode !== this) {
|
if (hoveredNode && hoveredNode !== this) {
|
||||||
|
@ -505,7 +517,7 @@ export default class JSONNode extends PureComponent {
|
||||||
handleMouseLeave = (event) => {
|
handleMouseLeave = (event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
// FIXME: this gives issues when the hovered node doesn't exist anymore. check whether mounted?
|
// FIXME: this gives issues when the hovered node doesn't exist anymore. check whether mounted?
|
||||||
hoveredNode.setState({hover: false})
|
hoveredNode.setState({hover: null})
|
||||||
|
|
||||||
this.setState({hover: null})
|
this.setState({hover: null})
|
||||||
}
|
}
|
||||||
|
|
|
@ -529,35 +529,35 @@ div.jsoneditor-node-container {
|
||||||
background-color: #ffed99; }
|
background-color: #ffed99; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover {
|
||||||
background-color: #ffdb80; }
|
background-color: #ffdb80; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after {
|
||||||
background-color: #ffed99; }
|
background-color: #ffed99; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
|
||||||
border: 1px dashed gray;
|
border: 1px dashed gray;
|
||||||
background-color: #f2f2f2; }
|
background-color: #f2f2f2; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area.jsoneditor-selected-insert-area > div.jsoneditor-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after.jsoneditor-selected-insert-area-before > div.jsoneditor-insert-area {
|
||||||
border: 1px dashed #f4af41;
|
border: 1px dashed #f4af41;
|
||||||
background-color: #ffdb80; }
|
background-color: #ffdb80; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before {
|
||||||
background-color: inherit; }
|
background-color: inherit; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area.jsoneditor-hover {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before.jsoneditor-hover {
|
||||||
background-color: #f2f2f2; }
|
background-color: #f2f2f2; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area.jsoneditor-hover.jsoneditor-hover-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before.jsoneditor-hover.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit; }
|
background-color: inherit; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area > div.jsoneditor-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before > div.jsoneditor-insert-area {
|
||||||
border: 1px dashed #f4af41;
|
border: 1px dashed #f4af41;
|
||||||
background: #ffed99; }
|
background: #ffed99; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover {
|
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover {
|
||||||
background-color: #ffdb80; }
|
background-color: #ffdb80; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit; }
|
background-color: inherit; }
|
||||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
|
||||||
border: 1px dashed #f4af41;
|
border: 1px dashed #f4af41;
|
||||||
background: #ffdb80; }
|
background: #ffdb80; }
|
||||||
div.jsoneditor-node-container.jsoneditor-hover {
|
div.jsoneditor-node-container.jsoneditor-hover {
|
||||||
background-color: #f2f2f2; }
|
background-color: #f2f2f2; }
|
||||||
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area {
|
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit; }
|
background-color: inherit; }
|
||||||
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
|
||||||
border: 1px dashed gray;
|
border: 1px dashed gray;
|
||||||
background-color: #f2f2f2; }
|
background-color: #f2f2f2; }
|
||||||
div.jsoneditor-node-container div.jsoneditor-insert-area {
|
div.jsoneditor-node-container div.jsoneditor-insert-area {
|
||||||
|
@ -587,8 +587,17 @@ div.jsoneditor-node-container {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: solid 10px #4d4d4d;
|
border-top: solid 10px #4d4d4d;
|
||||||
|
border-bottom: none;
|
||||||
border-left: solid 10px transparent;
|
border-left: solid 10px transparent;
|
||||||
border-right: solid 10px transparent; }
|
border-right: solid 10px transparent; }
|
||||||
|
div.jsoneditor-node-container div.jsoneditor-floating-menu.jsoneditor-floating-menu-bottom {
|
||||||
|
bottom: auto;
|
||||||
|
top: 100%; }
|
||||||
|
div.jsoneditor-node-container div.jsoneditor-floating-menu.jsoneditor-floating-menu-bottom:after {
|
||||||
|
top: -10px;
|
||||||
|
margin-left: -10px;
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: solid 10px #4d4d4d; }
|
||||||
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item {
|
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #4d4d4d;
|
background: #4d4d4d;
|
||||||
|
|
|
@ -575,7 +575,7 @@ div.jsoneditor-node-container {
|
||||||
&.jsoneditor-hover {
|
&.jsoneditor-hover {
|
||||||
background-color: $hoverAndSelectedColor;
|
background-color: $hoverAndSelectedColor;
|
||||||
|
|
||||||
&.jsoneditor-hover-insert-area {
|
&.jsoneditor-hover-insert-area-after {
|
||||||
background-color: $selectedColor;
|
background-color: $selectedColor;
|
||||||
|
|
||||||
> div.jsoneditor-insert-area {
|
> div.jsoneditor-insert-area {
|
||||||
|
@ -583,7 +583,7 @@ div.jsoneditor-node-container {
|
||||||
background-color: $hoverColor;
|
background-color: $hoverColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.jsoneditor-selected-insert-area {
|
&.jsoneditor-selected-insert-area-before {
|
||||||
> div.jsoneditor-insert-area {
|
> div.jsoneditor-insert-area {
|
||||||
border: 1px dashed #f4af41;
|
border: 1px dashed #f4af41;
|
||||||
background-color: $hoverAndSelectedColor;
|
background-color: $hoverAndSelectedColor;
|
||||||
|
@ -592,13 +592,13 @@ div.jsoneditor-node-container {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.jsoneditor-selected-insert-area {
|
&.jsoneditor-selected-insert-area-before {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
|
||||||
&.jsoneditor-hover {
|
&.jsoneditor-hover {
|
||||||
background-color: $hoverColor;
|
background-color: $hoverColor;
|
||||||
|
|
||||||
&.jsoneditor-hover-insert-area {
|
&.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,7 +613,7 @@ div.jsoneditor-node-container {
|
||||||
div.jsoneditor-hover {
|
div.jsoneditor-hover {
|
||||||
background-color: $hoverAndSelectedColor;
|
background-color: $hoverAndSelectedColor;
|
||||||
|
|
||||||
&.jsoneditor-hover-insert-area {
|
&.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
|
||||||
> div.jsoneditor-insert-area {
|
> div.jsoneditor-insert-area {
|
||||||
|
@ -627,7 +627,7 @@ div.jsoneditor-node-container {
|
||||||
&.jsoneditor-hover {
|
&.jsoneditor-hover {
|
||||||
background-color: $hoverColor;
|
background-color: $hoverColor;
|
||||||
|
|
||||||
&.jsoneditor-hover-insert-area {
|
&.jsoneditor-hover-insert-area-after {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
|
||||||
> div.jsoneditor-insert-area {
|
> div.jsoneditor-insert-area {
|
||||||
|
@ -662,16 +662,29 @@ div.jsoneditor-node-container {
|
||||||
box-shadow: 0 2px 6px 0 rgba(0,0,0,.24);
|
box-shadow: 0 2px 6px 0 rgba(0,0,0,.24);
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content:'';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: 35px;
|
left: 35px;
|
||||||
|
margin-left: -10px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: solid 10px $floating-menu-background;
|
||||||
|
border-bottom: none;
|
||||||
|
border-left: solid 10px transparent;
|
||||||
|
border-right: solid 10px transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.jsoneditor-floating-menu-bottom {
|
||||||
|
bottom: auto;
|
||||||
|
top: 100%;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
top: -10px;
|
||||||
margin-left: -10px;
|
margin-left: -10px;
|
||||||
width: 0;
|
border-top: none;
|
||||||
height: 0;
|
border-bottom: solid 10px $floating-menu-background;
|
||||||
border-top: solid 10px $floating-menu-background;
|
}
|
||||||
border-left: solid 10px transparent;
|
|
||||||
border-right: solid 10px transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-floating-menu-item {
|
button.jsoneditor-floating-menu-item {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { createElement as h, PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
const MENU_CLASS_NAME = 'jsoneditor-floating-menu'
|
const MENU_CLASS_NAME = 'jsoneditor-floating-menu'
|
||||||
|
const MENU_CLASS_NAME_BOTTOM = 'jsoneditor-floating-menu-bottom'
|
||||||
const MENU_ITEM_CLASS_NAME = 'jsoneditor-floating-menu-item'
|
const MENU_ITEM_CLASS_NAME = 'jsoneditor-floating-menu-item'
|
||||||
|
|
||||||
// Array: Sort | Map | Filter | Duplicate | Cut | Copy | Paste | Remove
|
// Array: Sort | Map | Filter | Duplicate | Cut | Copy | Paste | Remove
|
||||||
|
@ -134,7 +135,10 @@ export default class FloatingMenu extends PureComponent {
|
||||||
type: PropTypes.string.isRequired
|
type: PropTypes.string.isRequired
|
||||||
})
|
})
|
||||||
]).isRequired
|
]).isRequired
|
||||||
).isRequired
|
).isRequired,
|
||||||
|
path: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
|
emit: PropTypes.func.isRequired,
|
||||||
|
position: PropTypes.string // 'top' or 'bottom'
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
@ -150,7 +154,8 @@ export default class FloatingMenu extends PureComponent {
|
||||||
})
|
})
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
className: MENU_CLASS_NAME,
|
className: MENU_CLASS_NAME +
|
||||||
|
(this.props.position === 'bottom' ? (' ' + MENU_CLASS_NAME_BOTTOM) : ''),
|
||||||
onMouseDown: this.handleTouchStart,
|
onMouseDown: this.handleTouchStart,
|
||||||
onTouchStart: this.handleTouchStart,
|
onTouchStart: this.handleTouchStart,
|
||||||
}, items)
|
}, items)
|
||||||
|
|
|
@ -13,9 +13,12 @@ import initial from 'lodash/initial'
|
||||||
import last from 'lodash/last'
|
import last from 'lodash/last'
|
||||||
|
|
||||||
export const SELECTED = 1
|
export const SELECTED = 1
|
||||||
export const SELECTED_END = 2
|
export const SELECTED_START = 2
|
||||||
export const SELECTED_BEFORE = 3
|
export const SELECTED_END = 4
|
||||||
export const SELECTED_AFTER = 4
|
export const SELECTED_FIRST = 8
|
||||||
|
export const SELECTED_LAST = 16
|
||||||
|
export const SELECTED_BEFORE = 32
|
||||||
|
export const SELECTED_AFTER = 64
|
||||||
|
|
||||||
export const META = Symbol('meta')
|
export const META = Symbol('meta')
|
||||||
|
|
||||||
|
@ -349,7 +352,7 @@ function setSearchStatus (eson, esonPointer, searchStatus) {
|
||||||
/**
|
/**
|
||||||
* Merge selection status into the eson object, cleanup previous selection
|
* Merge selection status into the eson object, cleanup previous selection
|
||||||
* @param {ESON} eson
|
* @param {ESON} eson
|
||||||
* @param {Selection} [selection]
|
* @param {Selection | null} selection
|
||||||
* @return {ESON} Returns updated eson object
|
* @return {ESON} Returns updated eson object
|
||||||
*/
|
*/
|
||||||
export function applySelection (eson, selection) {
|
export function applySelection (eson, selection) {
|
||||||
|
@ -357,11 +360,13 @@ export function applySelection (eson, selection) {
|
||||||
return cleanupMetaData(eson, 'selected')
|
return cleanupMetaData(eson, 'selected')
|
||||||
}
|
}
|
||||||
else if (selection.before) {
|
else if (selection.before) {
|
||||||
const updatedEson = setIn(eson, selection.before.concat([META, 'selected']), SELECTED_BEFORE)
|
const updatedEson = setIn(eson, selection.before.concat([META, 'selected']),
|
||||||
|
SELECTED + SELECTED_BEFORE)
|
||||||
return cleanupMetaData(updatedEson, 'selected', [selection.before])
|
return cleanupMetaData(updatedEson, 'selected', [selection.before])
|
||||||
}
|
}
|
||||||
else if (selection.after) {
|
else if (selection.after) {
|
||||||
const updatedEson = setIn(eson, selection.after.concat([META, 'selected']), SELECTED_AFTER)
|
const updatedEson = setIn(eson, selection.after.concat([META, 'selected']),
|
||||||
|
SELECTED + SELECTED_AFTER)
|
||||||
return cleanupMetaData(updatedEson, 'selected', [selection.after])
|
return cleanupMetaData(updatedEson, 'selected', [selection.after])
|
||||||
}
|
}
|
||||||
else { // selection.start and selection.end
|
else { // selection.start and selection.end
|
||||||
|
@ -379,15 +384,21 @@ export function applySelection (eson, selection) {
|
||||||
const startIndex = root[META].props.indexOf(start)
|
const startIndex = root[META].props.indexOf(start)
|
||||||
const endIndex = root[META].props.indexOf(end)
|
const endIndex = root[META].props.indexOf(end)
|
||||||
|
|
||||||
const minIndex = Math.min(startIndex, endIndex)
|
const firstIndex = Math.min(startIndex, endIndex)
|
||||||
const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
|
const lastIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
|
||||||
|
const firstProp = root[META].props[firstIndex]
|
||||||
|
const lastProp = root[META].props[lastIndex - 1]
|
||||||
|
|
||||||
const selectedProps = root[META].props.slice(minIndex, maxIndex)
|
const selectedProps = root[META].props.slice(firstIndex, lastIndex)
|
||||||
selectedPaths = selectedProps.map(prop => rootPath.concat(prop))
|
selectedPaths = selectedProps.map(prop => rootPath.concat(prop))
|
||||||
let updatedObj = cloneWithSymbols(root)
|
let updatedObj = cloneWithSymbols(root)
|
||||||
selectedProps.forEach(prop => {
|
selectedProps.forEach(prop => {
|
||||||
updatedObj[prop] = setIn(updatedObj[prop], [META, 'selected'],
|
const selected = SELECTED +
|
||||||
prop === end ? SELECTED_END : SELECTED)
|
(prop === start ? SELECTED_START : 0) +
|
||||||
|
(prop === end ? SELECTED_END : 0) +
|
||||||
|
(prop === firstProp ? SELECTED_FIRST : 0) +
|
||||||
|
(prop === lastProp ? SELECTED_LAST : 0)
|
||||||
|
updatedObj[prop] = setIn(updatedObj[prop], [META, 'selected'], selected)
|
||||||
})
|
})
|
||||||
|
|
||||||
return updatedObj
|
return updatedObj
|
||||||
|
@ -396,17 +407,21 @@ export function applySelection (eson, selection) {
|
||||||
const startIndex = parseInt(start, 10)
|
const startIndex = parseInt(start, 10)
|
||||||
const endIndex = parseInt(end, 10)
|
const endIndex = parseInt(end, 10)
|
||||||
|
|
||||||
const minIndex = Math.min(startIndex, endIndex)
|
const firstIndex = Math.min(startIndex, endIndex)
|
||||||
const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
|
const lastIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
|
||||||
|
|
||||||
const selectedIndices = range(minIndex, maxIndex)
|
const selectedIndices = range(firstIndex, lastIndex)
|
||||||
selectedPaths = selectedIndices.map(index => rootPath.concat(String(index)))
|
selectedPaths = selectedIndices.map(index => rootPath.concat(String(index)))
|
||||||
|
|
||||||
let updatedArr = root.slice()
|
let updatedArr = root.slice()
|
||||||
updatedArr = cloneWithSymbols(root)
|
updatedArr = cloneWithSymbols(root)
|
||||||
selectedIndices.forEach(index => {
|
selectedIndices.forEach(index => {
|
||||||
updatedArr[index] = setIn(updatedArr[index], [META, 'selected'],
|
const selected = SELECTED +
|
||||||
index === endIndex ? SELECTED_END : SELECTED)
|
(index === start ? SELECTED_START : 0) +
|
||||||
|
(index === end ? SELECTED_END : 0) +
|
||||||
|
(index === firstIndex ? SELECTED_FIRST : 0) +
|
||||||
|
(index === lastIndex ? SELECTED_LAST : 0)
|
||||||
|
updatedArr[index] = setIn(updatedArr[index], [META, 'selected'], selected)
|
||||||
})
|
})
|
||||||
|
|
||||||
return updatedArr
|
return updatedArr
|
||||||
|
|
Loading…
Reference in New Issue