diff --git a/packages/react-data-grid/src/Cell.js b/packages/react-data-grid/src/Cell.js index d9d5c2da4c..0ec3f006c9 100644 --- a/packages/react-data-grid/src/Cell.js +++ b/packages/react-data-grid/src/Cell.js @@ -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) { + // 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'); }, @@ -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))) { let cellDOMNode = ReactDOM.findDOMNode(this); if (cellDOMNode) { cellDOMNode.focus(); diff --git a/packages/react-data-grid/src/__tests__/Focus.spec.js b/packages/react-data-grid/src/__tests__/Focus.spec.js new file mode 100644 index 0000000000..efa6ded049 --- /dev/null +++ b/packages/react-data-grid/src/__tests__/Focus.spec.js @@ -0,0 +1,77 @@ +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 += "
"; + } + 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(, {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() { + 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() { + 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); + }); + }); +});