Keep selected item height consistent in page-up, page-down
MODIFY
lib/project/results-view.js
lib/project/results-view.js
@@ -24,8 +24,8 @@ class ResultsView {
etch.initialize(this);
this.element.addEventListener('mousedown', this.handleClick.bind(this));
- this.element.addEventListener('scroll', this.renderResults.bind(this));
- this.element.addEventListener('resize', this.renderResults.bind(this));
+ this.element.addEventListener('scroll', () => this.renderResults())
+ this.element.addEventListener('resize', () => this.renderResults())
this.subscriptions = new CompositeDisposable(
this.model.onDidAddResult(this.addResult.bind(this)),
@@ -122,16 +122,17 @@ class ResultsView {
}
}
- renderResults({renderAll, renderNext} = {}) {
+ renderResults(scrollTop) {
for (const filePath of this.model.getPaths().slice(this.searchResults.length)) {
- if (!renderAll && !this.shouldRenderMoreResults()) break;
+ if (!this.shouldRenderMoreResults(scrollTop)) break;
this.searchResults.push(this.model.getResult(filePath));
}
return etch.update(this);
}
- shouldRenderMoreResults() {
+ shouldRenderMoreResults(scrollTop) {
+ if (scrollTop == null) scrollTop = this.element.scrollTop;
const pathDetailsElement = this.element.querySelector('.path-details');
const matchElement = this.element.querySelector('.path:not(.collapsed) .search-result');
const pathDetailsHeight = pathDetailsElement ? pathDetailsElement.offsetHeight : 0;
@@ -145,7 +146,7 @@ class ResultsView {
}
}
- return renderedHeight < this.element.scrollTop + this.element.offsetHeight + this.pixelOverdraw;
+ return renderedHeight < scrollTop + this.element.offsetHeight + this.pixelOverdraw;
}
handleClick(event) {
@@ -189,7 +190,7 @@ class ResultsView {
}
moveToBottom() {
- return this.renderResults({renderAll: true}).then(() => {
+ return this.renderResults(Infinity).then(() => {
this.selectedResultIndex = this.searchResults.length - 1;
if (this.collapsedResultIndices[this.selectedResultIndex]) {
this.selectedMatchIndex = -1;
@@ -223,8 +224,9 @@ class ResultsView {
const matchHeight = matchElement ? matchElement.offsetHeight : 0;
const position = this.positionOfSelectedResult(pathDetailsHeight, matchHeight);
- this.element.scrollTop += this.element.offsetHeight;
- return this.renderResults().then(() => {
+ const newScrollTop = this.element.scrollTop + this.element.offsetHeight;
+ return this.renderResults(newScrollTop).then(() => {
+ this.element.scrollTop = newScrollTop;
this.selectResultAtPosition(
position + this.element.offsetHeight,
pathDetailsHeight,
@@ -250,29 +252,43 @@ class ResultsView {
}
selectResultAtPosition(position, pathDetailsHeight, matchHeight) {
- let top = 0;
+ this.selectedResultIndex = this.searchResults.length - 1;
+ this.selectedMatchIndex = this.collapsedResultIndices[this.selectedResultIndex] ?
+ -1 : this.searchResults[this.selectedResultIndex].matches.length - 1;
+
+ let top = 0, bottom = 0;
for (let i = 0; i < this.searchResults.length; i++) {
- const detailsBottom = top + pathDetailsHeight;
- if (detailsBottom > position) {
+ bottom = top + pathDetailsHeight;
+ if (bottom > position) {
this.selectedResultIndex = i;
this.selectedMatchIndex = -1;
break;
}
+ top = bottom;
+
if (!this.collapsedResultIndices[i]) {
- const matchesBottom = detailsBottom + this.searchResults[i].matches.length * matchHeight;
+ const matchesBottom = top + this.searchResults[i].matches.length * matchHeight;
if (matchesBottom > position) {
this.selectedResultIndex = i;
- this.selectedMatchIndex = Math.floor((position - detailsBottom) / matchHeight);
+ this.selectedMatchIndex = Math.round((position - top) / matchHeight);
+ top += this.selectedMatchIndex * matchHeight;
+ bottom = top + matchHeight;
break;
}
top = matchesBottom;
- } else {
- top = detailsBottom;
}
}
+ if (this.element.scrollTop > top) {
+ this.element.scrollTop = top;
+ }
+
+ if (this.element.scrollTop < bottom - this.element.offsetHeight) {
+ this.element.scrollTop = bottom - this.element.offsetHeight;
+ }
+
etch.update(this);
}
@@ -377,13 +393,13 @@ class ResultsView {
expandAllResults() {
this.collapsedResultIndices = new Array(this.searchResults.length);
this.collapsedResultIndices.fill(false);
- this.renderResults({renderAll: true});
+ this.renderResults(Infinity);
}
collapseAllResults() {
this.collapsedResultIndices = new Array(this.model.getPaths().length);
this.collapsedResultIndices.fill(true);
- this.renderResults({renderAll: true});
+ this.renderResults(Infinity);
}
scrollToSelectedMatch() {
@@ -408,7 +424,7 @@ class ResultsView {
}
scrollToBottom() {
- this.renderResults({renderAll: true});
+ this.renderResults(Infinity);
this.element.scrollTop = this.element.scrollHeight;
}

MODIFY
spec/results-view-spec.js
spec/results-view-spec.js
@@ -326,18 +326,16 @@ describe('ResultsView', () => {
let itemHeight = resultsView.element.querySelector('.selected').offsetHeight;
let pageHeight = resultsView.element.offsetHeight;
let initialScrollTop = resultsView.element.scrollTop;
- let itemsPerPage = Math.floor(pageHeight / itemHeight);
+ let itemsPerPage = Math.round(pageHeight / itemHeight);
let initiallySelectedIndex = getSelectedIndex();
await resultsView.pageUp();
- expect(resultsView.element.querySelectorAll('li')[initiallySelectedIndex]).not.toHaveClass('selected');
- expect(resultsView.element.querySelectorAll('li')[initiallySelectedIndex - itemsPerPage]).toHaveClass('selected');
+ expect(getSelectedIndex()).toBe(initiallySelectedIndex - itemsPerPage);
expect(resultsView.element.scrollTop).toBe(initialScrollTop - pageHeight);
await resultsView.pageUp();
- expect(resultsView.element.querySelectorAll('li')[initiallySelectedIndex - itemsPerPage]).not.toHaveClass('selected');
- expect(resultsView.element.querySelectorAll('li')[initiallySelectedIndex - itemsPerPage * 2]).toHaveClass('selected');
+ expect(getSelectedIndex()).toBe(initiallySelectedIndex - itemsPerPage * 2);
expect(resultsView.element.scrollTop).toBe(initialScrollTop - (pageHeight * 2));
for (let i = 0; i < 60; i++) await resultsView.pageUp();

Keep selected item height consistent in page-up, page-down