diff --git a/lib/items/changed-file-item.js b/lib/items/changed-file-item.js
index da54340e9d..f3d1b6aa0a 100644
--- a/lib/items/changed-file-item.js
+++ b/lib/items/changed-file-item.js
@@ -1,13 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {Emitter} from 'event-kit';
+import ItemComponent from './item-component';
import {WorkdirContextPoolPropType} from '../prop-types';
-import {autobind} from '../helpers';
import ChangedFileContainer from '../containers/changed-file-container';
-import RefHolder from '../models/ref-holder';
-export default class ChangedFileItem extends React.Component {
+export default class ChangedFileItem extends ItemComponent {
static propTypes = {
workdirContextPool: WorkdirContextPoolPropType.isRequired,
@@ -36,15 +34,9 @@ export default class ChangedFileItem extends React.Component {
}
constructor(props) {
- super(props);
- autobind(this, 'destroy');
+ super(props, {});
- this.emitter = new Emitter();
- this.isDestroyed = false;
- this.hasTerminatedPendingState = false;
-
- this.refEditor = new RefHolder();
- this.refEditor.observe(editor => {
+ this.refHolder.observe(editor => {
this.emitter.emit('did-change-embedded-text-editor', editor);
});
}
@@ -56,29 +48,6 @@ export default class ChangedFileItem extends React.Component {
return title;
}
- terminatePendingState() {
- if (!this.hasTerminatedPendingState) {
- this.emitter.emit('did-terminate-pending-state');
- this.hasTerminatedPendingState = true;
- }
- }
-
- onDidTerminatePendingState(callback) {
- return this.emitter.on('did-terminate-pending-state', callback);
- }
-
- destroy() {
- /* istanbul ignore else */
- if (!this.isDestroyed) {
- this.emitter.emit('did-destroy');
- this.isDestroyed = true;
- }
- }
-
- onDidDestroy(callback) {
- return this.emitter.on('did-destroy', callback);
- }
-
render() {
const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();
@@ -87,14 +56,14 @@ export default class ChangedFileItem extends React.Component {
itemType={this.constructor}
repository={repository}
destroy={this.destroy}
- refEditor={this.refEditor}
+ refEditor={this.refHolder}
{...this.props}
/>
);
}
observeEmbeddedTextEditor(cb) {
- this.refEditor.map(editor => cb(editor));
+ this.refHolder.map(editor => cb(editor));
return this.emitter.on('did-change-embedded-text-editor', cb);
}
diff --git a/lib/items/commit-detail-item.js b/lib/items/commit-detail-item.js
index 4d019a2a16..3a1561005f 100644
--- a/lib/items/commit-detail-item.js
+++ b/lib/items/commit-detail-item.js
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {Emitter} from 'event-kit';
+import ItemComponent from './item-component';
import {WorkdirContextPoolPropType} from '../prop-types';
import CommitDetailContainer from '../containers/commit-detail-container';
import RefHolder from '../models/ref-holder';
-export default class CommitDetailItem extends React.Component {
+export default class CommitDetailItem extends ItemComponent {
static propTypes = {
workdirContextPool: WorkdirContextPoolPropType.isRequired,
workingDirectory: PropTypes.string.isRequired,
@@ -20,43 +20,16 @@ export default class CommitDetailItem extends React.Component {
}
constructor(props) {
- super(props);
+ super(props, {title: 'Commit', icon: 'git-commit'});
- this.emitter = new Emitter();
- this.isDestroyed = false;
- this.hasTerminatedPendingState = false;
this.shouldFocus = true;
this.refInitialFocus = new RefHolder();
- this.refEditor = new RefHolder();
- this.refEditor.observe(editor => {
+ this.refHolder.observe(editor => {
this.emitter.emit('did-change-embedded-text-editor', editor);
});
}
- terminatePendingState() {
- if (!this.hasTerminatedPendingState) {
- this.emitter.emit('did-terminate-pending-state');
- this.hasTerminatedPendingState = true;
- }
- }
-
- onDidTerminatePendingState(callback) {
- return this.emitter.on('did-terminate-pending-state', callback);
- }
-
- destroy = () => {
- /* istanbul ignore else */
- if (!this.isDestroyed) {
- this.emitter.emit('did-destroy');
- this.isDestroyed = true;
- }
- }
-
- onDidDestroy(callback) {
- return this.emitter.on('did-destroy', callback);
- }
-
render() {
const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();
@@ -66,7 +39,7 @@ export default class CommitDetailItem extends React.Component {
repository={repository}
{...this.props}
destroy={this.destroy}
- refEditor={this.refEditor}
+ refEditor={this.refHolder}
refInitialFocus={this.refInitialFocus}
/>
);
@@ -76,12 +49,8 @@ export default class CommitDetailItem extends React.Component {
return `Commit: ${this.props.sha}`;
}
- getIconName() {
- return 'git-commit';
- }
-
observeEmbeddedTextEditor(cb) {
- this.refEditor.map(editor => cb(editor));
+ this.refHolder.map(editor => cb(editor));
return this.emitter.on('did-change-embedded-text-editor', cb);
}
diff --git a/lib/items/commit-preview-item.js b/lib/items/commit-preview-item.js
index 9b44b3f4ad..fe687a6eb1 100644
--- a/lib/items/commit-preview-item.js
+++ b/lib/items/commit-preview-item.js
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {Emitter} from 'event-kit';
+import ItemComponent from './item-component';
import {WorkdirContextPoolPropType} from '../prop-types';
import CommitPreviewContainer from '../containers/commit-preview-container';
import RefHolder from '../models/ref-holder';
-export default class CommitPreviewItem extends React.Component {
+export default class CommitPreviewItem extends ItemComponent {
static propTypes = {
workdirContextPool: WorkdirContextPoolPropType.isRequired,
workingDirectory: PropTypes.string.isRequired,
@@ -23,42 +23,15 @@ export default class CommitPreviewItem extends React.Component {
}
constructor(props) {
- super(props);
+ super(props, {title: 'Staged Changes', icon: 'tasklist'});
- this.emitter = new Emitter();
- this.isDestroyed = false;
- this.hasTerminatedPendingState = false;
this.refInitialFocus = new RefHolder();
- this.refEditor = new RefHolder();
- this.refEditor.observe(editor => {
+ this.refHolder.observe(editor => {
this.emitter.emit('did-change-embedded-text-editor', editor);
});
}
- terminatePendingState() {
- if (!this.hasTerminatedPendingState) {
- this.emitter.emit('did-terminate-pending-state');
- this.hasTerminatedPendingState = true;
- }
- }
-
- onDidTerminatePendingState(callback) {
- return this.emitter.on('did-terminate-pending-state', callback);
- }
-
- destroy = () => {
- /* istanbul ignore else */
- if (!this.isDestroyed) {
- this.emitter.emit('did-destroy');
- this.isDestroyed = true;
- }
- }
-
- onDidDestroy(callback) {
- return this.emitter.on('did-destroy', callback);
- }
-
render() {
const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();
@@ -68,22 +41,14 @@ export default class CommitPreviewItem extends React.Component {
repository={repository}
{...this.props}
destroy={this.destroy}
- refEditor={this.refEditor}
+ refEditor={this.refHolder}
refInitialFocus={this.refInitialFocus}
/>
);
}
- getTitle() {
- return 'Staged Changes';
- }
-
- getIconName() {
- return 'tasklist';
- }
-
observeEmbeddedTextEditor(cb) {
- this.refEditor.map(editor => cb(editor));
+ this.refHolder.map(editor => cb(editor));
return this.emitter.on('did-change-embedded-text-editor', cb);
}
diff --git a/lib/items/git-tab-item.js b/lib/items/git-tab-item.js
index e8de6d7cca..ff164d3da3 100644
--- a/lib/items/git-tab-item.js
+++ b/lib/items/git-tab-item.js
@@ -1,10 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
-import RefHolder from '../models/ref-holder';
+import ItemComponent from './item-component';
import GitTabContainer from '../containers/git-tab-container';
-export default class GitTabItem extends React.Component {
+export default class GitTabItem extends ItemComponent {
static propTypes = {
repository: PropTypes.object.isRequired,
}
@@ -16,15 +16,13 @@ export default class GitTabItem extends React.Component {
}
constructor(props) {
- super(props);
-
- this.refController = new RefHolder();
+ super(props, {title: 'Git', icon: 'git-commit'});
}
render() {
return (
);
@@ -37,14 +35,6 @@ export default class GitTabItem extends React.Component {
};
}
- getTitle() {
- return 'Git';
- }
-
- getIconName() {
- return 'git-commit';
- }
-
getDefaultLocation() {
return 'right';
}
@@ -61,37 +51,47 @@ export default class GitTabItem extends React.Component {
return this.props.repository.getWorkingDirectoryPath();
}
+ // no-op
+ destroy() {
+ return false;
+ }
+
+ // no-op
+ terminatePendingState() {
+ return false;
+ }
+
// Forwarded to the controller instance when one is present
rememberLastFocus(...args) {
- return this.refController.map(c => c.rememberLastFocus(...args));
+ return this.refHolder.map(c => c.rememberLastFocus(...args));
}
restoreFocus(...args) {
- return this.refController.map(c => c.restoreFocus(...args));
+ return this.refHolder.map(c => c.restoreFocus(...args));
}
hasFocus(...args) {
- return this.refController.map(c => c.hasFocus(...args));
+ return this.refHolder.map(c => c.hasFocus(...args));
}
focus() {
- return this.refController.map(c => c.restoreFocus());
+ return this.refHolder.map(c => c.restoreFocus());
}
focusAndSelectStagingItem(...args) {
- return this.refController.map(c => c.focusAndSelectStagingItem(...args));
+ return this.refHolder.map(c => c.focusAndSelectStagingItem(...args));
}
focusAndSelectCommitPreviewButton() {
- return this.refController.map(c => c.focusAndSelectCommitPreviewButton());
+ return this.refHolder.map(c => c.focusAndSelectCommitPreviewButton());
}
quietlySelectItem(...args) {
- return this.refController.map(c => c.quietlySelectItem(...args));
+ return this.refHolder.map(c => c.quietlySelectItem(...args));
}
focusAndSelectRecentCommit() {
- return this.refController.map(c => c.focusAndSelectRecentCommit());
+ return this.refHolder.map(c => c.focusAndSelectRecentCommit());
}
}
diff --git a/lib/items/github-tab-item.js b/lib/items/github-tab-item.js
index dc55141ef6..c4ba5089d8 100644
--- a/lib/items/github-tab-item.js
+++ b/lib/items/github-tab-item.js
@@ -2,10 +2,10 @@ import React from 'react';
import PropTypes from 'prop-types';
import {GithubLoginModelPropType} from '../prop-types';
-import RefHolder from '../models/ref-holder';
+import ItemComponent from './item-component';
import GitHubTabContainer from '../containers/github-tab-container';
-export default class GitHubTabItem extends React.Component {
+export default class GitHubTabItem extends ItemComponent {
static propTypes = {
workspace: PropTypes.object.isRequired,
repository: PropTypes.object,
@@ -25,17 +25,7 @@ export default class GitHubTabItem extends React.Component {
}
constructor(props) {
- super(props);
-
- this.rootHolder = new RefHolder();
- }
-
- getTitle() {
- return 'GitHub';
- }
-
- getIconName() {
- return 'octoface';
+ super(props, {title: 'GitHub', icon: 'octoface'});
}
getDefaultLocation() {
@@ -59,15 +49,25 @@ export default class GitHubTabItem extends React.Component {
render() {
return (
-
+
);
}
hasFocus() {
- return this.rootHolder.map(root => root.contains(this.props.documentActiveElement())).getOr(false);
+ return this.refHolder.map(root => root.contains(this.props.documentActiveElement())).getOr(false);
}
restoreFocus() {
// No-op
}
+
+ // no-op
+ destroy() {
+ return false;
+ }
+
+ // no-op
+ terminatePendingState() {
+ return false;
+ }
}
diff --git a/lib/items/issueish-detail-item.js b/lib/items/issueish-detail-item.js
index a0c5c3a1f6..74b21f3dc2 100644
--- a/lib/items/issueish-detail-item.js
+++ b/lib/items/issueish-detail-item.js
@@ -1,6 +1,6 @@
-import React, {Component} from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
-import {Emitter} from 'event-kit';
+import ItemComponent from './item-component';
import {autobind} from '../helpers';
import {GithubLoginModelPropType, WorkdirContextPoolPropType} from '../prop-types';
@@ -8,9 +8,8 @@ import {addEvent} from '../reporter-proxy';
import Repository from '../models/repository';
import {getEndpoint} from '../models/endpoint';
import IssueishDetailContainer from '../containers/issueish-detail-container';
-import RefHolder from '../models/ref-holder';
-export default class IssueishDetailItem extends Component {
+export default class IssueishDetailItem extends ItemComponent {
static propTypes = {
// Issueish selection criteria
// Parsed from item URI
@@ -45,12 +44,10 @@ export default class IssueishDetailItem extends Component {
}
constructor(props) {
- super(props);
- autobind(this, 'switchToIssueish', 'handleTitleChanged');
+ super(props, {});
- this.emitter = new Emitter();
this.title = `${this.props.owner}/${this.props.repo}#${this.props.issueishNumber}`;
- this.hasTerminatedPendingState = false;
+ autobind(this, 'switchToIssueish', 'handleTitleChanged');
const repository = this.props.workingDirectory === ''
? Repository.absent()
@@ -68,8 +65,7 @@ export default class IssueishDetailItem extends Component {
this.switchToIssueish(this.props.owner, this.props.repo, this.props.issueishNumber);
}
- this.refEditor = new RefHolder();
- this.refEditor.observe(editor => {
+ this.refHolder.observe(editor => {
this.emitter.emit('did-change-embedded-text-editor', editor);
});
}
@@ -95,7 +91,7 @@ export default class IssueishDetailItem extends Component {
destroy={this.destroy}
itemType={this.constructor}
- refEditor={this.refEditor}
+ refEditor={this.refHolder}
/>
);
}
@@ -150,29 +146,6 @@ export default class IssueishDetailItem extends Component {
return this.emitter.on('did-change-title', cb);
}
- terminatePendingState() {
- if (!this.hasTerminatedPendingState) {
- this.emitter.emit('did-terminate-pending-state');
- this.hasTerminatedPendingState = true;
- }
- }
-
- onDidTerminatePendingState(callback) {
- return this.emitter.on('did-terminate-pending-state', callback);
- }
-
- destroy = () => {
- /* istanbul ignore else */
- if (!this.isDestroyed) {
- this.emitter.emit('did-destroy');
- this.isDestroyed = true;
- }
- }
-
- onDidDestroy(callback) {
- return this.emitter.on('did-destroy', callback);
- }
-
serialize() {
return {
uri: this.getURI(),
@@ -180,12 +153,8 @@ export default class IssueishDetailItem extends Component {
};
}
- getTitle() {
- return this.title;
- }
-
observeEmbeddedTextEditor(cb) {
- this.refEditor.map(editor => cb(editor));
+ this.refHolder.map(editor => cb(editor));
return this.emitter.on('did-change-embedded-text-editor', cb);
}
}
diff --git a/lib/items/item-component.js b/lib/items/item-component.js
new file mode 100644
index 0000000000..f13fad1a34
--- /dev/null
+++ b/lib/items/item-component.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import RefHolder from '../models/ref-holder';
+import {Emitter} from 'event-kit';
+import {autobind} from '../helpers';
+
+export default class ItemComponent extends React.Component {
+
+ constructor(props, {title, icon}) {
+ super(props);
+ autobind(this, 'destroy');
+
+ this.title = title;
+ this.icon = icon;
+
+ this.refHolder = new RefHolder();
+ this.emitter = new Emitter();
+ this.isDestroyed = false;
+ this.hasTerminatedPendingState = false;
+ }
+
+ getTitle() {
+ return this.title;
+ }
+
+ getIconName() {
+ return this.icon;
+ }
+
+ destroy() {
+ /* istanbul ignore else */
+ if (!this.isDestroyed) {
+ this.emitter.emit('did-destroy');
+ this.isDestroyed = true;
+ }
+ }
+
+ onDidDestroy(callback) {
+ return this.emitter.on('did-destroy', callback);
+ }
+
+ terminatePendingState() {
+ if (!this.hasTerminatedPendingState) {
+ this.emitter.emit('did-terminate-pending-state');
+ this.hasTerminatedPendingState = true;
+ }
+ }
+
+ onDidTerminatePendingState(callback) {
+ return this.emitter.on('did-terminate-pending-state', callback);
+ }
+}
diff --git a/test/items/git-tab-item.test.js b/test/items/git-tab-item.test.js
index 4bd740b459..8f4ceec06e 100644
--- a/test/items/git-tab-item.test.js
+++ b/test/items/git-tab-item.test.js
@@ -74,4 +74,34 @@ describe('GitTabItem', function() {
assert.isTrue(spies[method].called);
}
});
+
+ describe('destroy and terminatePendingState should be overridden as no-ops', function() {
+ it('does not destroy', async function() {
+ mount(buildApp());
+ const item = await atomEnv.workspace.open(GitTabItem.buildURI());
+ const callback = sinon.spy();
+ const sub = item.onDidDestroy(callback);
+
+ assert.strictEqual(callback.callCount, 0);
+ item.destroy();
+ assert.strictEqual(callback.callCount, 0);
+
+ sub.dispose();
+ });
+
+ it('does not terminate pending state', async function() {
+ mount(buildApp());
+
+ const item = await atomEnv.workspace.open(GitTabItem.buildURI());
+ const callback = sinon.spy();
+ const sub = item.onDidTerminatePendingState(callback);
+
+ assert.strictEqual(callback.callCount, 0);
+ item.terminatePendingState();
+ assert.strictEqual(callback.callCount, 0);
+
+ sub.dispose();
+ });
+ });
+
});
diff --git a/test/items/github-tab-item.test.js b/test/items/github-tab-item.test.js
index ae127b9a51..c2f7e81c60 100644
--- a/test/items/github-tab-item.test.js
+++ b/test/items/github-tab-item.test.js
@@ -76,4 +76,34 @@ describe('GitHubTabItem', function() {
activeElement = wrapper.find('.github-GitHub').getDOMNode();
assert.isTrue(item.hasFocus());
});
+
+ describe('destroy and terminatePendingState should be overridden as no-ops', function() {
+ it('does not destroy', async function() {
+ mount(buildApp());
+ const item = await atomEnv.workspace.open(GitHubTabItem.buildURI());
+ const callback = sinon.spy();
+ const sub = item.onDidDestroy(callback);
+
+ assert.strictEqual(callback.callCount, 0);
+ item.destroy();
+ assert.strictEqual(callback.callCount, 0);
+
+ sub.dispose();
+ });
+
+ it('does not terminate pending state', async function() {
+ mount(buildApp());
+
+ const item = await atomEnv.workspace.open(GitHubTabItem.buildURI());
+ const callback = sinon.spy();
+ const sub = item.onDidTerminatePendingState(callback);
+
+ assert.strictEqual(callback.callCount, 0);
+ item.terminatePendingState();
+ assert.strictEqual(callback.callCount, 0);
+
+ sub.dispose();
+ });
+ });
+
});