Bug 1544710 - ensure that selected row is always visible within TreeView after update. Clean up scroll into view operations across all uses of TreeView. r=mtigley

Differential Revision: https://phabricator.services.mozilla.com/D29342
This commit is contained in:
Yura Zenevich
2019-05-03 04:05:36 +00:00
parent 1681c6964b
commit 46844ab918
13 changed files with 287 additions and 76 deletions

View File

@@ -22,6 +22,8 @@ define(function(require, exports, module) {
const TreeRow = createFactory(require("./TreeRow"));
const TreeHeader = createFactory(require("./TreeHeader"));
const { scrollIntoView } = require("devtools/client/shared/scroll");
const SUPPORTED_KEYS = [
"ArrowUp",
"ArrowDown",
@@ -240,7 +242,8 @@ define(function(require, exports, module) {
const selected = this.getSelectedRow();
if (!selected && this.rows.length > 0) {
this.selectRow(this.rows[
Math.min(this.state.lastSelectedIndex, this.rows.length - 1)]);
Math.min(this.state.lastSelectedIndex, this.rows.length - 1)
], { alignTo: "top" });
}
}
@@ -291,39 +294,34 @@ define(function(require, exports, module) {
const parentRow = this.rows.slice(0, index).reverse().find(
r => r.props.member.level < row.props.member.level);
if (parentRow) {
this.selectRow(parentRow);
this.selectRow(parentRow, { alignTo: "top" });
}
}
break;
case "ArrowDown":
const nextRow = this.rows[index + 1];
if (nextRow) {
this.selectRow(nextRow);
this.selectRow(nextRow, { alignTo: "bottom" });
}
break;
case "ArrowUp":
const previousRow = this.rows[index - 1];
if (previousRow) {
this.selectRow(previousRow);
this.selectRow(previousRow, { alignTo: "top" });
}
break;
case "Home":
const firstRow = this.rows[0];
if (firstRow) {
// Due to the styling, the first row is sometimes overlapped by
// the table head. So we want to force the tree to scroll to the very top.
this.selectRow(firstRow, {
block: "end",
inline: "nearest",
});
this.selectRow(firstRow, { alignTo: "top" });
}
break;
case "End":
const lastRow = this.rows[this.rows.length - 1];
if (lastRow) {
this.selectRow(lastRow);
this.selectRow(lastRow, { alignTo: "bottom" });
}
break;
@@ -367,7 +365,10 @@ define(function(require, exports, module) {
if (cell && cell.classList.contains("treeLabelCell")) {
this.toggle(nodePath);
}
this.selectRow(event.currentTarget);
this.selectRow(
this.rows.find(row => row.props.member.path === nodePath),
{ preventAutoScroll: true });
}
onContextMenu(member, event) {
@@ -394,27 +395,47 @@ define(function(require, exports, module) {
return this.rows.indexOf(row);
}
selectRow(row, scrollOptions = {block: "nearest"}) {
row = findDOMNode(row);
_scrollIntoView(row, options = {}) {
const treeEl = this.treeRef.current;
if (!treeEl || !row) {
return;
}
if (this.state.selected === row.id) {
row.scrollIntoView(scrollOptions);
const { props: { member: { path } = {} } = {} } = row;
if (!path) {
return;
}
const element = treeEl.ownerDocument.getElementById(path);
if (!element) {
return;
}
scrollIntoView(element, { ...options });
}
selectRow(row, options = {}) {
const { props: { member: { path } = {} } = {} } = row;
if (this.isSelected(path)) {
return;
}
if (this.state.active != null) {
if (this.treeRef.current !== document.activeElement) {
this.treeRef.current.focus();
const treeEl = this.treeRef.current;
if (treeEl && treeEl !== treeEl.ownerDocument.activeElement) {
treeEl.focus();
}
}
if (!options.preventAutoScroll) {
this._scrollIntoView(row, options);
}
this.setState({
...this.state,
selected: row.id,
selected: path,
active: null,
});
row.scrollIntoView(scrollOptions);
}
activateRow(active) {