Some refactoring
This commit is contained in:
parent
c5ce6525a5
commit
a03d962daa
|
@ -4,7 +4,7 @@ import { createElement as h, Component } from 'react'
|
||||||
|
|
||||||
import ActionMenu from './menu/ActionMenu'
|
import ActionMenu from './menu/ActionMenu'
|
||||||
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
||||||
import { getInnerText, insideRect, findParentNode } from '../utils/domUtils'
|
import { getInnerText, insideRect, findParentWithAttribute } from '../utils/domUtils'
|
||||||
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
||||||
import { compileJSONPointer } from '../jsonData'
|
import { compileJSONPointer } from '../jsonData'
|
||||||
|
|
||||||
|
@ -417,7 +417,7 @@ export default class JSONNode extends Component {
|
||||||
|
|
||||||
handleOpenActionMenu = (event) => {
|
handleOpenActionMenu = (event) => {
|
||||||
// TODO: don't use refs, find root purely via DOM?
|
// TODO: don't use refs, find root purely via DOM?
|
||||||
const root = findParentNode(this.refs.actionMenuButton, 'data-jsoneditor', 'true')
|
const root = findParentWithAttribute(this.refs.actionMenuButton, 'data-jsoneditor', 'true')
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
menu: {
|
menu: {
|
||||||
|
@ -434,7 +434,7 @@ export default class JSONNode extends Component {
|
||||||
|
|
||||||
handleOpenAppendActionMenu = (event) => {
|
handleOpenAppendActionMenu = (event) => {
|
||||||
// TODO: don't use refs, find root purely via DOM?
|
// TODO: don't use refs, find root purely via DOM?
|
||||||
const root = findParentNode(this.refs.appendActionMenuButton, 'data-jsoneditor', 'true')
|
const root = findParentWithAttribute(this.refs.appendActionMenuButton, 'data-jsoneditor', 'true')
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
appendMenu: {
|
appendMenu: {
|
||||||
|
@ -594,32 +594,6 @@ export default class JSONNode extends Component {
|
||||||
? stringValue
|
? stringValue
|
||||||
: stringConvert(stringValue)
|
: stringConvert(stringValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the root DOM element of the JSONEditor
|
|
||||||
* Search is done based on the CSS class 'jsoneditor'
|
|
||||||
* @param event
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
// TODO: make redundant and cleanup
|
|
||||||
static findRootElement (event) {
|
|
||||||
function isEditorElement (elem) {
|
|
||||||
// FIXME: this is a bit tricky. can we use a special attribute or something?
|
|
||||||
return elem.className.split(' ').indexOf('jsoneditor') !== -1
|
|
||||||
}
|
|
||||||
|
|
||||||
let elem = event.target
|
|
||||||
while (elem) {
|
|
||||||
if (isEditorElement(elem)) {
|
|
||||||
return elem
|
|
||||||
}
|
|
||||||
|
|
||||||
elem = elem.parentNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { createElement as h, Component } from 'react'
|
import { createElement as h, Component } from 'react'
|
||||||
import { findParentNode } from '../../utils/domUtils'
|
import { findParentWithAttribute } from '../../utils/domUtils'
|
||||||
|
|
||||||
export let CONTEXT_MENU_HEIGHT = 240
|
export let CONTEXT_MENU_HEIGHT = 240
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ export default class Menu extends Component {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.handleRequestClose) {
|
if (!this.handleRequestClose) {
|
||||||
this.handleRequestClose = (event) => {
|
this.handleRequestClose = (event) => {
|
||||||
if (!findParentNode(event.target, 'data-menu', 'true')) {
|
if (!findParentWithAttribute(event.target, 'data-menu', 'true')) {
|
||||||
this.props.onRequestClose()
|
this.props.onRequestClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import { createElement as h, Component } from 'react'
|
import { createElement as h, Component } from 'react'
|
||||||
import { toCapital } from '../../utils/stringUtils'
|
import { toCapital } from '../../utils/stringUtils'
|
||||||
import { findParentNode } from '../../utils/domUtils'
|
import { findParentWithAttribute } from '../../utils/domUtils'
|
||||||
|
|
||||||
export default class ModeMenu extends Component {
|
export default class ModeMenu extends Component {
|
||||||
/**
|
/**
|
||||||
* @param {{open, modes, mode, onChangeMode, onRequestClose, onError}} props
|
* {{open, modes, mode, onChangeMode, onRequestClose, onError}} props
|
||||||
* @param {Object} state
|
|
||||||
* @return {JSX.Element}
|
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
if (this.props.open) {
|
if (this.props.open) {
|
||||||
|
@ -65,7 +63,7 @@ export default class ModeMenu extends Component {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.handleRequestClose) {
|
if (!this.handleRequestClose) {
|
||||||
this.handleRequestClose = (event) => {
|
this.handleRequestClose = (event) => {
|
||||||
if (!findParentNode(event.target, 'data-menu', 'true')) {
|
if (!findParentWithAttribute(event.target, 'data-menu', 'true')) {
|
||||||
this.props.onRequestClose()
|
this.props.onRequestClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import { selectContentEditable, getSelection as getDOMSelection } from '../../utils/domUtils'
|
import {
|
||||||
|
selectContentEditable, hasClassName,
|
||||||
|
findParentWithAttribute, findParentWithClassName
|
||||||
|
} from '../../utils/domUtils'
|
||||||
import { compileJSONPointer, parseJSONPointer } from '../../jsonData'
|
import { compileJSONPointer, parseJSONPointer } from '../../jsonData'
|
||||||
|
|
||||||
// singleton
|
// singleton
|
||||||
|
@ -172,21 +175,6 @@ export function findNode (container, path) {
|
||||||
return container.querySelector(`div[${PATH_ATTRIBUTE}="${compileJSONPointer(path)}"]`)
|
return container.querySelector(`div[${PATH_ATTRIBUTE}="${compileJSONPointer(path)}"]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fully implement getSelection, or cleanup if not needed
|
|
||||||
// function getSelectedElement () {
|
|
||||||
// const selection = getDOMSelection()
|
|
||||||
// return selection ? selection.startContainer : null
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// export function getSelection () {
|
|
||||||
// const element = getSelectedElement()
|
|
||||||
// const node = findBaseNode(element)
|
|
||||||
//
|
|
||||||
// return {
|
|
||||||
// path: node.getAttribute(PATH_ATTRIBUTE) // TODO: return parsed JSONPointer instead?
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
function findContentsContainer (element) {
|
function findContentsContainer (element) {
|
||||||
return findParentWithClassName (element, CONTENTS_CONTAINER_CLASS_NAME)
|
return findParentWithClassName (element, CONTENTS_CONTAINER_CLASS_NAME)
|
||||||
}
|
}
|
||||||
|
@ -212,49 +200,6 @@ export function searchHasFocus () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the first parent element having a specific class name
|
|
||||||
* @param {Element} element
|
|
||||||
* @param {string} className
|
|
||||||
* @return {Element} Returns the base element of the node
|
|
||||||
*/
|
|
||||||
function findParentWithClassName (element, className) {
|
|
||||||
let e = element
|
|
||||||
do {
|
|
||||||
if (hasClassName(e, className)) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
e = e.parentNode
|
|
||||||
}
|
|
||||||
while (e)
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the base element of a node from one of it's childs
|
|
||||||
* @param {Element} element
|
|
||||||
* @param {string} attribute
|
|
||||||
* @param {string} value
|
|
||||||
* @return {Element} Returns the base element of the node
|
|
||||||
*/
|
|
||||||
function findParentWithAttribute (element, attribute, value) {
|
|
||||||
let e = element
|
|
||||||
do {
|
|
||||||
if (e && e.hasAttribute && e.hasAttribute(attribute)) {
|
|
||||||
if (value === undefined || e.getAttribute(attribute) === value) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e = e.parentNode
|
|
||||||
}
|
|
||||||
while (e)
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function findPreviousNode (element) {
|
function findPreviousNode (element) {
|
||||||
const container = findContentsContainer(element)
|
const container = findContentsContainer(element)
|
||||||
const node = findBaseNode(element)
|
const node = findBaseNode(element)
|
||||||
|
@ -341,18 +286,6 @@ function findInputName (node, name) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether a HTML element contains a specific className
|
|
||||||
* @param {Element} element
|
|
||||||
* @param {boolean} className
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
function hasClassName (element, className) {
|
|
||||||
return element && element.className
|
|
||||||
? element.className.split(' ').indexOf(className) !== -1
|
|
||||||
: false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find the closest input that actually exists in this node
|
* find the closest input that actually exists in this node
|
||||||
* @param {Element} node
|
* @param {Element} node
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
* @return {String} innerText
|
* @return {String} innerText
|
||||||
*/
|
*/
|
||||||
export function getInnerText (element, buffer) {
|
export function getInnerText (element, buffer) {
|
||||||
var first = (buffer == undefined)
|
const first = (buffer === undefined)
|
||||||
if (first) {
|
if (first) {
|
||||||
buffer = {
|
buffer = {
|
||||||
'text': '',
|
'text': '',
|
||||||
'flush': function () {
|
'flush': function () {
|
||||||
var text = this.text
|
const text = this.text
|
||||||
this.text = ''
|
this.text = ''
|
||||||
return text
|
return text
|
||||||
},
|
},
|
||||||
|
@ -27,23 +27,23 @@ export function getInnerText (element, buffer) {
|
||||||
|
|
||||||
// divs or other HTML elements
|
// divs or other HTML elements
|
||||||
if (element.hasChildNodes()) {
|
if (element.hasChildNodes()) {
|
||||||
var childNodes = element.childNodes
|
const childNodes = element.childNodes
|
||||||
var innerText = ''
|
let innerText = ''
|
||||||
|
|
||||||
for (var i = 0, iMax = childNodes.length; i < iMax; i++) {
|
for (let i = 0, iMax = childNodes.length; i < iMax; i++) {
|
||||||
var child = childNodes[i]
|
const child = childNodes[i]
|
||||||
|
|
||||||
if (child.nodeName == 'DIV' || child.nodeName == 'P') {
|
if (child.nodeName === 'DIV' || child.nodeName === 'P') {
|
||||||
var prevChild = childNodes[i - 1]
|
const prevChild = childNodes[i - 1]
|
||||||
var prevName = prevChild ? prevChild.nodeName : undefined
|
const prevName = prevChild ? prevChild.nodeName : undefined
|
||||||
if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') {
|
if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') {
|
||||||
innerText += '\n'
|
innerText += '\n'
|
||||||
buffer.flush()
|
buffer.flush()
|
||||||
}
|
}
|
||||||
innerText += getInnerText(child, buffer)
|
innerText += getInnerText(child, buffer)
|
||||||
buffer.set('\n')
|
buffer.set('\n')
|
||||||
}
|
}
|
||||||
else if (child.nodeName == 'BR') {
|
else if (child.nodeName === 'BR') {
|
||||||
innerText += buffer.flush()
|
innerText += buffer.flush()
|
||||||
buffer.set('\n')
|
buffer.set('\n')
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export function getInnerText (element, buffer) {
|
||||||
return innerText
|
return innerText
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (element.nodeName == 'P' && getInternetExplorerVersion() != -1) {
|
if (element.nodeName === 'P' && getInternetExplorerVersion() !== -1) {
|
||||||
// On Internet Explorer, a <p> with hasChildNodes()==false is
|
// On Internet Explorer, a <p> with hasChildNodes()==false is
|
||||||
// rendered with a new line. Note that a <p> with
|
// rendered with a new line. Note that a <p> with
|
||||||
// hasChildNodes()==true is rendered without a new line
|
// hasChildNodes()==true is rendered without a new line
|
||||||
|
@ -108,24 +108,61 @@ export function selectContentEditable(contentEditableElement) {
|
||||||
* Find the parent node of an element which has an attribute with given value.
|
* Find the parent node of an element which has an attribute with given value.
|
||||||
* Can return the element itself too.
|
* Can return the element itself too.
|
||||||
* @param {Element} elem
|
* @param {Element} elem
|
||||||
* @param {string} attr
|
* @param {string} attribute
|
||||||
* @param {string} value
|
* @param {string} [value]
|
||||||
* @return {Element | null} Returns the parent element when found,
|
* @return {Element | null} Returns the parent element when found,
|
||||||
* or null otherwise
|
* or null otherwise
|
||||||
*/
|
*/
|
||||||
export function findParentNode (elem, attr, value) {
|
export function findParentWithAttribute (elem, attribute, value) {
|
||||||
let parent = elem
|
let parent = elem
|
||||||
|
|
||||||
while (parent && parent.getAttribute) {
|
while (parent && parent.getAttribute) {
|
||||||
if (parent.getAttribute(attr) == value) {
|
const match = (value === undefined)
|
||||||
|
? parent.hasAttribute(attribute)
|
||||||
|
: parent.getAttribute(attribute) === value
|
||||||
|
|
||||||
|
if (match) {
|
||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = parent.parentNode
|
parent = parent.parentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first parent element having a specific class name
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {string} className
|
||||||
|
* @return {Element} Returns the base element of the node
|
||||||
|
*/
|
||||||
|
export function findParentWithClassName (element, className) {
|
||||||
|
let parent = element
|
||||||
|
|
||||||
|
while (parent) {
|
||||||
|
if (hasClassName(parent, className)) {
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.parentNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether a HTML element contains a specific className
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {boolean} className
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function hasClassName (element, className) {
|
||||||
|
return element && element.className
|
||||||
|
? element.className.split(' ').indexOf(className) !== -1
|
||||||
|
: false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the child rect fits completely inside the parent rect.
|
* Test whether the child rect fits completely inside the parent rect.
|
||||||
* @param {ClientRect} parent
|
* @param {ClientRect} parent
|
||||||
|
@ -146,13 +183,13 @@ export function insideRect (parent, child, margin = 0) {
|
||||||
* @return {Number} Internet Explorer version, or -1 in case of an other browser
|
* @return {Number} Internet Explorer version, or -1 in case of an other browser
|
||||||
*/
|
*/
|
||||||
export function getInternetExplorerVersion() {
|
export function getInternetExplorerVersion() {
|
||||||
if (_ieVersion == -1) {
|
if (_ieVersion === -1) {
|
||||||
var rv = -1 // Return value assumes failure.
|
let rv = -1 // Return value assumes failure.
|
||||||
if (navigator.appName == 'Microsoft Internet Explorer')
|
if (navigator.appName === 'Microsoft Internet Explorer')
|
||||||
{
|
{
|
||||||
var ua = navigator.userAgent
|
const ua = navigator.userAgent
|
||||||
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})")
|
const re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})")
|
||||||
if (re.exec(ua) != null) {
|
if (re.exec(ua) !== null) {
|
||||||
rv = parseFloat( RegExp.$1 )
|
rv = parseFloat( RegExp.$1 )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,4 +205,4 @@ export function getInternetExplorerVersion() {
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
var _ieVersion = -1
|
let _ieVersion = -1
|
||||||
|
|
Loading…
Reference in New Issue