Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't autofocus if the entire react-data-grid is offscreen #704

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions packages/react-data-grid/src/Cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,23 @@ const Cell = React.createClass({
return !this.isSelected() && this.isDraggedOver() && this.props.rowIdx > dragged.rowIdx;
},

isFocusedOnBody() {
isTableOnScreen(dataGridDOMNode) {
// http://stackoverflow.com/a/11193613
const docViewTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
// http://stackoverflow.com/a/28241682
const docViewBottom = docViewTop + (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight);

const elemTop = dataGridDOMNode.offsetTop;
const elemBottom = elemTop + dataGridDOMNode.offsetHeight;

if ((elemTop >= docViewTop && elemTop <= docViewBottom) || (elemBottom >= docViewTop && elemBottom <= docViewBottom)) return true;
return false;
},

isFocusedOnBody(dataGridDOMNode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @theunixbeard , it would be better if you changed this back to the original isFocusedOnBody function, and then...

// Make sure the table is on-screen as prerequisite
if (!this.isTableOnScreen(dataGridDOMNode)) return false;

return document.activeElement == null || (document.activeElement.nodeName && typeof document.activeElement.nodeName === 'string' && document.activeElement.nodeName.toLowerCase() === 'body');
},

Expand All @@ -363,7 +379,7 @@ const Cell = React.createClass({
// Only focus to the current cell if the currently active node in the document is within the data grid.
// Meaning focus should not be stolen from elements that the grid doesnt control.
let dataGridDOMNode = this.props.cellMetaData && this.props.cellMetaData.getDataGridDOMNode ? this.props.cellMetaData.getDataGridDOMNode() : null;
if (this.isFocusedOnCell() || this.isFocusedOnBody() || (dataGridDOMNode && dataGridDOMNode.contains(document.activeElement))) {
if (this.isFocusedOnCell() || this.isFocusedOnBody(dataGridDOMNode) || (dataGridDOMNode && dataGridDOMNode.contains(document.activeElement))) {
Copy link
Contributor

@supamanda supamanda Apr 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... change this if statement to include || this.isFocusedOnBody() || this.isTableOnScreen(dataGridDOMNode)

(Or better still remove this.isFocusedOnBody() altogether.)

let cellDOMNode = ReactDOM.findDOMNode(this);
if (cellDOMNode) {
cellDOMNode.focus();
Expand Down
79 changes: 79 additions & 0 deletions packages/react-data-grid/src/__tests__/Focus.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import ReactDataGrid from '../ReactDataGrid';
import { mount } from 'enzyme';

const createRows = () => {
let rows = [];
for (let i = 1; i < 10; i++) {
rows.push({
id: i,
title: 'Title ' + i,
count: i * 1000
});
}
return rows;
};

const renderContainer = () => {
if (document.getElementById('sandbox') === null) {
let sbox = document.createElement('div');
sbox.id = 'sandbox';
sbox.style.width = '600px';
sbox.style.height = '5000px'; // Big enough to scroll out of range
document.body.appendChild(sbox);
sbox.innerHTML += "<div style='width:600px;height:200px' id='gridContainer'></div>";
}
let gridContainer = document.getElementById('gridContainer');
return gridContainer;
};

const renderComponent = (container, extraProps) => {
let rows = createRows();
let testProps = {
columns: [
{ key: 'id', name: 'ID', editable: true },
{ key: 'title', name: 'Title', editable: true },
{ key: 'count', name: 'Count', editable: true }
],
rowGetter: i => { return rows[i]; },
rowsCount: rows.length,
minHeight: 500,
enableCellSelect: true
};

const wrapper = mount(<ReactDataGrid {...testProps} {...extraProps} />, {attachTo: container});
return wrapper;
};

describe('Focus Tests', () => {
let container;
let testElement;

beforeEach(() => {
container = renderContainer();
});

afterEach(function() {
const elem = document.getElementById('sandbox');
elem.parentNode.removeChild(elem);
});

describe('with current focus on the body', function() {
it('should receive focus when onscreen', function() {
document.body.focus(); // IE requires this explicitly (otherwise activeElement is null)
expect(document.activeElement).toBe(document.body);
testElement = renderComponent(container);
expect(document.activeElement).toBe(
testElement.find('.react-grid-Cell').first().node
);
});
it('should not receive focus when offscreen', function() {
document.body.focus(); // IE requires this explicitly (otherwise activeElement is null)
expect(document.activeElement).toBe(document.body);
window.scrollTo(0, 2000);
expect(document.activeElement).toBe(document.body);
testElement = renderComponent(container);
expect(document.activeElement).toBe(document.body);
});
});
});