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.

396 lines (347 loc) 13.6 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. */ 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; }; })(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _assert2; function _assert() { return _assert2 = _interopRequireDefault(require('assert')); } var _commonsAtomFeatureConfig2; function _commonsAtomFeatureConfig() { return _commonsAtomFeatureConfig2 = _interopRequireDefault(require('../../commons-atom/featureConfig')); } var _reactForAtom2; function _reactForAtom() { return _reactForAtom2 = require('react-for-atom'); } var _commonsAtomDebounced2; function _commonsAtomDebounced() { return _commonsAtomDebounced2 = require('../../commons-atom/debounced'); } var _rxjsBundlesRxUmdMinJs2; function _rxjsBundlesRxUmdMinJs() { return _rxjsBundlesRxUmdMinJs2 = require('rxjs/bundles/Rx.umd.min.js'); } var _nuclideAnalytics2; function _nuclideAnalytics() { return _nuclideAnalytics2 = require('../../nuclide-analytics'); } var _nuclideLogging2; function _nuclideLogging() { return _nuclideLogging2 = require('../../nuclide-logging'); } var _ContextViewMessage2; function _ContextViewMessage() { return _ContextViewMessage2 = _interopRequireDefault(require('./ContextViewMessage')); } var _ContextViewPanel2; function _ContextViewPanel() { return _ContextViewPanel2 = require('./ContextViewPanel'); } var _ProviderContainer2; function _ProviderContainer() { return _ProviderContainer2 = require('./ProviderContainer'); } var _NoProvidersView2; function _NoProvidersView() { return _NoProvidersView2 = require('./NoProvidersView'); } var EDITOR_DEBOUNCE_INTERVAL = 500; var POSITION_DEBOUNCE_INTERVAL = 500; var logger = (0, (_nuclideLogging2 || _nuclideLogging()).getLogger)(); /** * Manages registering/unregistering of definition service and context providers, * and manages re-rendering when a new definition is emitted from the definition * service. */ var ContextViewManager = (function () { function ContextViewManager(width, isVisible) { _classCallCheck(this, ContextViewManager); this._atomPanel = null; this._contextProviders = []; this._defServiceSubscription = null; this._settingDisposables = new Map(); this._definitionService = null; this._isVisible = isVisible; this._locked = false; // Should be unlocked by default this._panelDOMElement = null; this._width = width; this.currentDefinition = null; this.hide = this.hide.bind(this); this._onResize = this._onResize.bind(this); this._setLocked = this._setLocked.bind(this); this._render(); } _createClass(ContextViewManager, [{ key: 'dispose', value: function dispose() { this._disposeView(); this._settingDisposables.forEach(function (disposable) { disposable.dispose(); }); } }, { key: 'hide', value: function hide() { (0, (_nuclideAnalytics2 || _nuclideAnalytics()).track)('nuclide-context-view:hide'); if (this._isVisible) { this._isVisible = false; this._render(); } this.updateSubscription(); } }, { key: 'registerProvider', value: function registerProvider(newProvider) { var _this = this; // Ensure provider with given ID isn't already registered, // and find index to insert at based on priority var insertIndex = -1; var foundIndex = false; var keyPath = newProvider.id + '.priority'; var newPriority = (_commonsAtomFeatureConfig2 || _commonsAtomFeatureConfig()).default.get(keyPath); var providers = this._contextProviders; for (var i = 0; i < providers.length; i++) { if (newProvider.id === providers[i].id) { return false; } var existingPriority = (_commonsAtomFeatureConfig2 || _commonsAtomFeatureConfig()).default.get(providers[i].id + '.priority'); if (!foundIndex && newPriority <= existingPriority) { insertIndex = i; foundIndex = true; } } if (insertIndex === -1) { insertIndex = providers.length; } this._contextProviders.splice(insertIndex, 0, newProvider); var disposable = (_commonsAtomFeatureConfig2 || _commonsAtomFeatureConfig()).default.observe(keyPath, function (newValue) { _this._sortProvidersBasedOnPriority(); }); this._settingDisposables.set(newProvider.id, disposable); this._render(); return true; } }, { key: '_sortProvidersBasedOnPriority', value: function _sortProvidersBasedOnPriority() { this._contextProviders.sort(function (provider1, provider2) { var priority1 = (_commonsAtomFeatureConfig2 || _commonsAtomFeatureConfig()).default.get(provider1.id + '.priority'); var priority2 = (_commonsAtomFeatureConfig2 || _commonsAtomFeatureConfig()).default.get(provider2.id + '.priority'); return priority1 - priority2; }); this._render(); } }, { key: 'serialize', value: function serialize() { return { width: this._width, visible: this._isVisible }; } /** * Sets handle to registered definition service, sets the subscriber * to the definition service to an Observable<Definition>, and * re-renders if necessary. */ }, { key: 'consumeDefinitionService', value: function consumeDefinitionService(service) { this._definitionService = service; this.updateSubscription(); this._render(); } /** * Subscribes or unsubscribes to definition service based on the current state. */ }, { key: 'updateSubscription', value: function updateSubscription() { var _this2 = this; // Only subscribe if panel showing && there's something to subscribe to && not locked if (this._isVisible && this._definitionService != null && !this._locked) { this._defServiceSubscription = (0, (_commonsAtomDebounced2 || _commonsAtomDebounced()).observeTextEditorsPositions)(EDITOR_DEBOUNCE_INTERVAL, POSITION_DEBOUNCE_INTERVAL).filter(function (editorPos) { return editorPos != null; }).map(function (editorPos) { return (0, (_nuclideAnalytics2 || _nuclideAnalytics()).trackOperationTiming)('nuclide-context-view:getDefinition', function () { (0, (_assert2 || _assert()).default)(editorPos != null); (0, (_assert2 || _assert()).default)(_this2._definitionService != null); return _this2._definitionService.getDefinition(editorPos.editor, editorPos.position).catch(function (error) { logger.error('Error querying definition service: ', error); return null; }); }); }).switchMap(function (queryResult) { return queryResult != null ? (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.fromPromise(queryResult) : (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.empty(); }).map(function (queryResult) { if (queryResult != null) { (0, (_nuclideAnalytics2 || _nuclideAnalytics()).track)('nuclide-context-view:filterQueryResults', { definitionsReturned: queryResult.definitions.length }); // TODO (@reesjones) Handle case where multiple definitions are shown return queryResult.definitions[0]; } // We do want to return null sometimes so providers can show "No definition selected" return null; }).subscribe(function (def) { return _this2.updateCurrentDefinition(def); }); return; } // Otherwise, unsubscribe if there is a subscription if (this._defServiceSubscription != null) { this._defServiceSubscription.unsubscribe(); this._defServiceSubscription = null; } } }, { key: 'show', value: function show() { (0, (_nuclideAnalytics2 || _nuclideAnalytics()).track)('nuclide-context-view:show'); if (!this._isVisible) { this._isVisible = true; this._render(); } this.updateSubscription(); } }, { key: 'toggle', value: function toggle() { if (this._isVisible) { this.hide(); } else { this.show(); } } }, { key: 'unregisterProvider', value: function unregisterProvider(idToRemove) { var wasRemoved = false; for (var i = 0; i < this._contextProviders.length; i++) { if (this._contextProviders[i].id === idToRemove) { // Remove from array this._contextProviders.splice(i, 1); // Unsubscribe from change events on the removed provider's `priority` setting var settingChangeListener = this._settingDisposables.get(idToRemove); if (settingChangeListener != null) { settingChangeListener.dispose(); } this._settingDisposables.delete(idToRemove); wasRemoved = true; } } this._render(); return wasRemoved; } }, { key: 'updateCurrentDefinition', value: function updateCurrentDefinition(newDefinition) { if (newDefinition === this.currentDefinition) { return; } this.currentDefinition = newDefinition; this._render(); } }, { key: '_setLocked', value: function _setLocked(locked) { if (locked !== this._locked) { this._locked = locked; this.updateSubscription(); this._render(); } } }, { key: '_disposeView', value: function _disposeView() { if (this._panelDOMElement != null) { (_reactForAtom2 || _reactForAtom()).ReactDOM.unmountComponentAtNode(this._panelDOMElement); this._panelDOMElement = null; } if (this._atomPanel != null) { this._atomPanel.destroy(); this._atomPanel = null; } if (this._defServiceSubscription != null) { this._defServiceSubscription.unsubscribe(); this._defServiceSubscription = null; } } }, { key: '_onResize', value: function _onResize(newWidth) { this._width = newWidth; } }, { key: '_renderProviders', value: function _renderProviders() { var _this3 = this; // Create collection of provider React elements to render, and var providerElements = this._contextProviders.map(function (prov, index) { var createElementFn = prov.getElementFactory(); return (_reactForAtom2 || _reactForAtom()).React.createElement( (_ProviderContainer2 || _ProviderContainer()).ProviderContainer, { title: prov.title, key: index }, createElementFn({ ContextViewMessage: (_ContextViewMessage2 || _ContextViewMessage()).default, definition: _this3.currentDefinition, setLocked: _this3._setLocked }) ); }); // If there are no context providers to show, show a message instead if (providerElements.length === 0) { providerElements.push((_reactForAtom2 || _reactForAtom()).React.createElement((_NoProvidersView2 || _NoProvidersView()).NoProvidersView, { key: 0 })); } // Render the panel in atom workspace if (!this._panelDOMElement) { this._panelDOMElement = document.createElement('div'); this._panelDOMElement.style.display = 'flex'; } (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement( (_ContextViewPanel2 || _ContextViewPanel()).ContextViewPanel, { initialWidth: this._width, onResize: this._onResize, definition: this.currentDefinition, locked: this._locked, onHide: this.hide }, providerElements ), this._panelDOMElement); if (!this._atomPanel) { (0, (_assert2 || _assert()).default)(this._panelDOMElement != null); this._atomPanel = atom.workspace.addRightPanel({ item: this._panelDOMElement, visible: true, priority: 200 }); } } }, { key: '_render', value: function _render() { if (this._isVisible) { this._renderProviders(); } else { this._disposeView(); } } }]); return ContextViewManager; })(); exports.ContextViewManager = ContextViewManager; // Subscriptions to all changes in registered context providers' `priority` setting. // Key: ID of the context provider // Value: Disposable for the change event subscription on its priority setting // Whether Context View should keep displaying the current content even after the cursor moves // display them in order