Some refactoring

This commit is contained in:
jos 2017-07-19 14:31:26 +02:00
parent c5ce6525a5
commit a03d962daa
5 changed files with 72 additions and 130 deletions

View File

@ -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
}
} }
/** /**

View File

@ -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()
} }
} }

View File

@ -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()
} }
} }

View File

@ -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

View File

@ -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