diff --git a/__gulpfile.js b/__gulpfile.js deleted file mode 100644 index 0065cde..0000000 --- a/__gulpfile.js +++ /dev/null @@ -1,164 +0,0 @@ -var gulp = require('gulp'), - runSequence = require('run-sequence').use(gulp) - del = require('del'), - fs = require('fs'), - jest = require('jest-cli'), - g = require('gulp-load-plugins')({ - scope: ['dependencies', 'devDependencies', 'peerDependencies'], - rename : { - 'gulp-pure-cjs' : 'pure', - 'gulp-uglifyjs' : 'uglify' - }}); - -var config = { - build : { - js : './cjs', - umd : './umd', - fileName : 'rtable.js', - minFileName : 'rtable.min.js' - }, - - jsxSource : './jsx/**/**.js', - umdSource : './cjs/**/**.js', - distSource : './umd/**/**.js', - testSource : './tests/**/**.spec.js', - - dist : './dist', - exports: 'RTable', - sourceMap : true, - port : 1234, - dependencies: [ - {name: 'react', exports: 'React'}, - {name: 'pubsub-js', exports : 'PubSub'} - ] -}; - - -// Umd options -var options = { - input: config.build.js +'/' +config.build.fileName, - output: config.build.fileName, - exports: config.exports, - map: false, - comments : true, - external : { - react : {amd : 'react', global : 'React'}, - 'pubsub-js' : {amd : 'pubsub-js', global : 'PubSub'} - } -}; - -gulp.task('clean', ['react-clean', 'umd-clean', 'dist-clean']); - -gulp.task('build', function(){ - runSequence('react', 'umd', 'dist'); -}); - -gulp.task('watch', function () { - var reactWatch = register(config.jsxSource, ['react']); - var umdWatch = register(config.umdSource, ['umd', 'dist']); -}); - -gulp.task('default', ['build','watch']); - -gulp.task('dist-clean', function(){ - del(config.dist); -}); - -gulp.task('dist', function(){ - return gulp.src(config.build.umd +"/"+config.build.fileName) - .pipe(g.uglify(config.build.minFileName, - { - outSourceMap : config.sourceMap - })) - .pipe(gulp.dest(config.dist)); -}); - -/** React **/ -gulp.task('react', function(){ - return gulp.src(config.jsxSource) - .pipe(g.plumber({errorHandler: g.notify.onError("Error: <%= error.message %> ")})) - .pipe(g.react()) - .pipe(gulp.dest(config.build.js)) - .on('error', g.notify.onError("Error: <%= error.message %>")); -}); - -gulp.task('react-clean', function(){ - del(config.build.js); -}); - -/** Test **/ - -gulp.task('jest', function () { - return gulp.src(__dirname).pipe( - g.jest({ - //scriptPreprocessor: "./tests/support/preprocessor.js", - unmockedModulePathPatterns: [ - "react" - ], - testDirectoryName: "tests", - testPathIgnorePatterns: [ - "node_modules", - "tests/support" - ], - moduleFileExtensions: [ - "js", - "json", - "react" - ] - })); -}); - -gulp.task('watch-test',function(){ - var watch = register([config.testSource, config.jsxSource],['jest']); -}); - -/** UMD **/ -gulp.task('umd-clean', function(){ - del(config.build.umd);; -}); - -gulp.task('umd', function () { - //needs umd folder to exist - if (!fs.existsSync(config.build.umd)){ - fs.mkdirSync(config.build.umd); - } - - return gulp.src(config.build.js +'/' +config.build.fileName) - .pipe(g.plumber({errorHandler: g.notify.onError("Error: <%= error.message %> ")})) - .pipe(g.pure(options)) - .pipe(gulp.dest(config.build.umd)) - .pipe(gulp.dest(config.dist)) - .on('error', g.notify.onError("Error: <%= error.message %>"));; -}); - -//linter - -gulp.task('lint', ['react'], function(){ - return gulp.src(config.umdSource) - .pipe(g.jshint()) - .pipe(g.jshint.reporter(g.stylish)); -}); - -//functions - -function register(path, tasks){ - var watch = gulp.watch(path,{}, tasks, function(event) { - console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); - }); - - watch.on('ready', function(watcher){ - console.log('ready to watch path: ' + path); - }); - - watch.on('change', function(event) { - console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); - }); - - watch.on('error', function(error){ - console.log("Error: <%= error.message %> "); - g.notify.onError("Error: <%= error.message %> "); - }); - - return watch; -} - diff --git a/cjs/PropRenderMixin.js b/cjs/PropRenderMixin.js new file mode 100644 index 0000000..2d2f428 --- /dev/null +++ b/cjs/PropRenderMixin.js @@ -0,0 +1,41 @@ +/* + +Provides comparation of old and new properties for shouldComponentUpdate method by using JSON.strinify comparation. +This provides deep comparation for properties with arrays and objects. + +NOTE ANY METHODs will be ignored +NOTE ORDER MATTERS {a :'1', b : '2'} will be FALSE to {b : '2', a : '1'} + +Author : Dmytro Lebedynskyi + +Why ? + +If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), + you can use this mixin for a performance boost in some cases. + + */ +var PropRenderMixin = { + componentWillMount: function() { + this.shouldUpdate = true; + this.oldProps = null; + }, + componentWillReceiveProps : function(newProps){ + var shouldUpdate = true, + newPropsStr = null; + + if (this.props.optimization){ + newPropsStr = JSON.stringify(newProps); + shouldUpdate = this.oldProps !== newPropsStr; + } + this.shouldUpdate = shouldUpdate; + + this.oldProps = newPropsStr; + }, + shouldComponentUpdate : function(newProps, newState){ + return this.shouldUpdate; + } +}; + +module.exports = PropRenderMixin; + + diff --git a/cjs/RTable.js b/cjs/RTable.js new file mode 100644 index 0000000..4f58c9c --- /dev/null +++ b/cjs/RTable.js @@ -0,0 +1,154 @@ +/** + * @jsx React.DOM + */ +var React = require('react'), + pubsub = require('pubsub-js'), + RTableHeaderCell = require('./RTableHeaderCell'), + RTableFilterCell = require('./RTableFilterCell'), + RTableSelectCell = require('./RTableSelectCell'), + RTableCell = require('./RTableCell'); + +var RTable = { + displayName : 'RTable', + getDefaultProps : function () { + return { + data : [], + definitions : [], + dataProp : '.', + columnFieldValueProp : 'field', + columnNameProp : 'name', + enableFilters : true, + enableSelection : true, + classes : 'rtable', + optimization : true, + fixedHeader : false + }; + }, + tableScroll : function(e){ + this.refs.rHeader.getDOMNode().style.width = this.refs.rTable.getDOMNode().clientWidth + this.refs.rTable.getDOMNode().scrollLeft + 'px'; + this.refs.rBody.getDOMNode().style.width = this.refs.rTable.getDOMNode().clientWidth + this.refs.rTable.getDOMNode().scrollLeft + 'px'; + }, + componentDidMount : function() { + pubsub.publish('RTable.Mounted', null); + + if (this.props.fixedHeader){ + this.refs.rTable.getDOMNode() + .addEventListener('scroll', this.tableScroll); + } + }, + componentWillUpdate : function(){ + pubsub.publish('RTable.BeforeUpdated', null); + }, + componentDidUpdate : function () { + pubsub.publish('RTable.Updated', null); + }, + componentWillUnmount : function(){ + pubsub.publish('RTable.Unmounted', null); + //clean up. + pubsub.unsubscribe('RTable.Mounted'); + pubsub.unsubscribe('RTable.Updated'); + pubsub.unsubscribe('RTable.BeforeUpdated'); + pubsub.unsubscribe('RTable.Unmounted'); + + this.refs.rTable.getDOMNode() + .removeEventListener('scroll', this.tableScroll); + }, + propTypes : { + //Definitions for columns + definitions : React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.string), + React.PropTypes.arrayOf(React.PropTypes.object)]), + //Data objects + data : React.PropTypes.arrayOf(React.PropTypes.object), + //Nested property name of each item in data array where to look for column values. Otherwise root object will be used. + dataProp : React.PropTypes.string, + //Property that will be looked for in each column object to use as property name to look for in data item. + columnFieldValueProp : React.PropTypes.string, + //Property that will be looked for in each column object to use as column title. + columnNameProp : React.PropTypes.string, + //should show filters + enableFilters : React.PropTypes.bool, + //should show row selection checkboxes + enableSelection : React.PropTypes.bool, + //css class names to be added + classes : React.PropTypes.string, + //optimization flag. Default is true. Uses memory + optimization : React.PropTypes.bool, + //should table apply fixed header and only body content scrolling + fixedHeader : React.PropTypes.bool + }, + render : function(){ + var theadRows = [], + headers = [], + filters = [], + colGroups = [], + rows = [], + classNames = 'rtable '; + + classNames += this.props.fixedHeader ? ' rtable-fixed-header ' : ''; + classNames += this.props.classes; + + if (this.props.data.length){ + this.renderSelectionColumn(colGroups, headers, filters); + + for (var i = 0; i < this.props.definitions.length; i++) { + //col groups + colGroups.push(React.createElement("col", {key: 'col_'+i, className: 'rtable-col rtable-col-'+i})); + //headers + headers.push(React.createElement(RTableHeaderCell, {key: 'header_cell_'+i, + definition: this.props.definitions[i], + columnNameProp: this.props.columnNameProp})); + //filters + filters.push(React.createElement(RTableFilterCell, {key: 'filter_cell' + i, + definition: this.props.definitions[i]})); + //rows + this.renderColumn(rows, i); + } + + theadRows.push(React.createElement("tr", {key: "rTableHeaderRow"}, headers)); + + if (this.props.enableFilters){ + theadRows.push(React.createElement("tr", {key: "rtableFilterRow"}, filters)); + } + } + + return (React.createElement("table", {className: classNames, ref: "rTable"}, + + React.createElement("colgroup", null, colGroups), + React.createElement("thead", {ref: "rHeader"}, theadRows), + React.createElement("tbody", {ref: "rBody"}, rows) + + )); + }, + getInitialRow : function(rowIndex, data){ + var arr = []; + if (this.props.enableSelection){ + arr.push(React.createElement(RTableSelectCell, {key: 'row_'+rowIndex+'_select', data: data})); + } + return arr; + }, + renderColumn : function(rows, columnIndex){ + for (var j = 0; j < this.props.data.length; j++) { + var row = rows[j] = rows[j] || (React.createElement("tr", {key: 'row_'+j})); + var cells = row.props.children = row.props.children || this.getInitialRow(j, this.props.data[j]); + cells.push(React.createElement(RTableCell, {key: 'row_'+j+'_cell_'+columnIndex, + data: this.props.data[j], + definition: this.props.definitions[columnIndex], + columnFieldValueProp: this.props.columnFieldValueProp, + dataProp: this.props.dataProp, + optimization: this.props.optimization})); + } + }, + renderSelectionColumn : function(cols, headers, filters){ + if (this.props.enableSelection){ + cols.push(React.createElement("col", {key: "col_selection", className: "rtable-col rtable-selection"})); + headers.push(React.createElement("th", {key: "header_cell_selection", className: "rtable-selection rtable-column-header"})); + filters.push(React.createElement("th", {key: "filter_cell_selection", className: "rtable-selection rtable-column-filter"})); + } + } +}; + +module.exports = { + class : RTable, + Component : React.createClass(RTable) +}; diff --git a/cjs/RTableCell.js b/cjs/RTableCell.js new file mode 100644 index 0000000..9804549 --- /dev/null +++ b/cjs/RTableCell.js @@ -0,0 +1,57 @@ +/** + * @jsx React.DOM + */ +var React = require('react'), + utils = require('./utils'), + PropRenderMixin = require('./PropRenderMixin'); + +var RTableCell = React.createClass({ + mixins: [PropRenderMixin], + displayName : 'RTableCell', + getDefaultProps : function(){ + return { + data : {}, + definition : {}, + columnFieldValueProp : 'field', + dataProp : '.', + optimization : true + }; + }, + propTypes : { + //Nested property name of each item in data array where to look for column values. Otherwise root object will be used. + dataProp : React.PropTypes.string, + //Property that will be looked for in each column object to use as property name to look for in data item. + columnFieldValueProp : React.PropTypes.string, + //Definition for column + definition : React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.object]), + //Data object. will use dataProp to look for display values. Value will be taken based on columnFieldValueProp value of definition object + data : React.PropTypes.object, + //optimisation flag. Default is true. Uses memory + optimization : React.PropTypes.bool + }, + render : function(){ + var def = null, + dataObj = null; + + if (typeof this.props.definition === 'object') { + if (!this.props.columnFieldValueProp || + !this.props.definition.hasOwnProperty(this.props.columnFieldValueProp)){ + utils.warn('definition property was not found on definition object', this.props.definition, this.props.columnFieldValueProp); + } + def = this.props.definition[this.props.columnFieldValueProp]; + } else { def = this.props.definition; } + + if ('.' !== this.props.dataProp){ + if (!this.props.data.hasOwnProperty(this.props.dataProp)){ + utils.warn('could not find data propety on object', this.props.data, this.props.dataProp); + } + dataObj = this.props.data[this.props.dataProp]; + } else {dataObj = this.props.data;} + + return (React.createElement("td", {className: "rtable-column-body"}, dataObj[def])); + } + }); + +module.exports = RTableCell; diff --git a/cjs/RTableFilterCell.js b/cjs/RTableFilterCell.js new file mode 100644 index 0000000..11adde5 --- /dev/null +++ b/cjs/RTableFilterCell.js @@ -0,0 +1,40 @@ +/** + * @jsx React.DOM + */ +var React = require('react'), + pubsub = require('pubsub-js'); + +var RTableFilterCell = React.createClass({ + displayName : 'RTableFilterCell', + getInitialState : function(){ + return { filter : null}; + }, + getDefaultProps : function () { + return { + definition : {} + }; + }, + propTypes : { + //definitions for table filter row + definition : React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.object]) + }, + handleChange : function (e){ + pubsub.publish('RTable.FilterChange', + { + definition : this.props.definition, + value : e.target.value + }); + + this.setState({definition : e.target.value}); + }, + componentWillUnmount : function(){ + pubsub.unsubscribe('RTable.FilterChange'); + }, + render : function(){ + return (React.createElement("th", {className: "rtable-column-filter"}, React.createElement("input", {type: "text", value: this.state.filter, onChange: this.handleChange}))); + } + }); + +module.exports = RTableFilterCell; diff --git a/cjs/RTableHeaderCell.js b/cjs/RTableHeaderCell.js new file mode 100644 index 0000000..3ec0944 --- /dev/null +++ b/cjs/RTableHeaderCell.js @@ -0,0 +1,35 @@ +/** + * @jsx React.DOM + */ +var React = require('react'), + utils = require('./utils'); + +var RTableHeaderCell = React.createClass({ + displayName : 'RTableHeaderCell', + getDefaultProps : function () { + return { + definition : {}, + columnNameProp : 'name' + }; + }, + propTypes : { + //definitions for table header row + definition : React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]), + //Property that will be looked for in each column object to use as column title. + columnNameProp : React.PropTypes.string + }, + render : function(){ + var header = null; + if (typeof this.props.definition === 'object') { + if (!this.props.columnNameProp || + !this.props.definition.hasOwnProperty(this.props.columnNameProp)){ + utils.warn('Header Name property was not found on definition object', this.props.definition, this.props.columnNameProp); + } + header = this.props.definition[this.props.columnNameProp]; + } else { header = this.props.definition; } + + return (React.createElement("th", {className: "rtable-column-header"}, header)); + } + }); + +module.exports = RTableHeaderCell; diff --git a/cjs/RTableSelectCell.js b/cjs/RTableSelectCell.js new file mode 100644 index 0000000..646c895 --- /dev/null +++ b/cjs/RTableSelectCell.js @@ -0,0 +1,37 @@ +/** + * @jsx React.DOM + */ +var React = require('react'), + pubsub = require('pubsub-js'); + +var RTableSelectCell = React.createClass({ + displayName : 'RTableSelectCell', + getInitialState : function(){ + return { isChecked : false}; + }, + getDefaultProps : function () { + return { + data : {} + }; + }, + propTypes : { + //Data object. will use dataProp to look for display values. Value will be taken based on columnFieldValueProp value of definition object + data : React.PropTypes.object + }, + onChange : function(e){ + var checked = !this.state.isChecked; + pubsub.publish('RTable.RowChecked', + { + data : this.props.data, + value : checked + }); + this.setState({isChecked: checked}); + }, + render : function(){ + return (React.createElement("td", {className: "rtable-selection rtable-column-body"}, React.createElement("input", {type: "checkbox", checked: this.state.isChecked, onChange: this.onChange}))); + }, + componentWillUnmount : function(){ + pubsub.unsubscribe('RTable.RowSelected'); + }}); + +module.exports = RTableSelectCell; diff --git a/cjs/utils.js b/cjs/utils.js new file mode 100644 index 0000000..78a5132 --- /dev/null +++ b/cjs/utils.js @@ -0,0 +1,18 @@ +var utils = {}; +utils.stringify = function(oldObj){ + return JSON.stringify(oldObj); +}; + +utils.cloneProps = function(oldObj){ + return JSON.parse(JSON.stringify(oldObj)); +}; + +utils.equalProps = function(oldObj, newObj){ + return JSON.stringify(oldObj) === JSON.stringify(newObj); +}; + +utils.warn = function(){ + if (console){console.warn(arguments);} +}; + +module.exports = utils; \ No newline at end of file diff --git a/css/styles.min.css b/css/styles.min.css new file mode 100644 index 0000000..ad1ccae --- /dev/null +++ b/css/styles.min.css @@ -0,0 +1 @@ +.rtable .rtable-selection{min-width:25px;max-width:25px;width:25px}.rtable-fixed-header{width:100%;overflow-x:scroll;display:block}.rtable-fixed-header tbody,.rtable-fixed-header thead{display:block}.rtable-fixed-header tbody{overflow-y:scroll;overflow-x:hidden;height:500px}.rtable-fixed-header td,.rtable-fixed-header th{height:25px;min-width:150px;width:150px}.rtable-fixed-header .rtable-column-filter input{width:95%} \ No newline at end of file diff --git a/dist/rtable.js b/dist/rtable.js index bb45b91..2f54e07 100644 --- a/dist/rtable.js +++ b/dist/rtable.js @@ -29,368 +29,7 @@ return module.exports; } _require.cache = []; - _require.modules = [ - function (module, exports) { - /* - -Provides comparation of old and new properties for shouldComponentUpdate method by using JSON.strinify comparation. -This provides deep comparation for properties with arrays and objects. - -NOTE ANY METHODs will be ignored -NOTE ORDER MATTERS {a :'1', b : '2'} will be FALSE to {b : '2', a : '1'} - -Author : Dmytro Lebedynskyi - -Why ? - -If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), - you can use this mixin for a performance boost in some cases. - - */ - var PropRenderMixin = { - componentWillMount: function () { - this.shouldUpdate = true; - this.oldProps = null; - }, - componentWillReceiveProps: function (newProps) { - var shouldUpdate = true, newPropsStr = null; - if (this.props.optimization) { - newPropsStr = JSON.stringify(newProps); - shouldUpdate = this.oldProps !== newPropsStr; - } - this.shouldUpdate = shouldUpdate; - this.oldProps = newPropsStr; - }, - shouldComponentUpdate: function (newProps, newState) { - return this.shouldUpdate; - } - }; - module.exports = PropRenderMixin; - }, - function (module, exports) { - /** - * @jsx React.DOM - */ - var React = _require(8), utils = _require(6), PropRenderMixin = _require(0); - var RTableCell = React.createClass({ - mixins: [PropRenderMixin], - displayName: 'RTableCell', - getDefaultProps: function () { - return { - data: {}, - definition: {}, - columnFieldValueProp: 'field', - dataProp: '.', - optimization: true - }; - }, - propTypes: { - //Nested property name of each item in data array where to look for column values. Otherwise root object will be used. - dataProp: React.PropTypes.string, - //Property that will be looked for in each column object to use as property name to look for in data item. - columnFieldValueProp: React.PropTypes.string, - //Definition for column - definition: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.object - ]), - //Data object. will use dataProp to look for display values. Value will be taken based on columnFieldValueProp value of definition object - data: React.PropTypes.object, - //optimisation flag. Default is true. Uses memory - optimization: React.PropTypes.bool - }, - render: function () { - var def = null, dataObj = null; - if (typeof this.props.definition === 'object') { - if (!this.props.columnFieldValueProp || !this.props.definition.hasOwnProperty(this.props.columnFieldValueProp)) { - utils.warn('definition property was not found on definition object', this.props.definition, this.props.columnFieldValueProp); - } - def = this.props.definition[this.props.columnFieldValueProp]; - } else { - def = this.props.definition; - } - if ('.' !== this.props.dataProp) { - if (!this.props.data.hasOwnProperty(this.props.dataProp)) { - utils.warn('could not find data propety on object', this.props.data, this.props.dataProp); - } - dataObj = this.props.data[this.props.dataProp]; - } else { - dataObj = this.props.data; - } - return React.createElement('td', { className: 'rtable-column-body' }, dataObj[def]); - } - }); - module.exports = RTableCell; - }, - function (module, exports) { - /** - * @jsx React.DOM - */ - var React = _require(8), pubsub = _require(7); - var RTableFilterCell = React.createClass({ - displayName: 'RTableFilterCell', - getInitialState: function () { - return { filter: null }; - }, - getDefaultProps: function () { - return { definition: {} }; - }, - propTypes: { - //definitions for table filter row - definition: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.object - ]) - }, - handleChange: function (e) { - pubsub.publish('RTable.FilterChange', { - definition: this.props.definition, - value: e.target.value - }); - this.setState({ definition: e.target.value }); - }, - componentWillUnmount: function () { - pubsub.unsubscribe('RTable.FilterChange'); - }, - render: function () { - return React.createElement('th', { className: 'rtable-column-filter' }, React.createElement('input', { - type: 'text', - value: this.state.filter, - onChange: this.handleChange - })); - } - }); - module.exports = RTableFilterCell; - }, - function (module, exports) { - /** - * @jsx React.DOM - */ - var React = _require(8), utils = _require(6); - var RTableHeaderCell = React.createClass({ - displayName: 'RTableHeaderCell', - getDefaultProps: function () { - return { - definition: {}, - columnNameProp: 'name' - }; - }, - propTypes: { - //definitions for table header row - definition: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.object - ]), - //Property that will be looked for in each column object to use as column title. - columnNameProp: React.PropTypes.string - }, - render: function () { - var header = null; - if (typeof this.props.definition === 'object') { - if (!this.props.columnNameProp || !this.props.definition.hasOwnProperty(this.props.columnNameProp)) { - utils.warn('Header Name property was not found on definition object', this.props.definition, this.props.columnNameProp); - } - header = this.props.definition[this.props.columnNameProp]; - } else { - header = this.props.definition; - } - return React.createElement('th', { className: 'rtable-column-header' }, header); - } - }); - module.exports = RTableHeaderCell; - }, - function (module, exports) { - /** - * @jsx React.DOM - */ - var React = _require(8), pubsub = _require(7); - var RTableSelectCell = React.createClass({ - displayName: 'RTableSelectCell', - getInitialState: function () { - return { isChecked: false }; - }, - getDefaultProps: function () { - return { data: {} }; - }, - propTypes: { - //Data object. will use dataProp to look for display values. Value will be taken based on columnFieldValueProp value of definition object - data: React.PropTypes.object - }, - onChange: function (e) { - var checked = !this.state.isChecked; - pubsub.publish('RTable.RowChecked', { - data: this.props.data, - value: checked - }); - this.setState({ isChecked: checked }); - }, - render: function () { - return React.createElement('td', { className: 'rtable-selection rtable-column-body' }, React.createElement('input', { - type: 'checkbox', - checked: this.state.isChecked, - onChange: this.onChange - })); - }, - componentWillUnmount: function () { - pubsub.unsubscribe('RTable.RowSelected'); - } - }); - module.exports = RTableSelectCell; - }, - function (module, exports) { - /** - * @jsx React.DOM - */ - var React = _require(8), pubsub = _require(7), RTableHeaderCell = _require(3), RTableFilterCell = _require(2), RTableSelectCell = _require(4), RTableCell = _require(1); - var RTable = { - displayName: 'RTable', - getDefaultProps: function () { - return { - data: [], - definitions: [], - dataProp: '.', - columnFieldValueProp: 'field', - columnNameProp: 'name', - enableFilters: true, - enableSelection: true, - classes: 'rtable', - optimization: true, - fixedHeader: false - }; - }, - tableScroll: function (e) { - this.refs.rHeader.getDOMNode().style.width = this.refs.rTable.getDOMNode().clientWidth + this.refs.rTable.getDOMNode().scrollLeft + 'px'; - this.refs.rBody.getDOMNode().style.width = this.refs.rTable.getDOMNode().clientWidth + this.refs.rTable.getDOMNode().scrollLeft + 'px'; - }, - componentDidMount: function () { - pubsub.publish('RTable.Mounted', null); - if (this.props.fixedHeader) { - this.refs.rTable.getDOMNode().addEventListener('scroll', this.tableScroll); - } - }, - componentWillUpdate: function () { - pubsub.publish('RTable.BeforeUpdated', null); - }, - componentDidUpdate: function () { - pubsub.publish('RTable.Updated', null); - }, - componentWillUnmount: function () { - pubsub.publish('RTable.Unmounted', null); //clean up - //clean up - pubsub.unsubscribe('RTable.Mounted'); - pubsub.unsubscribe('RTable.Updated'); - pubsub.unsubscribe('RTable.BeforeUpdated'); - pubsub.unsubscribe('RTable.Unmounted'); - this.refs.rTable.getDOMNode().removeEventListener('scroll', this.tableScroll); - }, - propTypes: { - //Definitions for columns - definitions: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.string), - React.PropTypes.arrayOf(React.PropTypes.object) - ]), - //Data objects - data: React.PropTypes.arrayOf(React.PropTypes.object), - //Nested property name of each item in data array where to look for column values. Otherwise root object will be used. - dataProp: React.PropTypes.string, - //Property that will be looked for in each column object to use as property name to look for in data item. - columnFieldValueProp: React.PropTypes.string, - //Property that will be looked for in each column object to use as column title. - columnNameProp: React.PropTypes.string, - //should show filters - enableFilters: React.PropTypes.bool, - //should show row selection checkboxes - enableSelection: React.PropTypes.bool, - //css class names to be added - classes: React.PropTypes.string, - //optimization flag. Default is true. Uses memory - optimization: React.PropTypes.bool, - //should table apply fixed header and only body content scrolling - fixedHeader: React.PropTypes.bool - }, - render: function () { - var theadRows = [], headers = [], filters = [], colGroups = [], rows = [], classNames = 'rtable '; - classNames += this.props.fixedHeader ? ' rtable-fixed-header ' : ''; - classNames += this.props.classes; - if (this.props.data.length) { - this.renderSelectionColumn(colGroups, headers, filters); - for (var i = 0; i < this.props.definitions.length; i++) { - //col groups - colGroups.push(React.createElement('col', { - key: 'col_' + i, - className: 'rtable-col rtable-col-' + i - })); //headers - //headers - headers.push(React.createElement(RTableHeaderCell, { - key: 'header_cell_' + i, - definition: this.props.definitions[i], - columnNameProp: this.props.columnNameProp - })); //filters - //filters - filters.push(React.createElement(RTableFilterCell, { - key: 'filter_cell' + i, - definition: this.props.definitions[i] - })); //rows - //rows - this.renderColumn(rows, i); - } - theadRows.push(React.createElement('tr', { key: 'rTableHeaderRow' }, headers)); - if (this.props.enableFilters) { - theadRows.push(React.createElement('tr', { key: 'rtableFilterRow' }, filters)); - } - } - return React.createElement('table', { - className: classNames, - ref: 'rTable' - }, React.createElement('colgroup', null, colGroups), React.createElement('thead', { ref: 'rHeader' }, theadRows), React.createElement('tbody', { ref: 'rBody' }, rows)); - }, - getInitialRow: function (rowIndex, data) { - var arr = []; - if (this.props.enableSelection) { - arr.push(React.createElement(RTableSelectCell, { - key: 'row_' + rowIndex + '_select', - data: data - })); - } - return arr; - }, - renderColumn: function (rows, columnIndex) { - for (var j = 0; j < this.props.data.length; j++) { - var row = rows[j] = rows[j] || React.createElement('tr', { key: 'row_' + j }); - var cells = row.props.children = row.props.children || this.getInitialRow(j, this.props.data[j]); - cells.push(React.createElement(RTableCell, { - key: 'row_' + j + '_cell_' + columnIndex, - data: this.props.data[j], - definition: this.props.definitions[columnIndex], - columnFieldValueProp: this.props.columnFieldValueProp, - dataProp: this.props.dataProp, - optimization: this.props.optimization - })); - } - }, - renderSelectionColumn: function (cols, headers, filters) { - if (this.props.enableSelection) { - cols.push(React.createElement('col', { - key: 'col_selection', - className: 'rtable-col rtable-selection' - })); - headers.push(React.createElement('th', { - key: 'header_cell_selection', - className: 'rtable-selection rtable-column-header' - })); - filters.push(React.createElement('th', { - key: 'filter_cell_selection', - className: 'rtable-selection rtable-column-filter' - })); - } - } - }; - module.exports = { - class: RTable, - Component: React.createClass(RTable) - }; - }, - function (module, exports) { + _require.modules = [function (module, exports) { var utils = {}; utils.stringify = function (oldObj) { return JSON.stringify(oldObj); @@ -407,13 +46,6 @@ If your React component's render function is "pure" (in other words, it renders } }; module.exports = utils; - }, - function (module, exports) { - module.exports = __external_PubSub; - }, - function (module, exports) { - module.exports = __external_React; - } - ]; - return _require(5); + }]; + return _require(0); })); \ No newline at end of file diff --git a/dist/rtable.min.js b/dist/rtable.min.js index 4d8bd18..20d64eb 100644 --- a/dist/rtable.min.js +++ b/dist/rtable.min.js @@ -1,2 +1,2 @@ -!function(a){"function"==typeof define&&define.amd?define(["react","pubsub-js"],a):"object"==typeof exports?module.exports=a(require("react"),require("pubsub-js")):this.RTable=a(React,PubSub)}(function(a,b){function c(a){var b=c.cache[a];if(!b){var d={};b=c.cache[a]={id:a,exports:d},c.modules[a].call(d,b,d)}return b.exports}return c.cache=[],c.modules=[function(a){var b={componentWillMount:function(){this.shouldUpdate=!0,this.oldProps=null},componentWillReceiveProps:function(a){var b=!0,c=null;this.props.optimization&&(c=JSON.stringify(a),b=this.oldProps!==c),this.shouldUpdate=b,this.oldProps=c},shouldComponentUpdate:function(){return this.shouldUpdate}};a.exports=b},function(a){var b=c(8),d=c(6),e=c(0),f=b.createClass({mixins:[e],displayName:"RTableCell",getDefaultProps:function(){return{data:{},definition:{},columnFieldValueProp:"field",dataProp:".",optimization:!0}},propTypes:{dataProp:b.PropTypes.string,columnFieldValueProp:b.PropTypes.string,definition:b.PropTypes.oneOfType([b.PropTypes.string,b.PropTypes.object]),data:b.PropTypes.object,optimization:b.PropTypes.bool},render:function(){var a=null,c=null;return"object"==typeof this.props.definition?(this.props.columnFieldValueProp&&this.props.definition.hasOwnProperty(this.props.columnFieldValueProp)||d.warn("definition property was not found on definition object",this.props.definition,this.props.columnFieldValueProp),a=this.props.definition[this.props.columnFieldValueProp]):a=this.props.definition,"."!==this.props.dataProp?(this.props.data.hasOwnProperty(this.props.dataProp)||d.warn("could not find data propety on object",this.props.data,this.props.dataProp),c=this.props.data[this.props.dataProp]):c=this.props.data,b.createElement("td",{className:"rtable-column-body"},c[a])}});a.exports=f},function(a){var b=c(8),d=c(7),e=b.createClass({displayName:"RTableFilterCell",getInitialState:function(){return{filter:null}},getDefaultProps:function(){return{definition:{}}},propTypes:{definition:b.PropTypes.oneOfType([b.PropTypes.string,b.PropTypes.object])},handleChange:function(a){d.publish("RTable.FilterChange",{definition:this.props.definition,value:a.target.value}),this.setState({definition:a.target.value})},componentWillUnmount:function(){d.unsubscribe("RTable.FilterChange")},render:function(){return b.createElement("th",{className:"rtable-column-filter"},b.createElement("input",{type:"text",value:this.state.filter,onChange:this.handleChange}))}});a.exports=e},function(a){var b=c(8),d=c(6),e=b.createClass({displayName:"RTableHeaderCell",getDefaultProps:function(){return{definition:{},columnNameProp:"name"}},propTypes:{definition:b.PropTypes.oneOfType([b.PropTypes.string,b.PropTypes.object]),columnNameProp:b.PropTypes.string},render:function(){var a=null;return"object"==typeof this.props.definition?(this.props.columnNameProp&&this.props.definition.hasOwnProperty(this.props.columnNameProp)||d.warn("Header Name property was not found on definition object",this.props.definition,this.props.columnNameProp),a=this.props.definition[this.props.columnNameProp]):a=this.props.definition,b.createElement("th",{className:"rtable-column-header"},a)}});a.exports=e},function(a){var b=c(8),d=c(7),e=b.createClass({displayName:"RTableSelectCell",getInitialState:function(){return{isChecked:!1}},getDefaultProps:function(){return{data:{}}},propTypes:{data:b.PropTypes.object},onChange:function(){var a=!this.state.isChecked;d.publish("RTable.RowChecked",{data:this.props.data,value:a}),this.setState({isChecked:a})},render:function(){return b.createElement("td",{className:"rtable-selection rtable-column-body"},b.createElement("input",{type:"checkbox",checked:this.state.isChecked,onChange:this.onChange}))},componentWillUnmount:function(){d.unsubscribe("RTable.RowSelected")}});a.exports=e},function(a){var b=c(8),d=c(7),e=c(3),f=c(2),g=c(4),h=c(1),i={displayName:"RTable",getDefaultProps:function(){return{data:[],definitions:[],dataProp:".",columnFieldValueProp:"field",columnNameProp:"name",enableFilters:!0,enableSelection:!0,classes:"rtable",optimization:!0,fixedHeader:!1}},tableScroll:function(){this.refs.rHeader.getDOMNode().style.width=this.refs.rTable.getDOMNode().clientWidth+this.refs.rTable.getDOMNode().scrollLeft+"px",this.refs.rBody.getDOMNode().style.width=this.refs.rTable.getDOMNode().clientWidth+this.refs.rTable.getDOMNode().scrollLeft+"px"},componentDidMount:function(){d.publish("RTable.Mounted",null),this.props.fixedHeader&&this.refs.rTable.getDOMNode().addEventListener("scroll",this.tableScroll)},componentWillUpdate:function(){d.publish("RTable.BeforeUpdated",null)},componentDidUpdate:function(){d.publish("RTable.Updated",null)},componentWillUnmount:function(){d.publish("RTable.Unmounted",null),d.unsubscribe("RTable.Mounted"),d.unsubscribe("RTable.Updated"),d.unsubscribe("RTable.BeforeUpdated"),d.unsubscribe("RTable.Unmounted"),this.refs.rTable.getDOMNode().removeEventListener("scroll",this.tableScroll)},propTypes:{definitions:b.PropTypes.oneOfType([b.PropTypes.arrayOf(b.PropTypes.string),b.PropTypes.arrayOf(b.PropTypes.object)]),data:b.PropTypes.arrayOf(b.PropTypes.object),dataProp:b.PropTypes.string,columnFieldValueProp:b.PropTypes.string,columnNameProp:b.PropTypes.string,enableFilters:b.PropTypes.bool,enableSelection:b.PropTypes.bool,classes:b.PropTypes.string,optimization:b.PropTypes.bool,fixedHeader:b.PropTypes.bool},render:function(){var a=[],c=[],d=[],g=[],h=[],i="rtable ";if(i+=this.props.fixedHeader?" rtable-fixed-header ":"",i+=this.props.classes,this.props.data.length){this.renderSelectionColumn(g,c,d);for(var j=0;j ")})) .pipe(g.react()) diff --git a/tasks/test.js b/tasks/test.js new file mode 100644 index 0000000..bb96f09 --- /dev/null +++ b/tasks/test.js @@ -0,0 +1,11 @@ +var gulp = require('gulp'), + g = require ('./g'), + config = require('./config'), + fn; + +gulp.task('test', fn = function () { + return gulp.src('.').pipe( + g.jest(config.jest)); +}); + +module.exports = fn; \ No newline at end of file diff --git a/tasks/umd.js b/tasks/umd.js index 9ce054b..a82e812 100644 --- a/tasks/umd.js +++ b/tasks/umd.js @@ -4,16 +4,32 @@ var gulp = require('gulp'), fs = require('fs'), fn; -gulp.task('umd', function () { + + +// Umd options +var options = { + input: config.src.cjsInput, + output: config.dist.fileName, + exports: config.dist.exportName, + map: false, + comments : true, + external : { + react : {amd : 'react', global : 'React'}, + 'pubsub-js' : {amd : 'pubsub-js', global : 'PubSub'} + } +}; + +gulp.task('umd', fn = function () { //needs umd folder to exist - if (!fs.existsSync(config.dist.umd)){ - fs.mkdirSync(config.dist.umd); + if (!fs.existsSync(config.dist.dist)){ + fs.mkdirSync(config.dist.dist); } - return gulp.src(config.build.js +'/' +config.build.fileName) + return gulp.src(config.src.cjs) .pipe(g.plumber({errorHandler: g.notify.onError("Error: <%= error.message %> ")})) .pipe(g.pure(options)) - .pipe(gulp.dest(config.build.umd)) - .pipe(gulp.dest(config.dist)) + .pipe(gulp.dest(config.dist.dist)) .on('error', g.notify.onError("Error: <%= error.message %>"));; -}); \ No newline at end of file +}); + +module.exports = fn; \ No newline at end of file diff --git a/tasks/watch.js b/tasks/watch.js new file mode 100644 index 0000000..361852e --- /dev/null +++ b/tasks/watch.js @@ -0,0 +1,38 @@ +var gulp = require('gulp'), + g = require ('./g'), + config = require('./config'), + fn = {}; + +gulp.task('watch', fn.watch = function(){ + register(config.src.jsx, ['react']); + register(config.src.cjs, ['umd']); +}); + +gulp.task('watch-dev', fn.watchTest = function(){ + register(config.src.cjs, ['test',['lint']]); +}); + + +function register(path, tasks){ + var watch = gulp.watch(path,{}, tasks, function(event) { + console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); + }); + + watch.on('ready', function(watcher){ + console.log('ready to watch path: ' + path); + }); + + watch.on('change', function(event) { + // console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); + }); + + watch.on('error', function(error){ + console.log("Error: <%= error.message %> "); + g.notify.onError("Error: <%= error.message %> "); + }); + + return watch; +} + + +module.exports = fn; \ No newline at end of file