diff --git a/modules/gridRowContainer.jsx.js b/modules/gridRowContainer.jsx.js index 0619d3c7..b0c0363a 100644 --- a/modules/gridRowContainer.jsx.js +++ b/modules/gridRowContainer.jsx.js @@ -118,7 +118,9 @@ var GridRowContainer = React.createClass({ }); } - return that.props.hasChildren === false ? arr[0] : React.createElement('tbody', null, that.state.showChildren ? arr.concat(children) : arr); + return that.props.hasChildren ? + React.createElement('tbody', null, that.state.showChildren ? arr.concat(children) : arr) : + (that.props.anyHasChildren ? React.createElement('tbody', null, arr[0]): arr[0]); } }); diff --git a/modules/gridTable.jsx.js b/modules/gridTable.jsx.js index 4cfead26..a4092d40 100644 --- a/modules/gridTable.jsx.js +++ b/modules/gridTable.jsx.js @@ -1,6 +1,6 @@ /* - See License / Disclaimer https://raw.githubusercontent.com/DynamicTyped/Griddle/master/LICENSE -*/ + See License / Disclaimer https://raw.githubusercontent.com/DynamicTyped/Griddle/master/LICENSE + */ 'use strict'; var React = require('react'); @@ -10,271 +10,274 @@ var ColumnProperties = require('./columnProperties.js'); var RowProperties = require('./rowProperties.js'); var GridTable = React.createClass({ - displayName: 'GridTable', - - getDefaultProps: function getDefaultProps() { - return { - "data": [], - "columnSettings": null, - "rowSettings": null, - "sortSettings": null, - "multipleSelectionSettings": null, - "className": "", - "enableInfiniteScroll": false, - "nextPage": null, - "hasMorePages": false, - "useFixedHeader": false, - "useFixedLayout": true, - "paddingHeight": null, - "rowHeight": null, - "filterByColumn": null, - "infiniteScrollLoadTreshold": null, - "bodyHeight": null, - "useGriddleStyles": true, - "useGriddleIcons": true, - "isSubGriddle": false, - "parentRowCollapsedClassName": "parent-row", - "parentRowExpandedClassName": "parent-row expanded", - "parentRowCollapsedComponent": "▶", - "parentRowExpandedComponent": "▼", - "externalLoadingComponent": null, - "externalIsLoading": false, - "onRowClick": null - }; - }, - getInitialState: function getInitialState() { - return { - scrollTop: 0, - scrollHeight: this.props.bodyHeight, - clientHeight: this.props.bodyHeight - }; - }, - componentDidMount: function componentDidMount() { - // After the initial render, see if we need to load additional pages. - this.gridScroll(); - }, - componentDidUpdate: function componentDidUpdate(prevProps, prevState) { - // After the subsequent renders, see if we need to load additional pages. - this.gridScroll(); - }, - gridScroll: function gridScroll() { - if (this.props.enableInfiniteScroll && !this.props.externalIsLoading) { - // If the scroll height is greater than the current amount of rows displayed, update the page. - var scrollable = this.refs.scrollable; - var scrollTop = scrollable.scrollTop; - var scrollHeight = scrollable.scrollHeight; - var clientHeight = scrollable.clientHeight; - - // If the scroll position changed and the difference is greater than a row height - if (this.props.rowHeight !== null && this.state.scrollTop !== scrollTop && Math.abs(this.state.scrollTop - scrollTop) >= this.getAdjustedRowHeight()) { - var newState = { - scrollTop: scrollTop, - scrollHeight: scrollHeight, - clientHeight: clientHeight + displayName: 'GridTable', + + getDefaultProps: function getDefaultProps() { + return { + "data": [], + "columnSettings": null, + "rowSettings": null, + "sortSettings": null, + "multipleSelectionSettings": null, + "className": "", + "enableInfiniteScroll": false, + "nextPage": null, + "hasMorePages": false, + "useFixedHeader": false, + "useFixedLayout": true, + "paddingHeight": null, + "rowHeight": null, + "filterByColumn": null, + "infiniteScrollLoadTreshold": null, + "bodyHeight": null, + "useGriddleStyles": true, + "useGriddleIcons": true, + "isSubGriddle": false, + "parentRowCollapsedClassName": "parent-row", + "parentRowExpandedClassName": "parent-row expanded", + "parentRowCollapsedComponent": "▶", + "parentRowExpandedComponent": "▼", + "externalLoadingComponent": null, + "externalIsLoading": false, + "onRowClick": null }; - - // Set the state to the new state - this.setState(newState); - } - - // Determine the diff by subtracting the amount scrolled by the total height, taking into consideratoin - // the spacer's height. - var scrollHeightDiff = scrollHeight - (scrollTop + clientHeight) - this.props.infiniteScrollLoadTreshold; - - // Make sure that we load results a little before reaching the bottom. - var compareHeight = scrollHeightDiff * 0.6; - - if (compareHeight <= this.props.infiniteScrollLoadTreshold) { - this.props.nextPage(); - } - } - }, - verifyProps: function verifyProps() { - if (this.props.columnSettings === null) { - console.error("gridTable: The columnSettings prop is null and it shouldn't be"); - } - if (this.props.rowSettings === null) { - console.error("gridTable: The rowSettings prop is null and it shouldn't be"); - } - }, - getAdjustedRowHeight: function getAdjustedRowHeight() { - return this.props.rowHeight + this.props.paddingHeight * 2; // account for padding. - }, - getNodeContent: function getNodeContent() { - this.verifyProps(); - var that = this; - - //figure out if we need to wrap the group in one tbody or many - var anyHasChildren = false; - - // If the data is still being loaded, don't build the nodes unless this is an infinite scroll table. - if (!this.props.externalIsLoading || this.props.enableInfiniteScroll) { - var nodeData = that.props.data; - var aboveSpacerRow = null; - var belowSpacerRow = null; - var usingDefault = false; - - // If we have a row height specified, only render what's going to be visible. - if (this.props.enableInfiniteScroll && this.props.rowHeight !== null && this.refs.scrollable !== undefined) { - var adjustedHeight = that.getAdjustedRowHeight(); - var visibleRecordCount = Math.ceil(that.state.clientHeight / adjustedHeight); - - // Inspired by : http://jsfiddle.net/vjeux/KbWJ2/9/ - var displayStart = Math.max(0, Math.floor(that.state.scrollTop / adjustedHeight) - visibleRecordCount * 0.25); - var displayEnd = Math.min(displayStart + visibleRecordCount * 1.25, this.props.data.length - 1); - - // Split the amount of nodes. - nodeData = nodeData.slice(displayStart, displayEnd + 1); - - // Set the above and below nodes. - var aboveSpacerRowStyle = { height: displayStart * adjustedHeight + "px" }; - aboveSpacerRow = React.createElement('tr', { key: 'above-' + aboveSpacerRowStyle.height, style: aboveSpacerRowStyle }); - var belowSpacerRowStyle = { height: (this.props.data.length - displayEnd) * adjustedHeight + "px" }; - belowSpacerRow = React.createElement('tr', { key: 'below-' + belowSpacerRowStyle.height, style: belowSpacerRowStyle }); - } - - var nodes = nodeData.map(function (row, index) { - var hasChildren = typeof row["children"] !== "undefined" && row["children"].length > 0; - var uniqueId = that.props.rowSettings.getRowKey(row, index); - - //at least one item in the group has children. - if (hasChildren) { - anyHasChildren = hasChildren; + }, + getInitialState: function getInitialState() { + return { + scrollTop: 0, + scrollHeight: this.props.bodyHeight, + clientHeight: this.props.bodyHeight + }; + }, + componentDidMount: function componentDidMount() { + // After the initial render, see if we need to load additional pages. + this.gridScroll(); + }, + componentDidUpdate: function componentDidUpdate(prevProps, prevState) { + // After the subsequent renders, see if we need to load additional pages. + this.gridScroll(); + }, + gridScroll: function gridScroll() { + if (this.props.enableInfiniteScroll && !this.props.externalIsLoading) { + // If the scroll height is greater than the current amount of rows displayed, update the page. + var scrollable = this.refs.scrollable; + var scrollTop = scrollable.scrollTop; + var scrollHeight = scrollable.scrollHeight; + var clientHeight = scrollable.clientHeight; + + // If the scroll position changed and the difference is greater than a row height + if (this.props.rowHeight !== null && this.state.scrollTop !== scrollTop && Math.abs(this.state.scrollTop - scrollTop) >= this.getAdjustedRowHeight()) { + var newState = { + scrollTop: scrollTop, + scrollHeight: scrollHeight, + clientHeight: clientHeight + }; + + // Set the state to the new state + this.setState(newState); + } + + // Determine the diff by subtracting the amount scrolled by the total height, taking into consideratoin + // the spacer's height. + var scrollHeightDiff = scrollHeight - (scrollTop + clientHeight) - this.props.infiniteScrollLoadTreshold; + + // Make sure that we load results a little before reaching the bottom. + var compareHeight = scrollHeightDiff * 0.6; + + if (compareHeight <= this.props.infiniteScrollLoadTreshold) { + this.props.nextPage(); + } + } + }, + verifyProps: function verifyProps() { + if (this.props.columnSettings === null) { + console.error("gridTable: The columnSettings prop is null and it shouldn't be"); + } + if (this.props.rowSettings === null) { + console.error("gridTable: The rowSettings prop is null and it shouldn't be"); + } + }, + getAdjustedRowHeight: function getAdjustedRowHeight() { + return this.props.rowHeight + this.props.paddingHeight * 2; // account for padding. + }, + getNodeContent: function getNodeContent() { + this.verifyProps(); + var that = this; + + //figure out if we need to wrap the group in one tbody or many + var anyHasChildren = false; + + // If the data is still being loaded, don't build the nodes unless this is an infinite scroll table. + if (!this.props.externalIsLoading || this.props.enableInfiniteScroll) { + var nodeData = that.props.data; + var aboveSpacerRow = null; + var belowSpacerRow = null; + var usingDefault = false; + + // If we have a row height specified, only render what's going to be visible. + if (this.props.enableInfiniteScroll && this.props.rowHeight !== null && this.refs.scrollable !== undefined) { + var adjustedHeight = that.getAdjustedRowHeight(); + var visibleRecordCount = Math.ceil(that.state.clientHeight / adjustedHeight); + + // Inspired by : http://jsfiddle.net/vjeux/KbWJ2/9/ + var displayStart = Math.max(0, Math.floor(that.state.scrollTop / adjustedHeight) - visibleRecordCount * 0.25); + var displayEnd = Math.min(displayStart + visibleRecordCount * 1.25, this.props.data.length - 1); + + // Split the amount of nodes. + nodeData = nodeData.slice(displayStart, displayEnd + 1); + + // Set the above and below nodes. + var aboveSpacerRowStyle = {height: displayStart * adjustedHeight + "px"}; + aboveSpacerRow = React.createElement('tr', {key: 'above-' + aboveSpacerRowStyle.height, style: aboveSpacerRowStyle}); + var belowSpacerRowStyle = {height: (this.props.data.length - displayEnd) * adjustedHeight + "px"}; + belowSpacerRow = React.createElement('tr', {key: 'below-' + belowSpacerRowStyle.height, style: belowSpacerRowStyle}); + } + + var nodes = nodeData.map(function (row, index) { + var hasChildren = typeof row["children"] !== "undefined" && row["children"].length > 0; + var uniqueId = that.props.rowSettings.getRowKey(row, index); + + //at least one item in the group has children. + if (hasChildren) { + anyHasChildren = hasChildren; + } + + return React.createElement(GridRowContainer, { + useGriddleStyles: that.props.useGriddleStyles, + isSubGriddle: that.props.isSubGriddle, + parentRowExpandedClassName: that.props.parentRowExpandedClassName, + parentRowCollapsedClassName: that.props.parentRowCollapsedClassName, + parentRowExpandedComponent: that.props.parentRowExpandedComponent, + parentRowCollapsedComponent: that.props.parentRowCollapsedComponent, + data: row, + key: uniqueId + '-container', + uniqueId: uniqueId, + columnSettings: that.props.columnSettings, + rowSettings: that.props.rowSettings, + paddingHeight: that.props.paddingHeight, + multipleSelectionSettings: that.props.multipleSelectionSettings, + rowHeight: that.props.rowHeight, + hasChildren: hasChildren, + tableClassName: that.props.className, + onRowClick: that.props.onRowClick, + anyHasChildren: anyHasChildren + }); + }); + + // no data section + if (this.props.showNoData) { + var colSpan = this.props.columnSettings.getVisibleColumnCount(); + nodes.push(React.createElement('tr', {key: 'no-data-section'}, React.createElement('td', {colSpan: colSpan}, this.props.noDataSection))); + } + + // Add the spacer rows for nodes we're not rendering. + if (aboveSpacerRow) { + nodes.unshift(aboveSpacerRow); + } + if (belowSpacerRow) { + nodes.push(belowSpacerRow); + } + + // Send back the nodes. + return { + nodes: nodes, + anyHasChildren: anyHasChildren + }; + } else { + return null; + } + }, + render: function render() { + var that = this; + var nodes = []; + + // for if we need to wrap the group in one tbody or many + var anyHasChildren = false; + + // Grab the nodes to render + var nodeContent = this.getNodeContent(); + if (nodeContent) { + nodes = nodeContent.nodes; + anyHasChildren = nodeContent.anyHasChildren; } - return React.createElement(GridRowContainer, { - useGriddleStyles: that.props.useGriddleStyles, - isSubGriddle: that.props.isSubGriddle, - parentRowExpandedClassName: that.props.parentRowExpandedClassName, - parentRowCollapsedClassName: that.props.parentRowCollapsedClassName, - parentRowExpandedComponent: that.props.parentRowExpandedComponent, - parentRowCollapsedComponent: that.props.parentRowCollapsedComponent, - data: row, - key: uniqueId + '-container', - uniqueId: uniqueId, - columnSettings: that.props.columnSettings, - rowSettings: that.props.rowSettings, - paddingHeight: that.props.paddingHeight, - multipleSelectionSettings: that.props.multipleSelectionSettings, - rowHeight: that.props.rowHeight, - hasChildren: hasChildren, - tableClassName: that.props.className, - onRowClick: that.props.onRowClick - }); - }); - - // no data section - if (this.props.showNoData) { - var colSpan = this.props.columnSettings.getVisibleColumnCount(); - nodes.push(React.createElement('tr', { key: 'no-data-section' }, React.createElement('td', { colSpan: colSpan }, this.props.noDataSection))); - } - - // Add the spacer rows for nodes we're not rendering. - if (aboveSpacerRow) { - nodes.unshift(aboveSpacerRow); - } - if (belowSpacerRow) { - nodes.push(belowSpacerRow); - } - - // Send back the nodes. - return { - nodes: nodes, - anyHasChildren: anyHasChildren - }; - } else { - return null; - } - }, - render: function render() { - var that = this; - var nodes = []; - - // for if we need to wrap the group in one tbody or many - var anyHasChildren = false; - - // Grab the nodes to render - var nodeContent = this.getNodeContent(); - if (nodeContent) { - nodes = nodeContent.nodes; - anyHasChildren = nodeContent.anyHasChildren; - } + var gridStyle = null; + var loadingContent = null; + var tableStyle = { + width: "100%" + }; - var gridStyle = null; - var loadingContent = null; - var tableStyle = { - width: "100%" - }; + if (this.props.useFixedLayout) { + tableStyle.tableLayout = "fixed"; + } - if (this.props.useFixedLayout) { - tableStyle.tableLayout = "fixed"; - } + if (this.props.enableInfiniteScroll) { + // If we're enabling infinite scrolling, we'll want to include the max height of the grid body + allow scrolling. + gridStyle = { + "position": "relative", + "overflowY": "scroll", + "height": this.props.bodyHeight + "px", + "width": "100%" + }; + } - if (this.props.enableInfiniteScroll) { - // If we're enabling infinite scrolling, we'll want to include the max height of the grid body + allow scrolling. - gridStyle = { - "position": "relative", - "overflowY": "scroll", - "height": this.props.bodyHeight + "px", - "width": "100%" - }; - } + // If we're currently loading, populate the loading content + if (this.props.externalIsLoading) { + var defaultLoadingStyle = null; + var defaultColSpan = null; - // If we're currently loading, populate the loading content - if (this.props.externalIsLoading) { - var defaultLoadingStyle = null; - var defaultColSpan = null; + if (this.props.useGriddleStyles) { + defaultLoadingStyle = { + textAlign: "center", + paddingBottom: "40px" + }; + } - if (this.props.useGriddleStyles) { - defaultLoadingStyle = { - textAlign: "center", - paddingBottom: "40px" - }; - } + defaultColSpan = this.props.columnSettings.getVisibleColumnCount(); - defaultColSpan = this.props.columnSettings.getVisibleColumnCount(); + var loadingComponent = this.props.externalLoadingComponent ? React.createElement(this.props.externalLoadingComponent, null) : React.createElement('div', null, 'Loading...'); - var loadingComponent = this.props.externalLoadingComponent ? React.createElement(this.props.externalLoadingComponent, null) : React.createElement('div', null, 'Loading...'); + loadingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', {style: defaultLoadingStyle, colSpan: defaultColSpan}, loadingComponent))); + } - loadingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', { style: defaultLoadingStyle, colSpan: defaultColSpan }, loadingComponent))); - } + //construct the table heading component + var tableHeading = this.props.showTableHeading ? React.createElement(GridTitle, { + useGriddleStyles: this.props.useGriddleStyles, useGriddleIcons: this.props.useGriddleIcons, + sortSettings: this.props.sortSettings, + multipleSelectionSettings: this.props.multipleSelectionSettings, + columnSettings: this.props.columnSettings, + filterByColumn: this.props.filterByColumn, + rowSettings: this.props.rowSettings + }) : undefined; + + //check to see if any of the rows have children... if they don't wrap everything in a tbody so the browser doesn't auto do this + if (!anyHasChildren) { + nodes = React.createElement('tbody', null, nodes); + } - //construct the table heading component - var tableHeading = this.props.showTableHeading ? React.createElement(GridTitle, { useGriddleStyles: this.props.useGriddleStyles, useGriddleIcons: this.props.useGriddleIcons, - sortSettings: this.props.sortSettings, - multipleSelectionSettings: this.props.multipleSelectionSettings, - columnSettings: this.props.columnSettings, - filterByColumn: this.props.filterByColumn, - rowSettings: this.props.rowSettings }) : undefined; - - //check to see if any of the rows have children... if they don't wrap everything in a tbody so the browser doesn't auto do this - if (!anyHasChildren) { - nodes = React.createElement('tbody', null, nodes); - } + var pagingContent = React.createElement('tbody', null); + if (this.props.showPager) { + var pagingStyles = this.props.useGriddleStyles ? { + padding: "0px", + backgroundColor: "#EDEDED", + border: "0px", + color: "#222", + height: this.props.showNoData ? "20px" : null + } : null; + pagingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', {colSpan: this.props.multipleSelectionSettings.isMultipleSelection ? this.props.columnSettings.getVisibleColumnCount() + 1 : this.props.columnSettings.getVisibleColumnCount(), style: pagingStyles, className: 'footer-container'}, !this.props.showNoData ? this.props.pagingContent : null))); + } - var pagingContent = React.createElement('tbody', null); - if (this.props.showPager) { - var pagingStyles = this.props.useGriddleStyles ? { - padding: "0px", - backgroundColor: "#EDEDED", - border: "0px", - color: "#222", - height: this.props.showNoData ? "20px" : null - } : null; - pagingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', { colSpan: this.props.multipleSelectionSettings.isMultipleSelection ? this.props.columnSettings.getVisibleColumnCount() + 1 : this.props.columnSettings.getVisibleColumnCount(), style: pagingStyles, className: 'footer-container' }, !this.props.showNoData ? this.props.pagingContent : null))); - } + // If we have a fixed header, split into two tables. + if (this.props.useFixedHeader) { + if (this.props.useGriddleStyles) { + tableStyle.tableLayout = "fixed"; + } - // If we have a fixed header, split into two tables. - if (this.props.useFixedHeader) { - if (this.props.useGriddleStyles) { - tableStyle.tableLayout = "fixed"; - } + return React.createElement('div', null, React.createElement('table', {className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null}, tableHeading), React.createElement('div', {ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle}, React.createElement('table', {className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null}, nodes, loadingContent, pagingContent))); + } - return React.createElement('div', null, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, tableHeading), React.createElement('div', { ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle }, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, nodes, loadingContent, pagingContent))); + return React.createElement('div', {ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle}, React.createElement('table', {className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null}, tableHeading, nodes, loadingContent, pagingContent)); } - - return React.createElement('div', { ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle }, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, tableHeading, nodes, loadingContent, pagingContent)); - } }); module.exports = GridTable;