This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.9 KiB
166 lines
4.9 KiB
/** |
|
* Copyright (c) 2015-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
* |
|
* @providesModule getReactData |
|
* @flow |
|
*/ |
|
'use strict'; |
|
|
|
/** |
|
* Convert a react internal instance to a sanitized data object. |
|
* |
|
* This is shamelessly stolen from react-devtools: |
|
* https://github.com/facebook/react-devtools/blob/master/backend/getData.js |
|
*/ |
|
function getData(element: Object): Object { |
|
var children = null; |
|
var props = null; |
|
var state = null; |
|
var context = null; |
|
var updater = null; |
|
var name = null; |
|
var type = null; |
|
var text = null; |
|
var publicInstance = null; |
|
var nodeType = 'Native'; |
|
// If the parent is a native node without rendered children, but with |
|
// multiple string children, then the `element` that gets passed in here is |
|
// a plain value -- a string or number. |
|
if (typeof element !== 'object') { |
|
nodeType = 'Text'; |
|
text = element + ''; |
|
} else if (element._currentElement === null || element._currentElement === false) { |
|
nodeType = 'Empty'; |
|
} else if (element._renderedComponent) { |
|
nodeType = 'NativeWrapper'; |
|
children = [element._renderedComponent]; |
|
props = element._instance.props; |
|
state = element._instance.state; |
|
context = element._instance.context; |
|
if (context && Object.keys(context).length === 0) { |
|
context = null; |
|
} |
|
} else if (element._renderedChildren) { |
|
children = childrenList(element._renderedChildren); |
|
} else if (element._currentElement && element._currentElement.props) { |
|
// This is a native node without rendered children -- meaning the children |
|
// prop is just a string or (in the case of the <option>) a list of |
|
// strings & numbers. |
|
children = element._currentElement.props.children; |
|
} |
|
|
|
if (!props && element._currentElement && element._currentElement.props) { |
|
props = element._currentElement.props; |
|
} |
|
|
|
// != used deliberately here to catch undefined and null |
|
if (element._currentElement != null) { |
|
type = element._currentElement.type; |
|
if (typeof type === 'string') { |
|
name = type; |
|
} else if (element.getName) { |
|
nodeType = 'Composite'; |
|
name = element.getName(); |
|
// 0.14 top-level wrapper |
|
// TODO(jared): The backend should just act as if these don't exist. |
|
if (element._renderedComponent && element._currentElement.props === element._renderedComponent._currentElement) { |
|
nodeType = 'Wrapper'; |
|
} |
|
if (name === null) { |
|
name = 'No display name'; |
|
} |
|
} else if (element._stringText) { |
|
nodeType = 'Text'; |
|
text = element._stringText; |
|
} else { |
|
name = type.displayName || type.name || 'Unknown'; |
|
} |
|
} |
|
|
|
if (element._instance) { |
|
var inst = element._instance; |
|
updater = { |
|
setState: inst.setState && inst.setState.bind(inst), |
|
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst), |
|
setInProps: inst.forceUpdate && setInProps.bind(null, element), |
|
setInState: inst.forceUpdate && setInState.bind(null, inst), |
|
setInContext: inst.forceUpdate && setInContext.bind(null, inst), |
|
}; |
|
publicInstance = inst; |
|
|
|
// TODO: React ART currently falls in this bucket, but this doesn't |
|
// actually make sense and we should clean this up after stabilizing our |
|
// API for backends |
|
if (inst._renderedChildren) { |
|
children = childrenList(inst._renderedChildren); |
|
} |
|
} |
|
|
|
return { |
|
nodeType, |
|
type, |
|
name, |
|
props, |
|
state, |
|
context, |
|
children, |
|
text, |
|
updater, |
|
publicInstance, |
|
}; |
|
} |
|
|
|
function setInProps(internalInst, path: Array<string | number>, value: any) { |
|
var element = internalInst._currentElement; |
|
internalInst._currentElement = { |
|
...element, |
|
props: copyWithSet(element.props, path, value), |
|
}; |
|
internalInst._instance.forceUpdate(); |
|
} |
|
|
|
function setInState(inst, path: Array<string | number>, value: any) { |
|
setIn(inst.state, path, value); |
|
inst.forceUpdate(); |
|
} |
|
|
|
function setInContext(inst, path: Array<string | number>, value: any) { |
|
setIn(inst.context, path, value); |
|
inst.forceUpdate(); |
|
} |
|
|
|
function setIn(obj: Object, path: Array<string | number>, value: any) { |
|
var last = path.pop(); |
|
var parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj); |
|
if (parent) { |
|
parent[last] = value; |
|
} |
|
} |
|
|
|
function childrenList(children) { |
|
var res = []; |
|
for (var name in children) { |
|
res.push(children[name]); |
|
} |
|
return res; |
|
} |
|
|
|
function copyWithSetImpl(obj, path, idx, value) { |
|
if (idx >= path.length) { |
|
return value; |
|
} |
|
var key = path[idx]; |
|
var updated = Array.isArray(obj) ? obj.slice() : {...obj}; |
|
// $FlowFixMe number or string is fine here |
|
updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); |
|
return updated; |
|
} |
|
|
|
function copyWithSet(obj: Object | Array<any>, path: Array<string | number>, value: any): Object | Array<any> { |
|
return copyWithSetImpl(obj, path, 0, value); |
|
} |
|
|
|
module.exports = getData;
|
|
|