├── src
├── js
│ ├── ZyngaScroller.jsx
│ ├── main.jsx
│ ├── LoadingObjectContainer.jsx
│ ├── SetContainerSize.jsx
│ ├── LoadingCellContainer.jsx
│ ├── TouchScrollArea.jsx
│ ├── FittedTable.jsx
│ ├── TouchableArea.jsx
│ ├── ObjectData.jsx
│ ├── ObjectDataListStore.jsx
│ └── detect-element-resize.js
├── css
│ ├── style.scss
│ ├── _reset.scss
│ └── _fixed-data-table.scss
└── index.html
├── dist
├── index.html
└── css
│ ├── style.min.css
│ └── style.css
├── package.json
├── LICENSE
└── gulpfile.js
/src/js/ZyngaScroller.jsx:
--------------------------------------------------------------------------------
1 | module.exports = global.Scroller
2 |
--------------------------------------------------------------------------------
/src/css/style.scss:
--------------------------------------------------------------------------------
1 | @import 'reset';
2 | @import 'fixed-data-table';
3 |
4 |
5 | body, #client {
6 | max-height:100%;
7 | height:100%;
8 | max-width:100%;
9 | width:100%;
10 | position:fixed;
11 | }
12 |
--------------------------------------------------------------------------------
/src/js/main.jsx:
--------------------------------------------------------------------------------
1 |
2 | var React = require('react');
3 | Object.assign = require('object-assign');
4 | React.initializeTouchEvents(true);
5 |
6 | var ObjectData = require('./ObjectData.jsx');
7 |
8 | var App = React.createClass({
9 | render: function(){
10 | return (
11 |
12 | );
13 | }
14 | });
15 |
16 |
17 | React.render(, document.getElementById('client'));
18 |
19 |
20 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/js/LoadingObjectContainer.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | var EventEmitter = require('events').EventEmitter;
4 | var assign = require('object-assign');
5 |
6 | var LoadingObjectContainer = function(){
7 | var self = this;
8 |
9 | this.data = undefined;
10 |
11 | this.setData = function(data){
12 | this.data = data;
13 | this.emitChange();
14 | };
15 |
16 | this.emitChange = function(){
17 | self.emit(LoadingObjectContainer.EVENTS.CHANGE);
18 | };
19 |
20 | this.addChangeListener = function(callback){
21 | self.on(LoadingObjectContainer.EVENTS.CHANGE, callback);
22 | };
23 |
24 | this.removeChangeListener = function(callback){
25 | self.removeListener(LoadingObjectContainer.EVENTS.CHANGE, callback);
26 | };
27 |
28 | return this;
29 | };
30 | LoadingObjectContainer.prototype = EventEmitter.prototype;
31 | LoadingObjectContainer.EVENTS = {};
32 | LoadingObjectContainer.EVENTS.CHANGE = "LOADINGOBJECTCONTAINER.CHANGE";
33 |
34 | module.exports = LoadingObjectContainer;
35 |
--------------------------------------------------------------------------------
/src/js/SetContainerSize.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | var detectResize = require('./detect-element-resize.js');
4 |
5 | var SetContainerSize = {
6 | getInitialState: function(){
7 | return {
8 | width: 0,
9 | height: 0
10 | };
11 | },
12 |
13 | componentDidMount : function(){
14 | this._onResize();
15 | detectResize.addResizeListener(this.getDOMNode().parentNode, this._onResize);
16 | },
17 |
18 | componentWillUnmount : function(){
19 | detectResize.removeResizeListener(this.getDOMNode().parentNode, this._onResize);
20 | },
21 |
22 | _onResize : function() {
23 | var node = this.getDOMNode();
24 |
25 | var borderWidth = node.offsetWidth - node.clientWidth;
26 | var borderHeight = node.offsetHeight - node.clientHeight;
27 |
28 | var width = node.parentNode.offsetWidth - borderWidth;
29 | var height = node.parentNode.offsetHeight - borderHeight;
30 |
31 | this.setState({
32 | width:width,
33 | height:height
34 | });
35 | }
36 | };
37 |
38 | module.exports = SetContainerSize;
39 |
40 |
--------------------------------------------------------------------------------
/src/js/LoadingCellContainer.jsx:
--------------------------------------------------------------------------------
1 |
2 | var React = require('react');
3 | var ReactComponentWithPureRenderMixin = require('react/lib/ReactComponentWithPureRenderMixin');
4 |
5 |
6 | var LoadingCellContainer = React.createClass({
7 |
8 | mixins: [ReactComponentWithPureRenderMixin],
9 |
10 | onDataChange : function(){
11 | this.forceUpdate();
12 | },
13 |
14 | componentWillMount : function(){
15 | this.props.data.addChangeListener(this.onDataChange);
16 | },
17 |
18 | componentWillUnmount: function(){
19 | this.props.data.removeChangeListener(this.onDataChange);
20 | },
21 |
22 | componentWillReceiveProps: function(nextProps){
23 | if (this.props && this.props.data){
24 | this.props.data.removeChangeListener(this.onDataChange);
25 | }
26 | nextProps.data.addChangeListener(this.onDataChange);
27 | },
28 |
29 | render : function() {
30 | if (this.props.data.data){
31 | return this.props.renderLoaded(this.props.data.data);
32 | } else {
33 | return this.props.unloaded;
34 | }
35 | }
36 | });
37 |
38 | module.exports = LoadingCellContainer;
39 |
--------------------------------------------------------------------------------
/src/css/_reset.scss:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 | html, body, div, span, applet, object, iframe,
6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
7 | a, abbr, acronym, address, big, cite, code,
8 | del, dfn, em, img, ins, kbd, q, s, samp,
9 | small, strike, strong, sub, sup, tt, var,
10 | b, u, i, center,
11 | dl, dt, dd, ol, ul, li,
12 | fieldset, form, label, legend,
13 | table, caption, tbody, tfoot, thead, tr, th, td,
14 | article, aside, canvas, details, embed,
15 | figure, figcaption, footer, header, hgroup,
16 | menu, nav, output, ruby, section, summary,
17 | time, mark, audio, video {
18 | margin: 0;
19 | padding: 0;
20 | border: 0;
21 | font-size: 100%;
22 | font: inherit;
23 | vertical-align: baseline;
24 | }
25 | /* HTML5 display-role reset for older browsers */
26 | article, aside, details, figcaption, figure,
27 | footer, header, hgroup, menu, nav, section {
28 | display: block;
29 | }
30 | body {
31 | line-height: 1;
32 | }
33 | ol, ul {
34 | list-style: none;
35 | }
36 | blockquote, q {
37 | quotes: none;
38 | }
39 | blockquote:before, blockquote:after,
40 | q:before, q:after {
41 | content: '';
42 | content: none;
43 | }
44 | table {
45 | border-collapse: collapse;
46 | border-spacing: 0;
47 | }
48 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fixed-data-table-simple",
3 | "version": "1.0.0",
4 | "description": "This is a lot of the boilerplate code necessary to use fixed-data-table",
5 | "main": "src/js/main.jsx",
6 | "dependencies": {
7 | "browser-sync": "^2.0.1",
8 | "del": "^1.1.1",
9 | "gulp": "^3.8.11",
10 | "gulp-autoprefixer": "^2.1.0",
11 | "fixed-data-table": "^0.1.0",
12 | "gulp-browserify": "^0.5.1",
13 | "gulp-cache": "^0.2.4",
14 | "gulp-concat": "^2.4.3",
15 | "gulp-imagemin": "^2.2.0",
16 | "gulp-jshint": "^1.9.2",
17 | "gulp-minify-css": "^0.4.5",
18 | "gulp-plumber": "^0.6.6",
19 | "gulp-notify": "^2.2.0",
20 | "gulp-rename": "^1.2.0",
21 | "gulp-sass": "^1.3.2",
22 | "gulp-uglify": "^1.1.0",
23 | "jquery": "^2.1.3",
24 | "object-assign": "^2.0.0",
25 | "react": "^0.12.2",
26 | "reactify": "^1.0.0",
27 | "events": "^1.0.2"
28 | },
29 | "devDependencies": {},
30 | "scripts": {
31 | "test": "echo \"Error: no test specified\" && exit 1"
32 | },
33 | "repository": {
34 | "type": "git",
35 | "url": "https://github.com/ofersadgat/fixed-data-table-simple.git"
36 | },
37 | "author": "Ofer Sadgat",
38 | "license": "BSD",
39 | "bugs": {
40 | "url": "https://github.com/ofersadgat/fixed-data-table-simple/issues"
41 | },
42 | "homepage": "https://github.com/ofersadgat/fixed-data-table-simple"
43 | }
44 |
--------------------------------------------------------------------------------
/src/js/TouchScrollArea.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var ZyngaScroller = require('./ZyngaScroller.jsx');
4 | var TouchableArea = require('./TouchableArea.jsx');
5 |
6 | var PropTypes = React.PropTypes;
7 |
8 | var cloneWithProps = require('react/lib/cloneWithProps');
9 |
10 | function isTouchDevice() {
11 | return 'ontouchstart' in document.documentElement // works on most browsers
12 | || 'onmsgesturechange' in window; // works on ie10
13 | };
14 |
15 | var ScrollArea = React.createClass({
16 |
17 | componentWillMount : function() {
18 | this.scroller = new ZyngaScroller(isTouchDevice() ? this._handleScroll : this._doNothing);
19 | },
20 |
21 | render : function() {
22 | if (!isTouchDevice()) {
23 | return this.props.children;
24 | }
25 |
26 | return (
27 |
28 | {this.props.children}
29 |
30 | );
31 | },
32 |
33 | _onContentDimensionsChange : function(tableWidth, tableHeight, contentWidth, contentHeight) {
34 | this.scroller.setDimensions(
35 | tableWidth,
36 | tableHeight,
37 | contentWidth,
38 | contentHeight
39 | );
40 | },
41 |
42 | _handleScroll : function(left, top) {
43 | this.props.handleScroll(left, top);
44 | },
45 |
46 | _doNothing : function(left, top) {
47 |
48 | }
49 | });
50 |
51 | module.exports = ScrollArea;
52 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, ofersadgat
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of fixed-data-table-simple nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/src/js/FittedTable.jsx:
--------------------------------------------------------------------------------
1 |
2 | var React = require('react');
3 | var FixedDataTable = require('fixed-data-table');
4 | var SetContainerSize = require('./SetContainerSize.jsx');
5 |
6 | var PropTypes = React.PropTypes;
7 | var Table = FixedDataTable.Table;
8 | var Column = FixedDataTable.Column;
9 |
10 | var TouchScrollArea = require('./TouchScrollArea.jsx');
11 |
12 | var FittedTable = React.createClass({
13 | mixins: [SetContainerSize],
14 |
15 | _onContentHeightChange : function(contentHeight) {
16 | var width = 0;
17 | React.Children.forEach(this.props.children, function(child){
18 | if ('width' in child.props){
19 | width = width + child.props.width;
20 | }
21 | });
22 | this.refs.touchScrollArea._onContentDimensionsChange(this.state.width, this.state.height, width, contentHeight);
23 | },
24 |
25 | handleScroll : function(left, top){
26 | this.setState({
27 | top: top,
28 | left: left
29 | });
30 | },
31 |
32 | render : function(){
33 | var controlledScrolling = this.state.left !== undefined || this.state.top !== undefined;
34 | return (
35 |
36 |
44 |
45 | );
46 | }
47 | });
48 |
49 | module.exports = FittedTable;
50 |
--------------------------------------------------------------------------------
/src/js/TouchableArea.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * This file provided by Facebook is for non-commercial testing and evaluation
3 | * purposes only. Facebook reserves all rights not expressly granted.
4 | *
5 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
8 | * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
9 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
10 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 | */
12 |
13 | var React = require('react');
14 |
15 | var TouchableArea = React.createClass({
16 | getDefaultProps : function() {
17 | return {
18 | touchable: true
19 | };
20 | },
21 |
22 | handleTouchStart : function(e) {
23 | if (!this.props.scroller || !this.props.touchable) {
24 | return;
25 | }
26 | this.props.scroller.doTouchStart(e.touches, e.timeStamp);
27 | e.preventDefault();
28 | },
29 |
30 | handleTouchMove : function(e) {
31 | if (!this.props.scroller || !this.props.touchable) {
32 | return;
33 | }
34 | this.props.scroller.doTouchMove(e.touches, e.timeStamp, e.scale);
35 | e.preventDefault();
36 | },
37 |
38 | handleTouchEnd : function(e) {
39 | if (!this.props.scroller || !this.props.touchable) {
40 | return;
41 | }
42 | this.props.scroller.doTouchEnd(e.timeStamp);
43 | e.preventDefault();
44 | },
45 |
46 | render : function() {
47 | return (
48 |
53 | {this.props.children}
54 |
55 | );
56 | }
57 | });
58 |
59 | module.exports = TouchableArea;
60 |
--------------------------------------------------------------------------------
/src/js/ObjectData.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | var React = require('react');
4 | var FixedDataTable = require('fixed-data-table');
5 |
6 | var PropTypes = React.PropTypes;
7 | var Table = FixedDataTable.Table;
8 | var Column = FixedDataTable.Column;
9 |
10 | var LoadingCellContainer = require('./LoadingCellContainer.jsx');
11 | var ObjectDataListStore = require('./ObjectDataListStore.jsx');
12 | var FittedTable = require('./FittedTable.jsx');
13 |
14 |
15 | var renderCell = function(cellData, cellDataKey, rowData, rowIndex, columnData, width){
16 | var renderLoaded = function(rowData){
17 | if (cellDataKey == 'thumbnail'){
18 | return
;
19 | }
20 | return {rowData[cellDataKey]}
;
21 | };
22 |
23 | return (
24 | }
28 | renderLoaded={renderLoaded} />
29 | );
30 | };
31 |
32 | var ObjectData = React.createClass({
33 |
34 | componentWillMount: function(){
35 | var self = this;
36 | ObjectDataListStore.addChangeListener(function(){
37 | self.forceUpdate();
38 | });
39 | },
40 |
41 | render : function() {
42 | return (
43 |
49 |
54 |
59 |
64 |
69 |
70 | );
71 | },
72 | });
73 |
74 | module.exports = ObjectData;
75 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var browserify = require('gulp-browserify');
3 | var concat = require('gulp-concat');
4 | var sass = require('gulp-sass');
5 | var autoprefixer = require('gulp-autoprefixer');
6 | var minifycss = require('gulp-minify-css');
7 | var jshint = require('gulp-jshint');
8 | var uglify = require('gulp-uglify');
9 | var imagemin = require('gulp-imagemin');
10 | var rename = require('gulp-rename');
11 | var concat = require('gulp-concat');
12 | var notify = require('gulp-notify');
13 | var cache = require('gulp-cache');
14 | var plumber = require('gulp-plumber');
15 | var browserSync = require('browser-sync');
16 | var del = require('del');
17 |
18 | // Static server
19 | gulp.task('browser-sync', function() {
20 | browserSync({
21 | notify: false,
22 | server: {
23 | baseDir: "./dist"
24 | }
25 | });
26 | });
27 |
28 | gulp.task('browserify', function(){
29 | return gulp.src('src/js/main.jsx')
30 | .pipe(plumber())
31 | .pipe(browserify({transform: 'reactify'}))
32 | .pipe(concat('table.js'))
33 | .pipe(plumber.stop())
34 | .pipe(gulp.dest('dist/js'));
35 | })
36 |
37 | gulp.task('js', function() {
38 | return gulp.src('src/js/**/*.js')
39 | .pipe(jshint('.jshintrc'))
40 | .pipe(jshint.reporter('default'))
41 | .pipe(concat('main.js'))
42 | .pipe(gulp.dest('dist/assets/js'))
43 | .pipe(rename({suffix: '.min'}))
44 | .pipe(uglify())
45 | .pipe(gulp.dest('dist/assets/js'))
46 | .pipe(notify({ message: 'Scripts task complete' }));
47 | });
48 |
49 | gulp.task('css', function() {
50 | return gulp.src('src/css/*')
51 | .pipe(plumber())
52 | .pipe(sass({ errLogToConsole: true }))
53 | .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1'))
54 | .pipe(concat('style.css'))
55 | .pipe(gulp.dest('dist/css'))
56 | .pipe(rename({suffix: '.min'}))
57 | .pipe(minifycss())
58 | .pipe(plumber.stop())
59 | .pipe(gulp.dest('dist/css'));
60 | });
61 |
62 | gulp.task('clean', function(cb) {
63 | del(['dist'], cb)
64 | });
65 |
66 | gulp.task('html', function(){
67 | return gulp.src('src/index.html')
68 | .pipe(gulp.dest('dist'));
69 | });
70 |
71 | gulp.task('images', function(){
72 | return gulp.src('src/images/*')
73 | .pipe(gulp.dest('dist/images'));
74 | });
75 |
76 | gulp.task('fonts', function(){
77 | return gulp.src('src/fonts/*')
78 | .pipe(gulp.dest('dist/fonts'));
79 | });
80 |
81 | gulp.task('default', ['browserify', 'css', 'images', 'fonts', 'html']);
82 |
83 | gulp.task('watch', ['browser-sync'], function () {
84 |
85 | gulp.watch('src/**/*.*', ['default', browserSync.reload]);
86 | });
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/js/ObjectDataListStore.jsx:
--------------------------------------------------------------------------------
1 |
2 | var $ = require('jquery');
3 | var EventEmitter = require('events').EventEmitter;
4 | var LoadingObjectContainer = require('./LoadingObjectContainer.jsx');
5 |
6 |
7 | var ObjectDataListStoreDefinition = function(){
8 | this.size = undefined;
9 | this.cache = [];
10 |
11 | this.setObjectAt = function(index, data){
12 | if (data instanceof Array){
13 | for (var i = 0; i < data.length; i++){
14 | this.setObjectAt(index + i, data[i]);
15 | }
16 | return;
17 | }
18 | if (!(index in this.cache)){
19 | this.cache[index] = new LoadingObjectContainer();
20 | }
21 | this.cache[index].setData(data);
22 | }.bind(this);
23 |
24 | this.getObjectAt = function getObjectAt(index) {
25 |
26 | if (index >= 0 && (index <= this.size || this.size === undefined) && (this.cache.length < index || this.cache[index] === undefined)) {
27 | var self = this;
28 | var limit = 30;
29 |
30 | var url = 'http://jsonplaceholder.typicode.com/photos';
31 |
32 | var supportsPaging = false; //this fake api doesnt support paging
33 | if (supportsPaging){
34 | url = url + '?limit=' + limit + '&offset=' + index;
35 | for (var i = 0; i < limit; i++){
36 | this.cache[index+i] = new LoadingObjectContainer();
37 | }
38 | }
39 |
40 | $.ajax(url, {
41 | crossDomain: true,
42 | }).then(function(data){
43 | self.setObjectAt(index, data);
44 | if (self.size === undefined || index + data.length > self.size){ //normally here you would set the size to the full table size, but this fake api doesnt have that information
45 | self.size = index + data.length;
46 | self.emitChange();
47 | }
48 | });
49 | }
50 | return index < 0 ? {} : this.cache[index];
51 | }.bind(this);
52 |
53 | this.getSize = function getSize() {
54 | return this.size === undefined ? 0 : this.size;
55 | }.bind(this);
56 |
57 | this.emitChange = function(){
58 | this.emit(ObjectDataListStore.EVENTS.CHANGE);
59 | }.bind(this);
60 |
61 | this.addChangeListener = function(callback){
62 | this.on(ObjectDataListStore.EVENTS.CHANGE, callback);
63 | }.bind(this);
64 |
65 | this.removeChangeListener = function(callback){
66 | this.removeListener(ObjectDataListStore.EVENTS.CHANGE, callback);
67 | }.bind(this);
68 |
69 | return this;
70 | };
71 | ObjectDataListStoreDefinition.prototype = EventEmitter.prototype;
72 | var ObjectDataListStore = new ObjectDataListStoreDefinition();
73 |
74 | ObjectDataListStore.EVENTS = {};
75 | ObjectDataListStore.EVENTS.CHANGE = "ObjectDataListStore.CHANGE";
76 |
77 | ObjectDataListStore.getObjectAt(0);
78 |
79 | module.exports = ObjectDataListStore;
80 |
--------------------------------------------------------------------------------
/dist/css/style.min.css:
--------------------------------------------------------------------------------
1 | a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}table{border-collapse:collapse;border-spacing:0}.public_Scrollbar_main{box-sizing:border-box;outline:0;overflow:hidden;position:absolute;-webkit-transition-duration:250ms;transition-duration:250ms;-webkit-transition-timing-function:ease;transition-timing-function:ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.public_Scrollbar_mainVertical{bottom:0;right:0;top:0;-webkit-transition-property:background-color width;transition-property:background-color width;width:15px}.public_Scrollbar_mainVertical.Scrollbar_mainActive,.public_Scrollbar_mainVertical:hover{background-color:rgba(255,255,255,.8);width:17px}.public_Scrollbar_mainHorizontal{bottom:0;height:15px;left:0;-webkit-transition-property:background-color height;transition-property:background-color height}.public_Scrollbar_mainHorizontal.Scrollbar_mainActive,.public_Scrollbar_mainHorizontal:hover{background-color:rgba(255,255,255,.8);height:17px}.Scrollbar_mainOpaque,.Scrollbar_mainOpaque.Scrollbar_mainActive,.Scrollbar_mainOpaque:hover{background-color:#fff}.Scrollbar_face{left:0;overflow:hidden;position:absolute;z-index:1}.Scrollbar_face:after{background-color:#c2c2c2;border-radius:6px;content:'';display:block;position:absolute;-webkit-transition:background-color 250ms ease;transition:background-color 250ms ease}.Scrollbar_faceActive:after,.Scrollbar_mainActive .Scrollbar_face:after,.public_Scrollbar_main:hover .Scrollbar_face:after{background-color:#7d7d7d}.Scrollbar_faceHorizontal{bottom:0;left:0;top:0}.Scrollbar_faceHorizontal:after{bottom:4px;left:0;top:4px;width:100%}.Scrollbar_faceVertical{left:0;right:0;top:0}.Scrollbar_faceVertical:after{height:100%;left:4px;right:4px;top:0}.public_fixedDataTable_main{border:1px solid #d3d3d3;overflow:hidden;position:relative}.fixedDataTable_hasBottomBorder,.public_fixedDataTable_header{border-bottom:solid 1px #d3d3d3}.public_fixedDataTable_header .public_fixedDataTableCell_main{font-weight:700}.public_fixedDataTable_header,.public_fixedDataTable_header .public_fixedDataTableCell_main{background-color:#f6f7f8;background-image:-webkit-linear-gradient(#fff,#efefef);background-image:linear-gradient(#fff,#efefef)}.public_fixedDataTable_footer .public_fixedDataTableCell_main{background-color:#f6f7f8;border-top:solid 1px #d3d3d3}.fixedDataTable_shadow{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAF0lEQVR4AWPUkNeSBhHCjJoK2twgFisAFagCCp3pJlAAAAAASUVORK5CYII=) repeat-x;height:4px;left:0;position:absolute;right:0;z-index:1}.fixedDataTable_rowsContainer{overflow:hidden;position:relative}.fixedDataTable_horizontalScrollbar{bottom:0;position:absolute}.fixedDataTable_horizontalScrollbar .public_Scrollbar_mainHorizontal{background:#fff}.public_fixedDataTableCell_main{background-color:#fff;border:1px solid #d3d3d3;border-width:0 1px 0 0;box-sizing:border-box;display:block;overflow:hidden;position:relative;white-space:normal}.public_fixedDataTableCell_lastChild{border-width:0 1px 1px 0}.public_fixedDataTableCell_highlighted{background-color:#f4f4f4}.public_fixedDataTableCell_alignRight{text-align:right}.public_fixedDataTableCell_alignCenter{text-align:center}.public_fixedDataTableCell_wrap1{display:table;overflow:hidden}.public_fixedDataTableCell_wrap2{display:table-row}.public_fixedDataTableCell_wrap3{display:table-cell;vertical-align:middle}.public_fixedDataTableCell_cellContent{padding:8px}.fixedDataTableCell_columnResizerContainer{position:absolute;right:0;width:6px;z-index:1}.fixedDataTableCell_columnResizerContainer:hover{cursor:ew-resize}.fixedDataTableCell_columnResizerContainer:hover .fixedDataTableCell_columnResizerKnob{visibility:visible}.fixedDataTableCell_columnResizerKnob{background-color:#0284ff;position:absolute;right:0;visibility:hidden;width:4px}.fixedDataTableCellGroup_cellGroup{-webkit-backface-visibility:hidden;backface-visibility:hidden;left:0;overflow:hidden;position:absolute;top:0;white-space:nowrap}.fixedDataTableCellGroup_cellGroup>.public_fixedDataTableCell_main{display:inline-block;vertical-align:top;white-space:normal}.fixedDataTableCellGroup_cellGroupWrapper{position:absolute;top:0}.fixedDataTableColumnResizerLine_mouseArea{cursor:ew-resize;position:absolute;right:-5px;width:12px}.fixedDataTableColumnResizerLine_main{border-right:1px solid #0284ff;box-sizing:border-box;position:absolute;z-index:10}.fixedDataTableColumnResizerLine_hiddenElem{display:none!important}.public_fixedDataTableRow_main{background-color:#fff;box-sizing:border-box;overflow:hidden;position:absolute;top:0}.fixedDataTableRow_body{left:0;position:absolute;top:0}.public_fixedDataTableRow_highlighted,.public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main{background-color:#f6f7f8}.fixedDataTableRow_fixedColumnsDivider{-webkit-backface-visibility:hidden;backface-visibility:hidden;border-left:solid 1px #d3d3d3;left:0;position:absolute;top:0;width:0}.fixedDataTableRow_columnsShadow{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==) repeat-y;width:4px}.fixedDataTableRow_rowWrapper{position:absolute;top:0}#client,body{max-height:100%;height:100%;max-width:100%;width:100%;position:fixed}
--------------------------------------------------------------------------------
/src/js/detect-element-resize.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Detect Element Resize
3 | *
4 | * https://github.com/sdecima/javascript-detect-element-resize
5 | * Sebastian Decima
6 | *
7 | * version: 0.5.3
8 | **/
9 |
10 |
11 | var attachEvent = document.attachEvent;
12 | var stylesCreated = false;
13 |
14 | if (!attachEvent) {
15 | var requestFrame = (function(){
16 | var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
17 | function(fn){ return window.setTimeout(fn, 20); };
18 | return function(fn){ return raf(fn); };
19 | })();
20 |
21 | var cancelFrame = (function(){
22 | var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
23 | window.clearTimeout;
24 | return function(id){ return cancel(id); };
25 | })();
26 |
27 | var resetTriggers = function(element){
28 | var triggers = element.__resizeTriggers__,
29 | expand = triggers.firstElementChild,
30 | contract = triggers.lastElementChild,
31 | expandChild = expand.firstElementChild;
32 | contract.scrollLeft = contract.scrollWidth;
33 | contract.scrollTop = contract.scrollHeight;
34 | expandChild.style.width = expand.offsetWidth + 1 + 'px';
35 | expandChild.style.height = expand.offsetHeight + 1 + 'px';
36 | expand.scrollLeft = expand.scrollWidth;
37 | expand.scrollTop = expand.scrollHeight;
38 | };
39 |
40 | var checkTriggers = function(element){
41 | return element.offsetWidth != element.__resizeLast__.width ||
42 | element.offsetHeight != element.__resizeLast__.height;
43 | }
44 |
45 | var scrollListener = function(e){
46 | var element = this;
47 | resetTriggers(this);
48 | if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
49 | this.__resizeRAF__ = requestFrame(function(){
50 | if (checkTriggers(element)) {
51 | element.__resizeLast__.width = element.offsetWidth;
52 | element.__resizeLast__.height = element.offsetHeight;
53 | element.__resizeListeners__.forEach(function(fn){
54 | fn.call(element, e);
55 | });
56 | }
57 | });
58 | };
59 |
60 | /* Detect CSS Animations support to detect element display/re-attach */
61 | var animation = false,
62 | animationstring = 'animation',
63 | keyframeprefix = '',
64 | animationstartevent = 'animationstart',
65 | domPrefixes = 'Webkit Moz O ms'.split(' '),
66 | startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
67 | pfx = '';
68 | {
69 | var elm = document.createElement('fakeelement');
70 | if( elm.style.animationName !== undefined ) { animation = true; }
71 |
72 | if( animation === false ) {
73 | for( var i = 0; i < domPrefixes.length; i++ ) {
74 | if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
75 | pfx = domPrefixes[ i ];
76 | animationstring = pfx + 'Animation';
77 | keyframeprefix = '-' + pfx.toLowerCase() + '-';
78 | animationstartevent = startEvents[ i ];
79 | animation = true;
80 | break;
81 | }
82 | }
83 | }
84 | }
85 |
86 | var animationName = 'resizeanim';
87 | var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
88 | var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
89 | }
90 |
91 | var createStyles = function() {
92 | if (!stylesCreated) {
93 | //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
94 | var css = (animationKeyframes ? animationKeyframes : '') +
95 | '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
96 | '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
97 | head = document.head || document.getElementsByTagName('head')[0],
98 | style = document.createElement('style');
99 |
100 | style.type = 'text/css';
101 | if (style.styleSheet) {
102 | style.styleSheet.cssText = css;
103 | } else {
104 | style.appendChild(document.createTextNode(css));
105 | }
106 |
107 | head.appendChild(style);
108 | stylesCreated = true;
109 | }
110 | }
111 |
112 | var addResizeListener = function(element, fn){
113 | if (attachEvent) element.attachEvent('onresize', fn);
114 | else {
115 | if (!element.__resizeTriggers__) {
116 | if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
117 | createStyles();
118 | element.__resizeLast__ = {};
119 | element.__resizeListeners__ = [];
120 | (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
121 | element.__resizeTriggers__.innerHTML = '' +
122 | '';
123 | element.appendChild(element.__resizeTriggers__);
124 | resetTriggers(element);
125 | element.addEventListener('scroll', scrollListener, true);
126 |
127 | /* Listen for a css animation to detect element display/re-attach */
128 | animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
129 | if(e.animationName == animationName)
130 | resetTriggers(element);
131 | });
132 | }
133 | element.__resizeListeners__.push(fn);
134 | }
135 | };
136 |
137 | var removeResizeListener = function(element, fn){
138 | if (attachEvent) element.detachEvent('onresize', fn);
139 | else {
140 | element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
141 | if (!element.__resizeListeners__.length) {
142 | element.removeEventListener('scroll', scrollListener);
143 | element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
144 | }
145 | }
146 | }
147 |
148 | module.exports = {
149 | addResizeListener : addResizeListener,
150 | removeResizeListener : removeResizeListener
151 | };
152 |
--------------------------------------------------------------------------------
/src/css/_fixed-data-table.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * FixedDataTable v0.1.0
3 | *
4 | * Copyright (c) 2015, Facebook, Inc.
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree. An additional grant
9 | * of patent rights can be found in the PATENTS file in the same directory.
10 | */
11 |
12 | /**
13 | * Copyright (c) 2015, Facebook, Inc.
14 | * All rights reserved.
15 | *
16 | * This source code is licensed under the BSD-style license found in the
17 | * LICENSE file in the root directory of this source tree. An additional grant
18 | * of patent rights can be found in the PATENTS file in the same directory.
19 | *
20 | * @providesModule Scrollbar
21 | */
22 |
23 | .public_Scrollbar_main {
24 | box-sizing: border-box;
25 | outline: none;
26 | overflow: hidden;
27 | position: absolute;
28 | -webkit-transition-duration: 250ms;
29 | transition-duration: 250ms;
30 | -webkit-transition-timing-function: ease;
31 | transition-timing-function: ease;
32 | -webkit-user-select: none;
33 | -moz-user-select: none;
34 | -ms-user-select: none;
35 | user-select: none;
36 | }
37 |
38 | .public_Scrollbar_mainVertical {
39 | bottom: 0;
40 | right: 0;
41 | top: 0;
42 | -webkit-transition-property: background-color width;
43 | transition-property: background-color width;
44 | width: 15px;
45 | }
46 |
47 | /* Touching the scroll-track directly makes the scroll-track bolder */
48 | .public_Scrollbar_mainVertical.Scrollbar_mainActive,
49 | .public_Scrollbar_mainVertical:hover {
50 | background-color: rgba(255, 255, 255, 0.8);
51 | width: 17px;
52 | }
53 |
54 | .public_Scrollbar_mainHorizontal {
55 | bottom: 0;
56 | height: 15px;
57 | left: 0;
58 | -webkit-transition-property: background-color height;
59 | transition-property: background-color height;
60 | }
61 |
62 | /* Touching the scroll-track directly makes the scroll-track bolder */
63 | .public_Scrollbar_mainHorizontal.Scrollbar_mainActive,
64 | .public_Scrollbar_mainHorizontal:hover {
65 | background-color: rgba(255, 255, 255, 0.8);
66 | height: 17px;
67 | }
68 |
69 | .Scrollbar_mainOpaque,
70 | .Scrollbar_mainOpaque.Scrollbar_mainActive,
71 | .Scrollbar_mainOpaque:hover {
72 | background-color: #fff;
73 | }
74 |
75 | .Scrollbar_face {
76 | left: 0;
77 | overflow: hidden;
78 | position: absolute;
79 | z-index: 1;
80 | }
81 |
82 | /**
83 | * This selector renders the "nub" of the scrollface. The nub must
84 | * be rendered as pseudo-element so that it won't receive any UI events then
85 | * we can get the correct `event.offsetX` and `event.offsetY` from the
86 | * scrollface element while dragging it.
87 | */
88 | .Scrollbar_face:after {
89 | background-color: #c2c2c2;
90 | border-radius: 6px;
91 | content: '';
92 | display: block;
93 | position: absolute;
94 | -webkit-transition: background-color 250ms ease;
95 | transition: background-color 250ms ease;
96 | }
97 |
98 | .public_Scrollbar_main:hover .Scrollbar_face:after,
99 | .Scrollbar_mainActive .Scrollbar_face:after,
100 | .Scrollbar_faceActive:after {
101 | background-color: #7d7d7d;
102 | }
103 |
104 | .Scrollbar_faceHorizontal {
105 | bottom: 0;
106 | left: 0;
107 | top: 0;
108 | }
109 |
110 | .Scrollbar_faceHorizontal:after {
111 | bottom: 4px;
112 | left: 0;
113 | top: 4px;
114 | width: 100%;
115 | }
116 |
117 | .Scrollbar_faceVertical {
118 | left: 0;
119 | right: 0;
120 | top: 0;
121 | }
122 |
123 | .Scrollbar_faceVertical:after {
124 | height: 100%;
125 | left: 4px;
126 | right: 4px;
127 | top: 0;
128 | }
129 | /**
130 | * Copyright (c) 2015, Facebook, Inc.
131 | * All rights reserved.
132 | *
133 | * This source code is licensed under the BSD-style license found in the
134 | * LICENSE file in the root directory of this source tree. An additional grant
135 | * of patent rights can be found in the PATENTS file in the same directory.
136 | *
137 | * @providesModule fixedDataTable
138 | */
139 |
140 | .public_fixedDataTable_main {
141 | border: solid 1px #d3d3d3;
142 | overflow: hidden;
143 | position: relative;
144 | }
145 |
146 | .public_fixedDataTable_header,
147 | .fixedDataTable_hasBottomBorder {
148 | border-bottom: solid 1px #d3d3d3;
149 | }
150 |
151 | .public_fixedDataTable_header .public_fixedDataTableCell_main {
152 | font-weight: bold;
153 | }
154 |
155 | .public_fixedDataTable_header,
156 | .public_fixedDataTable_header .public_fixedDataTableCell_main {
157 | background-color: #f6f7f8;
158 | background-image: -webkit-linear-gradient(#fff, #efefef);
159 | background-image: linear-gradient(#fff, #efefef);
160 | }
161 |
162 | .public_fixedDataTable_footer .public_fixedDataTableCell_main {
163 | background-color: #f6f7f8;
164 | border-top: solid 1px #d3d3d3;
165 | }
166 |
167 | .fixedDataTable_shadow {
168 | background: 0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAF0lEQVR4AWPUkNeSBhHCjJoK2twgFisAFagCCp3pJlAAAAAASUVORK5CYII=) repeat-x;
169 | height: 4px;
170 | left: 0;
171 | position: absolute;
172 | right: 0;
173 | z-index: 1;
174 | }
175 |
176 | .fixedDataTable_rowsContainer {
177 | overflow: hidden;
178 | position: relative;
179 | }
180 |
181 | .fixedDataTable_horizontalScrollbar {
182 | bottom: 0;
183 | position: absolute;
184 | }
185 |
186 | .fixedDataTable_horizontalScrollbar .public_Scrollbar_mainHorizontal {
187 | background: #fff;
188 | }
189 | /**
190 | * Copyright (c) 2015, Facebook, Inc.
191 | * All rights reserved.
192 | *
193 | * This source code is licensed under the BSD-style license found in the
194 | * LICENSE file in the root directory of this source tree. An additional grant
195 | * of patent rights can be found in the PATENTS file in the same directory.
196 | *
197 | * @providesModule fixedDataTableCell
198 | */
199 |
200 | .public_fixedDataTableCell_main {
201 | background-color: #fff;
202 | border: solid 1px #d3d3d3;
203 | border-width: 0 1px 0 0;
204 | box-sizing: border-box;
205 | display: block;
206 | overflow: hidden;
207 | position: relative;
208 | white-space: normal;
209 | }
210 |
211 | .public_fixedDataTableCell_lastChild {
212 | border-width: 0 1px 1px 0;
213 | }
214 |
215 | .public_fixedDataTableCell_highlighted {
216 | background-color: #f4f4f4;
217 | }
218 |
219 | .public_fixedDataTableCell_alignRight {
220 | text-align: right;
221 | }
222 |
223 | .public_fixedDataTableCell_alignCenter {
224 | text-align: center;
225 | }
226 |
227 | .public_fixedDataTableCell_wrap1 {
228 | display: table;
229 | overflow: hidden;
230 | }
231 |
232 | .public_fixedDataTableCell_wrap2 {
233 | display: table-row;
234 | }
235 |
236 | .public_fixedDataTableCell_wrap3 {
237 | display: table-cell;
238 | vertical-align: middle;
239 | }
240 |
241 | .public_fixedDataTableCell_cellContent {
242 | padding: 8px;
243 | }
244 |
245 | .fixedDataTableCell_columnResizerContainer {
246 | position: absolute;
247 | right: 0px;
248 | width: 6px;
249 | z-index: 1;
250 | }
251 |
252 | .fixedDataTableCell_columnResizerContainer:hover {
253 | cursor: ew-resize;
254 | }
255 |
256 | .fixedDataTableCell_columnResizerContainer:hover .fixedDataTableCell_columnResizerKnob {
257 | visibility: visible;
258 | }
259 |
260 | .fixedDataTableCell_columnResizerKnob {
261 | background-color: #0284ff;
262 | position: absolute;
263 | right: 0px;
264 | visibility: hidden;
265 | width: 4px;
266 | }
267 | /**
268 | * Copyright (c) 2015, Facebook, Inc.
269 | * All rights reserved.
270 | *
271 | * This source code is licensed under the BSD-style license found in the
272 | * LICENSE file in the root directory of this source tree. An additional grant
273 | * of patent rights can be found in the PATENTS file in the same directory.
274 | *
275 | * @providesModule fixedDataTableCellGroup
276 | */
277 |
278 | .fixedDataTableCellGroup_cellGroup {
279 | -webkit-backface-visibility: hidden;
280 | backface-visibility: hidden;
281 | left: 0;
282 | overflow: hidden;
283 | position: absolute;
284 | top: 0;
285 | white-space: nowrap;
286 | }
287 |
288 | .fixedDataTableCellGroup_cellGroup > .public_fixedDataTableCell_main {
289 | display: inline-block;
290 | vertical-align: top;
291 | white-space: normal;
292 | }
293 |
294 | .fixedDataTableCellGroup_cellGroupWrapper {
295 | position: absolute;
296 | top: 0;
297 | }
298 | /**
299 | * Copyright (c) 2015, Facebook, Inc.
300 | * All rights reserved.
301 | *
302 | * This source code is licensed under the BSD-style license found in the
303 | * LICENSE file in the root directory of this source tree. An additional grant
304 | * of patent rights can be found in the PATENTS file in the same directory.
305 | *
306 | * @providesModule fixedDataTableColumnResizerLine
307 | */
308 |
309 | .fixedDataTableColumnResizerLine_mouseArea {
310 | cursor: ew-resize;
311 | position: absolute;
312 | right: -5px;
313 | width: 12px;
314 | }
315 |
316 | .fixedDataTableColumnResizerLine_main {
317 | border-right: 1px solid #0284ff;
318 | box-sizing: border-box;
319 | position: absolute;
320 | z-index: 10;
321 | }
322 |
323 | .fixedDataTableColumnResizerLine_hiddenElem {
324 | display: none !important;
325 | }
326 | /**
327 | * Copyright (c) 2015, Facebook, Inc.
328 | * All rights reserved.
329 | *
330 | * This source code is licensed under the BSD-style license found in the
331 | * LICENSE file in the root directory of this source tree. An additional grant
332 | * of patent rights can be found in the PATENTS file in the same directory.
333 | *
334 | * @providesModule fixedDataTableRow
335 | */
336 |
337 | .public_fixedDataTableRow_main {
338 | background-color: #fff;
339 | box-sizing: border-box;
340 | overflow: hidden;
341 | position: absolute;
342 | top: 0;
343 | }
344 |
345 | .fixedDataTableRow_body {
346 | left: 0;
347 | position: absolute;
348 | top: 0;
349 | }
350 |
351 | .public_fixedDataTableRow_highlighted,
352 | .public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main {
353 | background-color: #f6f7f8;
354 | }
355 |
356 | .fixedDataTableRow_fixedColumnsDivider {
357 | -webkit-backface-visibility: hidden;
358 | backface-visibility: hidden;
359 | border-left: solid 1px #d3d3d3;
360 | left: 0;
361 | position: absolute;
362 | top: 0;
363 | width: 0;
364 | }
365 |
366 | .fixedDataTableRow_columnsShadow {
367 | background: 0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==) repeat-y;
368 | width: 4px;
369 | }
370 |
371 | .fixedDataTableRow_rowWrapper {
372 | position: absolute;
373 | top: 0;
374 | }
375 |
--------------------------------------------------------------------------------
/dist/css/style.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
6 | margin: 0;
7 | padding: 0;
8 | border: 0;
9 | font-size: 100%;
10 | font: inherit;
11 | vertical-align: baseline; }
12 |
13 | /* HTML5 display-role reset for older browsers */
14 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
15 | display: block; }
16 |
17 | body {
18 | line-height: 1; }
19 |
20 | ol, ul {
21 | list-style: none; }
22 |
23 | blockquote, q {
24 | quotes: none; }
25 |
26 | blockquote:before, blockquote:after, q:before, q:after {
27 | content: '';
28 | content: none; }
29 |
30 | table {
31 | border-collapse: collapse;
32 | border-spacing: 0; }
33 |
34 | /**
35 | * FixedDataTable v0.1.0
36 | *
37 | * Copyright (c) 2015, Facebook, Inc.
38 | * All rights reserved.
39 | *
40 | * This source code is licensed under the BSD-style license found in the
41 | * LICENSE file in the root directory of this source tree. An additional grant
42 | * of patent rights can be found in the PATENTS file in the same directory.
43 | */
44 | /**
45 | * Copyright (c) 2015, Facebook, Inc.
46 | * All rights reserved.
47 | *
48 | * This source code is licensed under the BSD-style license found in the
49 | * LICENSE file in the root directory of this source tree. An additional grant
50 | * of patent rights can be found in the PATENTS file in the same directory.
51 | *
52 | * @providesModule Scrollbar
53 | */
54 | .public_Scrollbar_main {
55 | box-sizing: border-box;
56 | outline: none;
57 | overflow: hidden;
58 | position: absolute;
59 | -webkit-transition-duration: 250ms;
60 | transition-duration: 250ms;
61 | -webkit-transition-timing-function: ease;
62 | transition-timing-function: ease;
63 | -webkit-user-select: none;
64 | -moz-user-select: none;
65 | -ms-user-select: none;
66 | user-select: none; }
67 |
68 | .public_Scrollbar_mainVertical {
69 | bottom: 0;
70 | right: 0;
71 | top: 0;
72 | -webkit-transition-property: background-color width;
73 | transition-property: background-color width;
74 | width: 15px; }
75 |
76 | /* Touching the scroll-track directly makes the scroll-track bolder */
77 | .public_Scrollbar_mainVertical.Scrollbar_mainActive, .public_Scrollbar_mainVertical:hover {
78 | background-color: rgba(255, 255, 255, 0.8);
79 | width: 17px; }
80 |
81 | .public_Scrollbar_mainHorizontal {
82 | bottom: 0;
83 | height: 15px;
84 | left: 0;
85 | -webkit-transition-property: background-color height;
86 | transition-property: background-color height; }
87 |
88 | /* Touching the scroll-track directly makes the scroll-track bolder */
89 | .public_Scrollbar_mainHorizontal.Scrollbar_mainActive, .public_Scrollbar_mainHorizontal:hover {
90 | background-color: rgba(255, 255, 255, 0.8);
91 | height: 17px; }
92 |
93 | .Scrollbar_mainOpaque, .Scrollbar_mainOpaque.Scrollbar_mainActive, .Scrollbar_mainOpaque:hover {
94 | background-color: #fff; }
95 |
96 | .Scrollbar_face {
97 | left: 0;
98 | overflow: hidden;
99 | position: absolute;
100 | z-index: 1; }
101 |
102 | /**
103 | * This selector renders the "nub" of the scrollface. The nub must
104 | * be rendered as pseudo-element so that it won't receive any UI events then
105 | * we can get the correct `event.offsetX` and `event.offsetY` from the
106 | * scrollface element while dragging it.
107 | */
108 | .Scrollbar_face:after {
109 | background-color: #c2c2c2;
110 | border-radius: 6px;
111 | content: '';
112 | display: block;
113 | position: absolute;
114 | -webkit-transition: background-color 250ms ease;
115 | transition: background-color 250ms ease; }
116 |
117 | .public_Scrollbar_main:hover .Scrollbar_face:after, .Scrollbar_mainActive .Scrollbar_face:after, .Scrollbar_faceActive:after {
118 | background-color: #7d7d7d; }
119 |
120 | .Scrollbar_faceHorizontal {
121 | bottom: 0;
122 | left: 0;
123 | top: 0; }
124 |
125 | .Scrollbar_faceHorizontal:after {
126 | bottom: 4px;
127 | left: 0;
128 | top: 4px;
129 | width: 100%; }
130 |
131 | .Scrollbar_faceVertical {
132 | left: 0;
133 | right: 0;
134 | top: 0; }
135 |
136 | .Scrollbar_faceVertical:after {
137 | height: 100%;
138 | left: 4px;
139 | right: 4px;
140 | top: 0; }
141 |
142 | /**
143 | * Copyright (c) 2015, Facebook, Inc.
144 | * All rights reserved.
145 | *
146 | * This source code is licensed under the BSD-style license found in the
147 | * LICENSE file in the root directory of this source tree. An additional grant
148 | * of patent rights can be found in the PATENTS file in the same directory.
149 | *
150 | * @providesModule fixedDataTable
151 | */
152 | .public_fixedDataTable_main {
153 | border: solid 1px #d3d3d3;
154 | overflow: hidden;
155 | position: relative; }
156 |
157 | .public_fixedDataTable_header, .fixedDataTable_hasBottomBorder {
158 | border-bottom: solid 1px #d3d3d3; }
159 |
160 | .public_fixedDataTable_header .public_fixedDataTableCell_main {
161 | font-weight: bold; }
162 |
163 | .public_fixedDataTable_header, .public_fixedDataTable_header .public_fixedDataTableCell_main {
164 | background-color: #f6f7f8;
165 | background-image: -webkit-linear-gradient(#fff, #efefef);
166 | background-image: linear-gradient(#fff, #efefef); }
167 |
168 | .public_fixedDataTable_footer .public_fixedDataTableCell_main {
169 | background-color: #f6f7f8;
170 | border-top: solid 1px #d3d3d3; }
171 |
172 | .fixedDataTable_shadow {
173 | background: 0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAF0lEQVR4AWPUkNeSBhHCjJoK2twgFisAFagCCp3pJlAAAAAASUVORK5CYII=) repeat-x;
174 | height: 4px;
175 | left: 0;
176 | position: absolute;
177 | right: 0;
178 | z-index: 1; }
179 |
180 | .fixedDataTable_rowsContainer {
181 | overflow: hidden;
182 | position: relative; }
183 |
184 | .fixedDataTable_horizontalScrollbar {
185 | bottom: 0;
186 | position: absolute; }
187 |
188 | .fixedDataTable_horizontalScrollbar .public_Scrollbar_mainHorizontal {
189 | background: #fff; }
190 |
191 | /**
192 | * Copyright (c) 2015, Facebook, Inc.
193 | * All rights reserved.
194 | *
195 | * This source code is licensed under the BSD-style license found in the
196 | * LICENSE file in the root directory of this source tree. An additional grant
197 | * of patent rights can be found in the PATENTS file in the same directory.
198 | *
199 | * @providesModule fixedDataTableCell
200 | */
201 | .public_fixedDataTableCell_main {
202 | background-color: #fff;
203 | border: solid 1px #d3d3d3;
204 | border-width: 0 1px 0 0;
205 | box-sizing: border-box;
206 | display: block;
207 | overflow: hidden;
208 | position: relative;
209 | white-space: normal; }
210 |
211 | .public_fixedDataTableCell_lastChild {
212 | border-width: 0 1px 1px 0; }
213 |
214 | .public_fixedDataTableCell_highlighted {
215 | background-color: #f4f4f4; }
216 |
217 | .public_fixedDataTableCell_alignRight {
218 | text-align: right; }
219 |
220 | .public_fixedDataTableCell_alignCenter {
221 | text-align: center; }
222 |
223 | .public_fixedDataTableCell_wrap1 {
224 | display: table;
225 | overflow: hidden; }
226 |
227 | .public_fixedDataTableCell_wrap2 {
228 | display: table-row; }
229 |
230 | .public_fixedDataTableCell_wrap3 {
231 | display: table-cell;
232 | vertical-align: middle; }
233 |
234 | .public_fixedDataTableCell_cellContent {
235 | padding: 8px; }
236 |
237 | .fixedDataTableCell_columnResizerContainer {
238 | position: absolute;
239 | right: 0px;
240 | width: 6px;
241 | z-index: 1; }
242 |
243 | .fixedDataTableCell_columnResizerContainer:hover {
244 | cursor: ew-resize; }
245 |
246 | .fixedDataTableCell_columnResizerContainer:hover .fixedDataTableCell_columnResizerKnob {
247 | visibility: visible; }
248 |
249 | .fixedDataTableCell_columnResizerKnob {
250 | background-color: #0284ff;
251 | position: absolute;
252 | right: 0px;
253 | visibility: hidden;
254 | width: 4px; }
255 |
256 | /**
257 | * Copyright (c) 2015, Facebook, Inc.
258 | * All rights reserved.
259 | *
260 | * This source code is licensed under the BSD-style license found in the
261 | * LICENSE file in the root directory of this source tree. An additional grant
262 | * of patent rights can be found in the PATENTS file in the same directory.
263 | *
264 | * @providesModule fixedDataTableCellGroup
265 | */
266 | .fixedDataTableCellGroup_cellGroup {
267 | -webkit-backface-visibility: hidden;
268 | backface-visibility: hidden;
269 | left: 0;
270 | overflow: hidden;
271 | position: absolute;
272 | top: 0;
273 | white-space: nowrap; }
274 |
275 | .fixedDataTableCellGroup_cellGroup > .public_fixedDataTableCell_main {
276 | display: inline-block;
277 | vertical-align: top;
278 | white-space: normal; }
279 |
280 | .fixedDataTableCellGroup_cellGroupWrapper {
281 | position: absolute;
282 | top: 0; }
283 |
284 | /**
285 | * Copyright (c) 2015, Facebook, Inc.
286 | * All rights reserved.
287 | *
288 | * This source code is licensed under the BSD-style license found in the
289 | * LICENSE file in the root directory of this source tree. An additional grant
290 | * of patent rights can be found in the PATENTS file in the same directory.
291 | *
292 | * @providesModule fixedDataTableColumnResizerLine
293 | */
294 | .fixedDataTableColumnResizerLine_mouseArea {
295 | cursor: ew-resize;
296 | position: absolute;
297 | right: -5px;
298 | width: 12px; }
299 |
300 | .fixedDataTableColumnResizerLine_main {
301 | border-right: 1px solid #0284ff;
302 | box-sizing: border-box;
303 | position: absolute;
304 | z-index: 10; }
305 |
306 | .fixedDataTableColumnResizerLine_hiddenElem {
307 | display: none !important; }
308 |
309 | /**
310 | * Copyright (c) 2015, Facebook, Inc.
311 | * All rights reserved.
312 | *
313 | * This source code is licensed under the BSD-style license found in the
314 | * LICENSE file in the root directory of this source tree. An additional grant
315 | * of patent rights can be found in the PATENTS file in the same directory.
316 | *
317 | * @providesModule fixedDataTableRow
318 | */
319 | .public_fixedDataTableRow_main {
320 | background-color: #fff;
321 | box-sizing: border-box;
322 | overflow: hidden;
323 | position: absolute;
324 | top: 0; }
325 |
326 | .fixedDataTableRow_body {
327 | left: 0;
328 | position: absolute;
329 | top: 0; }
330 |
331 | .public_fixedDataTableRow_highlighted, .public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main {
332 | background-color: #f6f7f8; }
333 |
334 | .fixedDataTableRow_fixedColumnsDivider {
335 | -webkit-backface-visibility: hidden;
336 | backface-visibility: hidden;
337 | border-left: solid 1px #d3d3d3;
338 | left: 0;
339 | position: absolute;
340 | top: 0;
341 | width: 0; }
342 |
343 | .fixedDataTableRow_columnsShadow {
344 | background: 0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==) repeat-y;
345 | width: 4px; }
346 |
347 | .fixedDataTableRow_rowWrapper {
348 | position: absolute;
349 | top: 0; }
350 |
351 | body, #client {
352 | max-height: 100%;
353 | height: 100%;
354 | max-width: 100%;
355 | width: 100%;
356 | position: fixed; }
357 |
--------------------------------------------------------------------------------