Refactored ActionMenu and AppendActionMenu
This commit is contained in:
parent
1bcc6382aa
commit
5fc5e302dc
|
@ -1,7 +1,7 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
|
|
||||||
import ActionMenu from './menu/ActionMenu'
|
import ActionButton from './menu/ActionButton'
|
||||||
import AppendActionMenu from './menu/AppendActionMenu'
|
import AppendActionButton from './menu/AppendActionButton'
|
||||||
import { escapeHTML, unescapeHTML } from './utils/stringUtils'
|
import { escapeHTML, unescapeHTML } from './utils/stringUtils'
|
||||||
import { getInnerText } from './utils/domUtils'
|
import { getInnerText } from './utils/domUtils'
|
||||||
import { stringConvert, valueType, isUrl } from './utils/typeUtils'
|
import { stringConvert, valueType, isUrl } from './utils/typeUtils'
|
||||||
|
@ -34,6 +34,7 @@ export default class JSONNode extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
// TODO: remove state
|
||||||
this.state = {
|
this.state = {
|
||||||
menu: null, // context menu
|
menu: null, // context menu
|
||||||
appendMenu: null, // append context menu (used in placeholder of empty object/array)
|
appendMenu: null, // append context menu (used in placeholder of empty object/array)
|
||||||
|
@ -281,53 +282,19 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderActionMenuButton () {
|
renderActionMenuButton () {
|
||||||
const className = 'jsoneditor-button jsoneditor-contextmenu' +
|
return h(ActionButton, {
|
||||||
(this.state.menu ? ' jsoneditor-visible' : '')
|
|
||||||
|
|
||||||
return h('div', {class: 'jsoneditor-button-container'}, [
|
|
||||||
this.renderActionMenu(),
|
|
||||||
h('button', {class: className, onClick: this.handleContextMenu})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAppendContextMenuButton () {
|
|
||||||
const className = 'jsoneditor-button jsoneditor-contextmenu' +
|
|
||||||
(this.state.appendMenu ? ' jsoneditor-visible' : '')
|
|
||||||
|
|
||||||
return h('div', {class: 'jsoneditor-button-container'}, [
|
|
||||||
this.renderAppendContextMenu(),
|
|
||||||
h('button', {class: className, onClick: this.handleAppendContextMenu})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
renderActionMenu () {
|
|
||||||
if (this.state.menu) {
|
|
||||||
return h(ActionMenu, {
|
|
||||||
anchor: this.state.menu.anchor,
|
|
||||||
root: this.state.menu.root,
|
|
||||||
path: this.getPath(),
|
path: this.getPath(),
|
||||||
type: this.props.data.type,
|
type: this.props.data.type,
|
||||||
events: this.props.events
|
events: this.props.events
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAppendContextMenu () {
|
renderAppendContextMenuButton () {
|
||||||
if (this.state.appendMenu) {
|
return h(AppendActionButton, {
|
||||||
return h(AppendActionMenu, {
|
|
||||||
anchor: this.state.menu.anchor,
|
|
||||||
root: this.state.menu.root,
|
|
||||||
path: this.getPath(),
|
path: this.getPath(),
|
||||||
events: this.props.events
|
events: this.props.events
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
let prop
|
let prop
|
||||||
|
@ -500,7 +467,7 @@ export default class JSONNode extends Component {
|
||||||
* @param event
|
* @param event
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
// TODO: move to TreeMode?
|
// TODO: cleanup
|
||||||
static findRootElement (event) {
|
static findRootElement (event) {
|
||||||
function isEditorElement (elem) {
|
function isEditorElement (elem) {
|
||||||
// FIXME: this is a bit tricky. can we use a special attribute or something?
|
// FIXME: this is a bit tricky. can we use a special attribute or something?
|
||||||
|
|
|
@ -49,7 +49,10 @@ export default class TreeMode extends Component {
|
||||||
|
|
||||||
render (props, state) {
|
render (props, state) {
|
||||||
// TODO: make mode tree dynamic
|
// TODO: make mode tree dynamic
|
||||||
return h('div', {class: 'jsoneditor jsoneditor-mode-tree'}, [
|
return h('div', {
|
||||||
|
class: 'jsoneditor jsoneditor-mode-tree',
|
||||||
|
'data-jsoneditor': 'true'
|
||||||
|
}, [
|
||||||
this.renderMenu(),
|
this.renderMenu(),
|
||||||
|
|
||||||
h('div', {class: 'jsoneditor-contents jsoneditor-tree-contents', onClick: this.handleHideMenus}, [
|
h('div', {class: 'jsoneditor-contents jsoneditor-tree-contents', onClick: this.handleHideMenus}, [
|
||||||
|
|
|
@ -275,21 +275,21 @@ button.jsoneditor-button.jsoneditor-expanded {
|
||||||
background-position: -2px -74px;
|
background-position: -2px -74px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-contextmenu {
|
button.jsoneditor-button.jsoneditor-actionmenu {
|
||||||
background-position: -50px -74px;
|
background-position: -50px -74px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-contextmenu:hover,
|
button.jsoneditor-button.jsoneditor-actionmenu:hover,
|
||||||
button.jsoneditor-button.jsoneditor-contextmenu:focus,
|
button.jsoneditor-button.jsoneditor-actionmenu:focus,
|
||||||
button.jsoneditor-button.jsoneditor-contextmenu.jsoneditor-visible {
|
button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible {
|
||||||
background-position: -50px -50px;
|
background-position: -50px -50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******************************* Context Menu *********************************/
|
/******************************* Action Menu **********************************/
|
||||||
|
|
||||||
div.jsoneditor-contextmenu {
|
div.jsoneditor-actionmenu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
|
@ -301,7 +301,7 @@ div.jsoneditor-contextmenu {
|
||||||
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
|
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.jsoneditor-contextmenu.jsoneditor-contextmenu-top {
|
div.jsoneditor-actionmenu.jsoneditor-actionmenu-top {
|
||||||
top: auto;
|
top: auto;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
}
|
}
|
||||||
|
@ -521,6 +521,7 @@ div.jsoneditor-modes {
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border: none;
|
border: none;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { h, Component } from 'preact'
|
||||||
|
import ActionMenu from './ActionMenu'
|
||||||
|
import { findParentNode } from '../utils/domUtils'
|
||||||
|
|
||||||
|
export default class ActionButton extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super (props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
open: false, // whether the menu is open or not
|
||||||
|
anchor: null,
|
||||||
|
root: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{path, type, events}} props
|
||||||
|
* @param state
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
render (props, state) {
|
||||||
|
const className = 'jsoneditor-button jsoneditor-actionmenu' +
|
||||||
|
(this.state.open ? ' jsoneditor-visible' : '')
|
||||||
|
|
||||||
|
return h('div', {class: 'jsoneditor-button-container'}, [
|
||||||
|
h(ActionMenu, {
|
||||||
|
...props, // path, type, events
|
||||||
|
...state, // open, anchor, root
|
||||||
|
onRequestClose: this.handleRequestClose
|
||||||
|
}),
|
||||||
|
h('button', {class: className, onClick: this.handleOpen})
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpen = (event) => {
|
||||||
|
this.setState({
|
||||||
|
open: true,
|
||||||
|
anchor: event.target,
|
||||||
|
root: findParentNode(event.target, 'data-jsoneditor', 'true')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRequestClose = () => {
|
||||||
|
this.setState({open: false})
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ import {
|
||||||
|
|
||||||
export default class ActionMenu extends Component {
|
export default class ActionMenu extends Component {
|
||||||
/**
|
/**
|
||||||
* @param {{anchor, root, path, type, events}} props
|
* @param {{open, anchor, root, path, type, events, onRequestClose}} props
|
||||||
* @param state
|
* @param state
|
||||||
* @return {JSX.Element}
|
* @return {JSX.Element}
|
||||||
*/
|
*/
|
||||||
|
@ -34,8 +34,7 @@ export default class ActionMenu extends Component {
|
||||||
// TODO: implement a hook to adjust the action menu
|
// TODO: implement a hook to adjust the action menu
|
||||||
|
|
||||||
return h(Menu, {
|
return h(Menu, {
|
||||||
anchor: props.anchor,
|
...props,
|
||||||
root: props.root,
|
|
||||||
items
|
items
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { h, Component } from 'preact'
|
||||||
|
import AppendActionMenu from './AppendActionMenu'
|
||||||
|
import { findParentNode } from '../utils/domUtils'
|
||||||
|
|
||||||
|
export default class AppendActionButton extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super (props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
open: false, // whether the menu is open or not
|
||||||
|
anchor: null,
|
||||||
|
root: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{path, events}} props
|
||||||
|
* @param state
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
render (props, state) {
|
||||||
|
const className = 'jsoneditor-button jsoneditor-actionmenu' +
|
||||||
|
(this.state.open ? ' jsoneditor-visible' : '')
|
||||||
|
|
||||||
|
return h('div', {class: 'jsoneditor-button-container'}, [
|
||||||
|
h(AppendActionMenu, {
|
||||||
|
...props, // path, events
|
||||||
|
...state, // open, anchor, root
|
||||||
|
onRequestClose: this.handleRequestClose
|
||||||
|
}),
|
||||||
|
h('button', {class: className, onClick: this.handleOpen})
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpen = (event) => {
|
||||||
|
this.setState({
|
||||||
|
open: true,
|
||||||
|
anchor: event.target,
|
||||||
|
root: findParentNode(event.target, 'data-jsoneditor', 'true')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRequestClose = () => {
|
||||||
|
this.setState({open: false})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,7 @@ export default class AppendActionMenu extends Component {
|
||||||
// TODO: implement a hook to adjust the action menu
|
// TODO: implement a hook to adjust the action menu
|
||||||
|
|
||||||
return h(Menu, {
|
return h(Menu, {
|
||||||
anchor: props.anchor,
|
...props,
|
||||||
root: props.root,
|
|
||||||
items
|
items
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
114
src/menu/Menu.js
114
src/menu/Menu.js
|
@ -1,4 +1,5 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
|
import { findParentNode } from '../utils/domUtils'
|
||||||
|
|
||||||
export let CONTEXT_MENU_HEIGHT = 240
|
export let CONTEXT_MENU_HEIGHT = 240
|
||||||
|
|
||||||
|
@ -6,6 +7,23 @@ export default class Menu extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
expanded: null, // menu index of expanded menu item
|
||||||
|
expanding: null, // menu index of expanding menu item
|
||||||
|
collapsing: null // menu index of collapsing menu item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{open: boolean, items: Array, anchor, root, onRequestClose: function}} props
|
||||||
|
* @param state
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
render (props, state) {
|
||||||
|
if (!props.open) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// determine orientation
|
// determine orientation
|
||||||
const anchorRect = this.props.anchor.getBoundingClientRect()
|
const anchorRect = this.props.anchor.getBoundingClientRect()
|
||||||
const rootRect = this.props.root.getBoundingClientRect()
|
const rootRect = this.props.root.getBoundingClientRect()
|
||||||
|
@ -14,31 +32,16 @@ export default class Menu extends Component {
|
||||||
? 'top'
|
? 'top'
|
||||||
: 'bottom'
|
: 'bottom'
|
||||||
|
|
||||||
this.state = {
|
|
||||||
orientation,
|
|
||||||
expanded: null, // menu index of expanded menu item
|
|
||||||
expanding: null, // menu index of expanding menu item
|
|
||||||
collapsing: null // menu index of collapsing menu item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {{items: Array}} props
|
|
||||||
* @param state
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
render (props, state) {
|
|
||||||
if (!props.items) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: create a non-visible button to set the focus to the menu
|
// TODO: create a non-visible button to set the focus to the menu
|
||||||
// TODO: implement (customizable) quick keys
|
// TODO: implement (customizable) quick keys
|
||||||
|
|
||||||
const className = 'jsoneditor-contextmenu ' +
|
const className = 'jsoneditor-actionmenu ' +
|
||||||
((this.state.orientation === 'top') ? 'jsoneditor-contextmenu-top' : 'jsoneditor-contextmenu-bottom')
|
((orientation === 'top') ? 'jsoneditor-actionmenu-top' : 'jsoneditor-actionmenu-bottom')
|
||||||
|
|
||||||
return h('div', {class: className},
|
return h('div', {
|
||||||
|
class: className,
|
||||||
|
'data-menu': 'true'
|
||||||
|
},
|
||||||
props.items.map(this.renderMenuItem)
|
props.items.map(this.renderMenuItem)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -49,9 +52,15 @@ export default class Menu extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.click && item.submenu) {
|
if (item.click && item.submenu) {
|
||||||
|
// FIXME: don't create functions in the render function
|
||||||
|
const onClick = (event) => {
|
||||||
|
item.click()
|
||||||
|
this.props.onRequestClose()
|
||||||
|
}
|
||||||
|
|
||||||
// two buttons: direct click and a small button to expand the submenu
|
// two buttons: direct click and a small button to expand the submenu
|
||||||
return h('div', {class: 'jsoneditor-menu-item'}, [
|
return h('div', {class: 'jsoneditor-menu-item'}, [
|
||||||
h('button', {class: 'jsoneditor-menu-button jsoneditor-menu-default ' + item.className, title: item.title, onClick: item.click }, [
|
h('button', {class: 'jsoneditor-menu-button jsoneditor-menu-default ' + item.className, title: item.title, onClick }, [
|
||||||
h('span', {class: 'jsoneditor-icon'}),
|
h('span', {class: 'jsoneditor-icon'}),
|
||||||
h('span', {class: 'jsoneditor-text'}, item.text)
|
h('span', {class: 'jsoneditor-text'}, item.text)
|
||||||
]),
|
]),
|
||||||
|
@ -73,9 +82,15 @@ export default class Menu extends Component {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// FIXME: don't create functions in the render function
|
||||||
|
const onClick = (event) => {
|
||||||
|
item.click()
|
||||||
|
this.props.onRequestClose()
|
||||||
|
}
|
||||||
|
|
||||||
// just a button (no submenu)
|
// just a button (no submenu)
|
||||||
return h('div', {class: 'jsoneditor-menu-item'}, [
|
return h('div', {class: 'jsoneditor-menu-item'}, [
|
||||||
h('button', {class: 'jsoneditor-menu-button ' + item.className, title: item.title, onClick: item.click }, [
|
h('button', {class: 'jsoneditor-menu-button ' + item.className, title: item.title, onClick }, [
|
||||||
h('span', {class: 'jsoneditor-icon'}),
|
h('span', {class: 'jsoneditor-icon'}),
|
||||||
h('span', {class: 'jsoneditor-text'}, item.text)
|
h('span', {class: 'jsoneditor-text'}, item.text)
|
||||||
]),
|
]),
|
||||||
|
@ -92,8 +107,14 @@ export default class Menu extends Component {
|
||||||
const collapsing = this.state.collapsing === index
|
const collapsing = this.state.collapsing === index
|
||||||
|
|
||||||
const contents = submenu.map(item => {
|
const contents = submenu.map(item => {
|
||||||
|
// FIXME: don't create functions in the render function
|
||||||
|
const onClick = () => {
|
||||||
|
item.click()
|
||||||
|
this.props.onRequestClose()
|
||||||
|
}
|
||||||
|
|
||||||
return h('div', {class: 'jsoneditor-menu-item'}, [
|
return h('div', {class: 'jsoneditor-menu-item'}, [
|
||||||
h('button', {class: 'jsoneditor-menu-button ' + item.className, title: item.title, onClick: item.click }, [
|
h('button', {class: 'jsoneditor-menu-button ' + item.className, title: item.title, onClick }, [
|
||||||
h('span', {class: 'jsoneditor-icon'}),
|
h('span', {class: 'jsoneditor-icon'}),
|
||||||
h('span', {class: 'jsoneditor-text'}, item.text)
|
h('span', {class: 'jsoneditor-text'}, item.text)
|
||||||
]),
|
]),
|
||||||
|
@ -128,4 +149,49 @@ export default class Menu extends Component {
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.updateRequestCloseListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate () {
|
||||||
|
this.updateRequestCloseListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this.removeRequestCloseListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRequestCloseListener () {
|
||||||
|
if (this.props.open) {
|
||||||
|
this.addRequestCloseListener()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.removeRequestCloseListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addRequestCloseListener () {
|
||||||
|
if (!this.handleRequestClose) {
|
||||||
|
// Attach event listener on next tick, else the current click to open
|
||||||
|
// the menu will immediately result in requestClose event as well
|
||||||
|
setTimeout(() => {
|
||||||
|
this.handleRequestClose = (event) => {
|
||||||
|
if (!findParentNode(event.target, 'data-menu', 'true')) {
|
||||||
|
this.props.onRequestClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.addEventListener('click', this.handleRequestClose)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRequestCloseListener () {
|
||||||
|
if (this.handleRequestClose) {
|
||||||
|
window.removeEventListener('click', this.handleRequestClose)
|
||||||
|
this.handleRequestClose = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRequestClose = null
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
import { toCapital } from '../utils/stringUtils'
|
import { toCapital } from '../utils/stringUtils'
|
||||||
|
import { findParentNode } from '../utils/domUtils'
|
||||||
|
|
||||||
export default class ModeMenu extends Component {
|
export default class ModeMenu extends Component {
|
||||||
/**
|
/**
|
||||||
* @param {{open, modes, mode, onMode, onError}} props
|
* @param {{open, modes, mode, onMode, onRequestClose, onError}} props
|
||||||
* @param {Obect} state
|
* @param {Object} state
|
||||||
* @return {JSX.Element}
|
* @return {JSX.Element}
|
||||||
*/
|
*/
|
||||||
render (props, state) {
|
render (props, state) {
|
||||||
|
@ -17,7 +18,7 @@ export default class ModeMenu extends Component {
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
try {
|
try {
|
||||||
props.onMode(mode)
|
props.onMode(mode)
|
||||||
this.setState({ open: false })
|
props.onRequestClose()
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
props.onError(err)
|
props.onError(err)
|
||||||
|
@ -27,8 +28,8 @@ export default class ModeMenu extends Component {
|
||||||
})
|
})
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
class: 'jsoneditor-contextmenu jsoneditor-modemenu',
|
class: 'jsoneditor-actionmenu jsoneditor-modemenu',
|
||||||
'isnodemenu': 'true',
|
nodemenu: 'true',
|
||||||
}, items)
|
}, items)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -63,7 +64,7 @@ export default class ModeMenu extends Component {
|
||||||
// the menu will immediately result in requestClose event as well
|
// the menu will immediately result in requestClose event as well
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.handleRequestClose = (event) => {
|
this.handleRequestClose = (event) => {
|
||||||
if (!ModeMenu.inNodeMenu(event.target)) {
|
if (!findParentNode(event.target, 'data-menu', 'true')) {
|
||||||
this.props.onRequestClose()
|
this.props.onRequestClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,24 +80,5 @@ export default class ModeMenu extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether any of the parent nodes of this element is the root of the
|
|
||||||
* NodeMenu (has an attribute isNodeMenu:true)
|
|
||||||
* @param elem
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
static inNodeMenu (elem) {
|
|
||||||
let parent = elem
|
|
||||||
|
|
||||||
while (parent && parent.getAttribute) {
|
|
||||||
if (parent.getAttribute('isnodemenu')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
parent = parent.parentNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRequestClose = null
|
handleRequestClose = null
|
||||||
}
|
}
|
|
@ -69,6 +69,31 @@ export function getInnerText (element, buffer) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the parent node of an element which has an attribute with given value.
|
||||||
|
* Can return the element itself too.
|
||||||
|
* @param {Element} elem
|
||||||
|
* @param {string} attr
|
||||||
|
* @param {string} value
|
||||||
|
* @return {Element | null} Returns the parent element when found,
|
||||||
|
* or null otherwise
|
||||||
|
*/
|
||||||
|
export function findParentNode (elem, attr, value) {
|
||||||
|
let parent = elem
|
||||||
|
|
||||||
|
while (parent && parent.getAttribute) {
|
||||||
|
if (parent.getAttribute(attr) == value) {
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
parent = parent.parentNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the version of Internet Explorer or a -1
|
* Returns the version of Internet Explorer or a -1
|
||||||
* (indicating the use of another browser).
|
* (indicating the use of another browser).
|
||||||
|
|
Loading…
Reference in New Issue