UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

416 lines (367 loc) 17.2 kB
Object.defineProperty(exports, '__esModule', { value: true }); /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ // TODO @jxg export debugger typedefs from main module. (t11406963) var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _reactForAtom2; function _reactForAtom() { return _reactForAtom2 = require('react-for-atom'); } var _assert2; function _assert() { return _assert2 = _interopRequireDefault(require('assert')); } var _bindObservableAsProps2; function _bindObservableAsProps() { return _bindObservableAsProps2 = require('./bindObservableAsProps'); } var _highlightOnUpdate2; function _highlightOnUpdate() { return _highlightOnUpdate2 = require('./highlightOnUpdate'); } var _ValueComponentClassNames2; function _ValueComponentClassNames() { return _ValueComponentClassNames2 = require('./ValueComponentClassNames'); } var _Tree2; function _Tree() { return _Tree2 = require('./Tree'); } var _LoadingSpinner2; function _LoadingSpinner() { return _LoadingSpinner2 = require('./LoadingSpinner'); } var SPINNER_DELAY = 100; /* ms */ var NOT_AVAILABLE_MESSAGE = '<not available>'; function isObjectValue(result) { return result.objectId != null; } function TreeItemWithLoadingSpinner() { return (_reactForAtom2 || _reactForAtom()).React.createElement( (_Tree2 || _Tree()).TreeItem, null, (_reactForAtom2 || _reactForAtom()).React.createElement((_LoadingSpinner2 || _LoadingSpinner()).LoadingSpinner, { size: 'EXTRA_SMALL', delay: SPINNER_DELAY }) ); } /** * A wrapper that renders a (delayed) spinner while the list of child properties is being loaded. * Otherwise, it renders ValueComponent for each property in `children`. */ var LoadableValueComponent = function LoadableValueComponent(props) { var children = props.children; var fetchChildren = props.fetchChildren; var path = props.path; var expandedValuePaths = props.expandedValuePaths; var onExpandedStateChange = props.onExpandedStateChange; var simpleValueComponent = props.simpleValueComponent; var shouldCacheChildren = props.shouldCacheChildren; var getCachedChildren = props.getCachedChildren; var setCachedChildren = props.setCachedChildren; if (children == null) { return TreeItemWithLoadingSpinner(); } if (shouldCacheChildren) { setCachedChildren(path, children); } return (_reactForAtom2 || _reactForAtom()).React.createElement( 'span', null, children.map(function (child) { return (_reactForAtom2 || _reactForAtom()).React.createElement( (_Tree2 || _Tree()).TreeItem, { key: child.name }, (_reactForAtom2 || _reactForAtom()).React.createElement(ValueComponent, { evaluationResult: child.value, fetchChildren: fetchChildren, expression: child.name, expandedValuePaths: expandedValuePaths, onExpandedStateChange: onExpandedStateChange, path: path + '.' + child.name, simpleValueComponent: simpleValueComponent, shouldCacheChildren: shouldCacheChildren, getCachedChildren: getCachedChildren, setCachedChildren: setCachedChildren }) ); }) ); }; // TODO allow passing action components (edit button, pin button) here function renderValueLine(expression, value) { if (expression == null) { return (_reactForAtom2 || _reactForAtom()).React.createElement( 'div', { className: 'nuclide-ui-lazy-nested-value-container' }, value ); } else { // TODO @jxg use a text editor to apply proper syntax highlighting for expressions (t11408154) return (_reactForAtom2 || _reactForAtom()).React.createElement( 'div', { className: 'nuclide-ui-lazy-nested-value-container' }, (_reactForAtom2 || _reactForAtom()).React.createElement( 'span', { className: (_ValueComponentClassNames2 || _ValueComponentClassNames()).ValueComponentClassNames.identifier }, expression ), ': ', value ); } } /** * A component that knows how to render recursive, interactive expression/evaluationResult pairs. * The rendering of non-expandable "leaf" values is delegated to the SimpleValueComponent. */ var ValueComponent = (function (_React$Component) { _inherits(ValueComponent, _React$Component); function ValueComponent(props) { _classCallCheck(this, ValueComponent); _get(Object.getPrototypeOf(ValueComponent.prototype), 'constructor', this).call(this, props); this.state = { isExpanded: false, children: null }; this._toggleExpand = this._toggleExpand.bind(this); } _createClass(ValueComponent, [{ key: 'componentDidMount', value: function componentDidMount() { var _props = this.props; var path = _props.path; var expandedValuePaths = _props.expandedValuePaths; var fetchChildren = _props.fetchChildren; var evaluationResult = _props.evaluationResult; var nodeData = expandedValuePaths.get(path); if (!this.state.isExpanded && nodeData != null && nodeData.isExpanded && this._shouldFetch() && evaluationResult != null && evaluationResult.objectId != null && fetchChildren != null) { (0, (_assert2 || _assert()).default)(evaluationResult.objectId != null); this.setState({ children: fetchChildren(evaluationResult.objectId), isExpanded: true }); } } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (this._shouldFetch() && this.state.isExpanded && nextProps.evaluationResult != null && nextProps.fetchChildren != null) { var _objectId = nextProps.evaluationResult.objectId; if (_objectId == null) { return; } this.setState({ children: nextProps.fetchChildren(_objectId) }); } } }, { key: '_shouldFetch', value: function _shouldFetch() { var _props2 = this.props; var shouldCacheChildren = _props2.shouldCacheChildren; var getCachedChildren = _props2.getCachedChildren; var path = _props2.path; var children = getCachedChildren(path); return !shouldCacheChildren || children == null; } }, { key: '_toggleExpand', value: function _toggleExpand(event) { var _props3 = this.props; var fetchChildren = _props3.fetchChildren; var evaluationResult = _props3.evaluationResult; var onExpandedStateChange = _props3.onExpandedStateChange; var path = _props3.path; var newState = { children: null, isExpanded: !this.state.isExpanded }; if (!this.state.isExpanded) { if (this._shouldFetch() && typeof fetchChildren === 'function' && evaluationResult != null && evaluationResult.objectId != null) { newState.children = fetchChildren(evaluationResult.objectId); } } onExpandedStateChange(path, newState.isExpanded); this.setState(newState); event.stopPropagation(); } }, { key: 'render', value: function render() { var _props4 = this.props; var evaluationResult = _props4.evaluationResult; var expression = _props4.expression; var fetchChildren = _props4.fetchChildren; var isRoot = _props4.isRoot; var path = _props4.path; var expandedValuePaths = _props4.expandedValuePaths; var onExpandedStateChange = _props4.onExpandedStateChange; var shouldCacheChildren = _props4.shouldCacheChildren; var getCachedChildren = _props4.getCachedChildren; var setCachedChildren = _props4.setCachedChildren; var SimpleValueComponent = _props4.simpleValueComponent; if (evaluationResult == null) { return renderValueLine(expression, NOT_AVAILABLE_MESSAGE); } if (!isObjectValue(evaluationResult)) { var simpleValueElement = (_reactForAtom2 || _reactForAtom()).React.createElement(SimpleValueComponent, { expression: expression, evaluationResult: evaluationResult, simpleValueComponent: SimpleValueComponent }); return isRoot ? simpleValueElement : (_reactForAtom2 || _reactForAtom()).React.createElement( (_Tree2 || _Tree()).TreeItem, null, simpleValueElement ); } var description = evaluationResult.description || '<no description provided>'; var _state = this.state; var children = _state.children; var isExpanded = _state.isExpanded; var childListElement = null; if (isExpanded) { var _cachedChildren = getCachedChildren(path); if (shouldCacheChildren && _cachedChildren != null) { childListElement = (_reactForAtom2 || _reactForAtom()).React.createElement(LoadableValueComponent, { children: _cachedChildren, fetchChildren: fetchChildren, path: path, expandedValuePaths: expandedValuePaths, onExpandedStateChange: onExpandedStateChange, simpleValueComponent: SimpleValueComponent, shouldCacheChildren: shouldCacheChildren, getCachedChildren: getCachedChildren, setCachedChildren: setCachedChildren }); } else if (children == null) { childListElement = (_reactForAtom2 || _reactForAtom()).React.createElement(TreeItemWithLoadingSpinner, null); } else { var ChildrenComponent = (0, (_bindObservableAsProps2 || _bindObservableAsProps()).bindObservableAsProps)(children.map(function (childrenValue) { return { children: childrenValue }; }).startWith({ children: null }), LoadableValueComponent); childListElement = (_reactForAtom2 || _reactForAtom()).React.createElement(ChildrenComponent, { fetchChildren: fetchChildren, path: path, expandedValuePaths: expandedValuePaths, onExpandedStateChange: onExpandedStateChange, simpleValueComponent: SimpleValueComponent, shouldCacheChildren: shouldCacheChildren, getCachedChildren: getCachedChildren, setCachedChildren: setCachedChildren }); } } var title = renderValueLine(expression, description); return (_reactForAtom2 || _reactForAtom()).React.createElement( (_Tree2 || _Tree()).TreeList, { showArrows: true, className: 'nuclide-ui-lazy-nested-value-treelist' }, (_reactForAtom2 || _reactForAtom()).React.createElement( (_Tree2 || _Tree()).NestedTreeItem, { collapsed: !this.state.isExpanded, onClick: this._toggleExpand, title: title }, childListElement ) ); } }]); return ValueComponent; })((_reactForAtom2 || _reactForAtom()).React.Component); /** * TopLevelValueComponent wraps all expandable value components. It is in charge of keeping track * of the set of recursively expanded values. The set is keyed by a "path", which is a string * containing the concatenated object keys of all recursive parent object for a given item. This * is necessary to preserve the expansion state while the values are temporarily unavailable, such * as after stepping in the debugger, which triggers a recursive re-fetch. */ var TopLevelLazyNestedValueComponent = (function (_React$Component2) { _inherits(TopLevelLazyNestedValueComponent, _React$Component2); function TopLevelLazyNestedValueComponent(props) { _classCallCheck(this, TopLevelLazyNestedValueComponent); _get(Object.getPrototypeOf(TopLevelLazyNestedValueComponent.prototype), 'constructor', this).call(this, props); this.expandedValuePaths = new Map(); this.handleExpansionChange = this.handleExpansionChange.bind(this); this.getCachedChildren = this.getCachedChildren.bind(this); this.setCachedChildren = this.setCachedChildren.bind(this); this.shouldCacheChildren = this.props.shouldCacheChildren == null ? false : this.props.shouldCacheChildren; } _createClass(TopLevelLazyNestedValueComponent, [{ key: 'handleExpansionChange', value: function handleExpansionChange(expandedValuePath, isExpanded) { var nodeData = this.expandedValuePaths.get(expandedValuePath) || { isExpanded: isExpanded, cachedChildren: null }; if (isExpanded) { this.expandedValuePaths.set(expandedValuePath, _extends({}, nodeData, { isExpanded: true })); } else { this.expandedValuePaths.set(expandedValuePath, _extends({}, nodeData, { isExpanded: false })); } } }, { key: 'getCachedChildren', value: function getCachedChildren(path) { var nodeData = this.expandedValuePaths.get(path); if (nodeData == null) { return null; } else { return nodeData.cachedChildren; } } }, { key: 'setCachedChildren', value: function setCachedChildren(path, children) { var nodeData = this.expandedValuePaths.get(path); if (nodeData != null) { this.expandedValuePaths.set(path, _extends({}, nodeData, { cachedChildren: children })); } } }, { key: 'render', value: function render() { var className = this.props.className != null ? this.props.className : 'nuclide-ui-lazy-nested-value'; return (_reactForAtom2 || _reactForAtom()).React.createElement( 'span', { className: className }, (_reactForAtom2 || _reactForAtom()).React.createElement(ValueComponent, _extends({}, this.props, { isRoot: true, expandedValuePaths: this.expandedValuePaths, onExpandedStateChange: this.handleExpansionChange, path: 'root', shouldCacheChildren: this.shouldCacheChildren, getCachedChildren: this.getCachedChildren, setCachedChildren: this.setCachedChildren })) ); } }]); return TopLevelLazyNestedValueComponent; })((_reactForAtom2 || _reactForAtom()).React.Component); function arePropsEqual(p1, p2) { var evaluationResult1 = p1.evaluationResult; var evaluationResult2 = p2.evaluationResult; if (evaluationResult1 === evaluationResult2) { return true; } if (evaluationResult1 == null || evaluationResult2 == null) { return false; } return evaluationResult1.value === evaluationResult2.value && evaluationResult1.type === evaluationResult2.type && evaluationResult1.description === evaluationResult2.description; } var LazyNestedValueComponent = (0, (_highlightOnUpdate2 || _highlightOnUpdate()).highlightOnUpdate)(TopLevelLazyNestedValueComponent, arePropsEqual, undefined, /* custom classname */ undefined); exports.LazyNestedValueComponent = LazyNestedValueComponent; // $FlowIssue -- Flow's object spread operator inference is buggy. // $FlowIssue `evaluationResult` gets injected via HOC. /* custom delay */