All files ListComponents.js

84.51% Statements 60/71
71.43% Branches 45/63
78.57% Functions 11/14
89.06% Lines 57/64
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158                                        7x 7x 7x       1x       10x 10x 10x 10x 2x       2x 2x 2x 2x 6x 6x 6x                 2x 2x             8x                                       7x 7x 7x 7x     7x 7x       9x 2x   9x 8x         16x 16x 16x 16x       16x 4x 4x 14x 14x 14x 14x 14x     14x       4x   12x 6x   6x                   9x 9x 9x 15x 3x   12x   6x 6x   6x 6x         9x      
/** Sub-components for: List and AjaxList */
import React, { PropTypes } from 'react';
import {devOnly, isEquivalent, shallowCopyExcept} from './utils';
import {_buildElement} from './utils-internal';
 
export class ListPagination extends React.Component {
    static propTypes = {
        onPageChanged: React.PropTypes.func.isRequired,
        id : PropTypes.string.isRequired,
        total : PropTypes.number.isRequired,
        count : PropTypes.number.isRequired,
        page : PropTypes.number.isRequired,
        maxPagesDisplayed : PropTypes.number
    };
 
    static defaultProps = {
        maxPagesDisplayed: 15
    };
 
    constructor(props) {
        super();
        this.props = props;
        this._handlePageChange = this._handlePageChange.bind(this);
    }
 
    _handlePageChange(page) {
        this.props.onPageChanged(page);
    }
 
    render() {
        const self = this;
        Eif (self.props.page != undefined) {
            let pages = Math.ceil(self.props.total / self.props.count);
            if (pages > 1) {
                return (
                    <nav className={`list-pagination ${this.props.className ? this.props.className : ''}`} id={`${self.props.id}-pagination`}>
                        <ul className="pagination">
                            {(() => {
                                const current = self.props.page;
                                let pg = [], skipped = false;
                                pg.push((<li key="pg-prev" className={self.props.page < 2 ? "disabled" : ""} onClick={function() { if (self.props.page > 1) { self._handlePageChange(self.props.page -1) }}}><span>&laquo;</span></li>));
                                for (let p = 1; p <= pages; p++) {
                                    Eif (pages < self.props.maxPagesDisplayed || p < 2 || p > pages-2 || Math.abs(p-current) < 2) {
                                        skipped = false;
                                        pg.push((<li key={`pg-pg-${p}`} className={p == self.props.page ? "active" : ""}
                                                     onClick={function() { if (p != current) { self._handlePageChange(p) }}}><span>{p}</span></li>));
                                    } else {
                                        if (! skipped) {
                                            skipped = true;
                                            pg.push((<li key={`pg-skp-${p}`} className="pg-skp disabled"><span>&hellip;</span></li>));
                                        }
                                    }
                                }
                                pg.push((<li className={pages <= self.props.page ? "disabled" : ""} key="pg-next" onClick={function() { Eif (pages > self.props.page) { self._handlePageChange(self.props.page +1) }}}><span>&raquo;</span></li>));
                                return pg;
                            })()}
                        </ul>
                    </nav>
                );
            }
        }
        return null;
    }
}
 
 
export class SimpleListTable extends React.Component {
    static propTypes = {
        id: React.PropTypes.string.isRequired,
        data: React.PropTypes.any, // object with property items or an array
        renderRow: React.PropTypes.func.isRequired,
        headerAlwaysOn: React.PropTypes.bool.isRequired,
        noDataElement : React.PropTypes.element, // react element
        indexOffset : React.PropTypes.number
    };
 
    static defaultProps = {
        indexOffset : 0
    };
 
    constructor(props) {
        super();
        this.state = {data : props.data};
        this.id = props.id;
        Iif (props.renderRow == undefined) {
            throw 'Missing function renderRow(item,index,key):component';
        }
        this.parts = SimpleListTable.parseListChildren(props.children);
        this.props = props;
    }
 
    componentWillReceiveProps(nextProps) {
        if (this.props.children == undefined || nextProps.children != this.props.children) {
            this.parts = SimpleListTable.parseListChildren(nextProps.children);
        }
        if(nextProps.data != this.props.data) {
            this.setState({data : nextProps.data});
        }
    }
 
    render() {
        const {data} = this.state;
        const hasData = data && data.length > 0;
        const showHeaders = hasData || this.props.headerAlwaysOn;
        return (
            <table className={`table ${this.props.className ? this.props.className : ''}`} style={{width:'100%'}} id={this.id + "-table"}>
                {showHeaders ? this.parts.thead : null}
                {(() => {
                    if (hasData) {
                        const rows = [];
                        data.forEach((item, index) => {
                            const realIndex = this.props.indexOffset + index;
                            let key = this.id + '-row-' + realIndex;
                            let newRow = this.props.renderRow(item, realIndex, key);
                            Eif (newRow != undefined && newRow != null) {
                                Iif (Array.isArray(newRow)) {
                                    throw 'Can return single &lt;tr&gt; component only';
                                } else {
                                    rows.push(newRow);
                                }
                            }
                        });
                        return (<tbody>{rows}</tbody>);
                    } else {
                        if (this.props.noDataElement) {
                            return (<tbody><tr><td colSpan="100%">{this.props.noDataElement}</td></tr></tbody>);
                        } else {
                            return null;
                        }
                    }
                })()}
                {showHeaders ? this.parts.tfoot : null}
            </table>
        );
    }
 
    static parseListChildren(childrenIn) {
        const out = { tfoot: null, thead: null };
        const children = Array.isArray(childrenIn) ? childrenIn : [childrenIn];
        for (let i = 0; i < children.length; i++) {
            if (children[i] == null || children[i] == undefined) {
                continue;
            }
            switch (children[i].type) {
                case 'tfoot':
                    out.tfoot = children[i];
                    break;
                case 'thead':
                    out.thead = children[i];
                    break;
                default:
                    devOnly(() => { console.error('List can contain thead or tfoot components only, but', children[i], 'found in list'); });
            }
        }
        return out;
    }
}