<commit_before>/**
 * @file ScrollTable component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, Fragment, createRef} from 'react';
import PropTypes from 'prop-types';

// Components
import BaseTable from '../_BaseTable';
import ScrollableTable from '../_ScrollableTable';
import DynamicRenderTableProvider from '../_DynamicRenderTableProvider';

// Statics
import Theme from '../Theme';
import TableFragment from '../_statics/TableFragment';
import HorizontalAlign from '../_statics/HorizontalAlign';
import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortingType from '../_statics/SortingType';

// Vendors
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';
import Util from '../_vendors/Util';

class ScrollTable extends Component {

    static Fragment = TableFragment;
    static Align = HorizontalAlign;
    static Fixed = HorizontalAlign;
    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.headScroller = createRef();
        this.bodyScroller = createRef();
        this.footScroller = createRef();

        this.lastScrollerEl = {};

    }

    componentDidMount() {

        this.updateEl();

        const {onInit} = this.props;
        onInit && onInit();

    }

    componentDidUpdate() {
        this.updateEl();
    }

    updateFragmentEl = fragment => {

        const {onGetScrollerEl} = this.props,
            instance = this?.[`${fragment}Scroller`]?.current,
            el = instance && findDOMNode(instance);

        if (!onGetScrollerEl || !el || this.lastScrollerEl[fragment] == el) {
            return;
        }

        onGetScrollerEl(fragment, el);
        this.lastScrollerEl[fragment] = el;

    };

    updateEl = () => {

        const {isHeadFixed, isFootFixed} = this.props;

        this.updateFragmentEl(TableFragment.BODY);
        isHeadFixed && this.updateFragmentEl(TableFragment.HEAD);
        isFootFixed && this.updateFragmentEl(TableFragment.FOOT);

    };

    hasVerticalScroll = () => {

        const scrollEl = this.lastScrollerEl[TableFragment.BODY];

        if (!scrollEl) {
            return false;
        }

        return scrollEl.scrollHeight > scrollEl.offsetHeight;

    };

    handleColumnsSpan = (...restArgs) => {
        const {fixed, onRequestColumnsSpan} = this.props;
        return onRequestColumnsSpan && onRequestColumnsSpan(fixed, ...restArgs);
    };

    render() {

        const {

            horizontalScrollStyle, verticalScrollStyle, fixed, columns, headColumns, bodyColumns,
            isHeadHidden, isFootHidden, isLayoutFixed, isHeadFixed, isFootFixed, data, scroll, hasFixedRightColumn,
            useDynamicRender, dynamicRenderIndex, scrollHeight, rowHeight, scrollBuffer, defaultColumnWidth,
            onScroll, onWheel, onColumnMeasure,

            // not passing down these props
            hasFixedLeftColumn, onInit, onGetScrollerEl,

            ...restProps

        } = this.props;

        if (!columns && !headColumns && !bodyColumns) {
            return null;
        }

        const hasVerticalScroll = this.hasVerticalScroll(),
            hasHead = !isHeadHidden && isHeadFixed,
            hasFoot = !isFootHidden && isFootFixed;

        return (
            <Fragment>

                {
                    hasHead ?
                        <ScrollableTable ref={this.headScroller}
                                         className="scroll-table-head"
                                         fragment={TableFragment.HEAD}
                                         scroll={scroll}
                                         useDynamicRender={useDynamicRender}
                                         scrollHeight={scrollHeight}
                                         rowHeight={rowHeight}
                                         scrollBuffer={scrollBuffer}
                                         onScroll={onScroll}>
                            {
                                scrollEl =>
                                    <BaseTable {...restProps}
                                               fixed={fixed}
                                               fragment={TableFragment.HEAD}
                                               columns={columns}
                                               headColumns={headColumns}
                                               bodyColumns={bodyColumns}
                                               hasFixedRightColumn={hasFixedRightColumn}
                                               data={data}
                                               scrollEl={scrollEl}
                                               useDynamicRender={useDynamicRender}
                                               scrollHeight={scrollHeight}
                                               rowHeight={rowHeight}
                                               scrollBuffer={scrollBuffer}
                                               hasVerticalScroll={hasVerticalScroll}
                                               isBodyHidden={true}
                                               isFootHidden={true}
                                               isLayoutFixed={isLayoutFixed}
                                               defaultColumnWidth={defaultColumnWidth}
                                               useColumnsWidth={true}
                                               onRequestColumnsSpan={this.handleColumnsSpan}/>
                            }
                        </ScrollableTable>
                        :
                        null
                }

                <ScrollableTable ref={this.bodyScroller}
                                 className={classNames('scroll-table-body', {
                                     'has-head': hasHead,
                                     'has-foot': hasFoot
                                 })}
                                 style={verticalScrollStyle}
                                 scroll={scroll}
                                 useDynamicRender={useDynamicRender}
                                 scrollHeight={scrollHeight}
                                 rowHeight={rowHeight}
                                 scrollBuffer={scrollBuffer}
                                 onScroll={onScroll}
                                 onWheel={onWheel}>
                    {
                        scrollEl =>
                            <DynamicRenderTableProvider data={data}
                                                        useDynamicRender={useDynamicRender}
                                                        rowHeight={rowHeight}>
                                <BaseTable {...restProps}
                                           style={{
                                               width: horizontalScrollStyle?.width,
                                               minWidth: horizontalScrollStyle?.width ? '100%' : null,
                                               transform: useDynamicRender && dynamicRenderIndex ?
                                                   `translateY(${dynamicRenderIndex.startWithBuffer * rowHeight}px)`
                                                   :
                                                   null
                                           }}
                                           fixed={fixed}
                                           fragment={TableFragment.BODY}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}
                                           hasFixedRightColumn={hasFixedRightColumn}
                                           isLayoutFixed={isLayoutFixed}
                                           isHeadFixed={isHeadFixed}
                                           isFootFixed={isFootFixed}
                                           isHeadHidden={isHeadHidden || isHeadFixed}
                                           isFootHidden={isFootHidden || isFootFixed}
                                           data={data}
                                           scrollEl={scrollEl}
                                           useDynamicRender={useDynamicRender}
                                           scrollHeight={scrollHeight}
                                           rowHeight={rowHeight}
                                           scrollBuffer={scrollBuffer}
                                           defaultColumnWidth={defaultColumnWidth}
                                           onRequestColumnsSpan={this.handleColumnsSpan}
                                           onColumnMeasure={onColumnMeasure}/>
                            </DynamicRenderTableProvider>
                    }
                </ScrollableTable>

                {
                    hasFoot ?
                        <ScrollableTable ref={this.footScroller}
                                         className="scroll-table-foot"
                                         fragment={TableFragment.FOOT}
                                         scroll={scroll}
                                         useDynamicRender={useDynamicRender}
                                         scrollHeight={scrollHeight}
                                         rowHeight={rowHeight}
                                         scrollBuffer={scrollBuffer}
                                         onScroll={onScroll}>
                            {
                                scrollEl =>
                                    <BaseTable {...restProps}
                                               fixed={fixed}
                                               fragment={TableFragment.FOOT}
                                               columns={columns}
                                               headColumns={headColumns}
                                               bodyColumns={bodyColumns}
                                               hasFixedRightColumn={hasFixedRightColumn}
                                               ignoreColumnSpan={true}
                                               data={data}
                                               scrollEl={scrollEl}
                                               useDynamicRender={useDynamicRender}
                                               scrollHeight={scrollHeight}
                                               rowHeight={rowHeight}
                                               scrollBuffer={scrollBuffer}
                                               hasVerticalScroll={hasVerticalScroll}
                                               isHeadHidden={true}
                                               isBodyHidden={true}
                                               isLayoutFixed={isLayoutFixed}
                                               defaultColumnWidth={defaultColumnWidth}
                                               useColumnsWidth={true}
                                               onRequestColumnsSpan={this.handleColumnsSpan}/>
                            }
                        </ScrollableTable>
                        :
                        null
                }

            </Fragment>
        );

    }
}

ScrollTable.propTypes = {

    horizontalScrollStyle: PropTypes.object,
    verticalScrollStyle: PropTypes.object,

    fixed: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(Util.enumerateValue(HorizontalAlign))]),

    /**
     * The theme of the table select radio or checkbox.
     */
    selectTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The select mode of table.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The select all mode of table, all or current page.
     */
    selectAllMode: PropTypes.oneOf(Util.enumerateValue(SelectAllMode)),

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.shape({

        /**
         * unique keyof column.
         */
        key: PropTypes.string,

        /**
         * fixed position of column ( 'left' / 'right' ).
         */
        fixed: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * width of column.
         */
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

        /**
         * minimum width of column.
         */
        minWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

        /**
         * align of current column.
         */
        align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * no wrap of current column.
         */
        noWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of header.
         */
        headClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headStyle: PropTypes.object,

        /**
         * align of table header cell
         */
        headAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headRenderer: PropTypes.any,

        /**
         * The title in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headTitle: PropTypes.any,

        /**
         * column span of table header.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table header.
         */
        headNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of td.
         */
        bodyClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        bodyStyle: PropTypes.object,

        /**
         * align of table body cell.
         */
        bodyAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyRenderer: PropTypes.any,

        /**
         * The title in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyTitle: PropTypes.any,

        /**
         * column span of table body.
         *  (1) function callback:
         *      function (rowData, colIndex, rowIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table body.
         */
        bodyNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footStyle: PropTypes.object,

        /**
         * align of table footer cell
         */
        footAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footRenderer: PropTypes.any,

        /**
         * The title in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footTitle: PropTypes.any,

        /**
         * column span of table foot.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table foot.
         */
        footNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * If true,this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sorting property.
         */
        sortingProp: PropTypes.string,

        defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType))

    })),
    headColumns: PropTypes.array,
    bodyColumns: PropTypes.array,
    columnKeyField: PropTypes.string,
    columnsWidth: PropTypes.object,
    data: PropTypes.array,
    dynamicRenderData: PropTypes.array,
    value: PropTypes.array,
    idField: PropTypes.string,
    expandRows: PropTypes.array,

    /**
     * scroll
     */
    scroll: PropTypes.shape({
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        maxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
    }),

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    isClickSorting: PropTypes.bool,

    /**
     * fixed
     */
    isLayoutFixed: PropTypes.bool,
    isHeadFixed: PropTypes.bool,
    isFootFixed: PropTypes.bool,

    /**
     * hidden
     */
    isHeadHidden: PropTypes.bool,
    isFootHidden: PropTypes.bool,

    /**
     * has renderer
     */
    hasHeadRenderer: PropTypes.bool,
    hasBodyRenderer: PropTypes.bool,
    hasFootRenderer: PropTypes.bool,

    /**
     * fixed column
     */
    hasFixedLeftColumn: PropTypes.bool,
    hasFixedRightColumn: PropTypes.bool,

    /**
     * Dynamic Render
     */
    useDynamicRender: PropTypes.bool,
    dynamicRenderIndex: PropTypes.object,
    scrollHeight: PropTypes.number,
    rowHeight: PropTypes.number,
    scrollBuffer: PropTypes.number,

    /**
     * column resizable
     */
    isColumnResizable: PropTypes.bool,
    defaultColumnWidth: PropTypes.number,
    minColumnWidth: PropTypes.number,
    maxColumnWidth: PropTypes.number,
    resizingColumn: PropTypes.object,

    /**
     * callback
     */
    onInit: PropTypes.func,
    onGetScrollerEl: PropTypes.func,
    onExpandChange: PropTypes.func,
    onScroll: PropTypes.func,
    onWheel: PropTypes.func,
    onSortChange: PropTypes.func,
    onRequestColumnsSpan: PropTypes.func,
    onColumnsWidthChange: PropTypes.func,
    onColumnResizeStart: PropTypes.func,
    onColumnResizeEnd: PropTypes.func,
    onColumnMeasure: PropTypes.func

};

ScrollTable.defaultProps = {

    columnKeyField: 'key',
    selectMode: SelectMode.SINGLE_SELECT,
    selectAllMode: SelectAllMode.CURRENT_PAGE,
    idField: 'id',
    expandRows: [],

    /**
     * sorting
     */
    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    isClickSorting: true,

    /**
     * fixed
     */
    isLayoutFixed: true,
    isHeadFixed: false,
    isFootFixed: false,

    /**
     * hidden
     */
    isHeadHidden: false,
    isFootHidden: false,

    /**
     * has renderer
     */
    hasHeadRenderer: true,
    hasBodyRenderer: true,
    hasFootRenderer: true,

    /**
     * fixed column
     */
    hasFixedLeftColumn: false,
    hasFixedRightColumn: false,

    /**
     * Dynamic Render
     */
    useDynamicRender: false,
    scrollHeight: 500,
    rowHeight: 50,
    scrollBuffer: 8,

    /**
     * column resizable
     */
    isColumnResizable: false,
    defaultColumnWidth: 100,
    minColumnWidth: 64,
    maxColumnWidth: Infinity

};

export default ScrollTable;
<commit_msg>update ScrollTable<commit_after>/**
 * @file ScrollTable component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, Fragment, createRef} from 'react';
import PropTypes from 'prop-types';

// Components
import BaseTable from '../_BaseTable';
import ScrollableTable from '../_ScrollableTable';
import DynamicRenderTableProvider from '../_DynamicRenderTableProvider';

// Statics
import Theme from '../Theme';
import TableFragment from '../_statics/TableFragment';
import HorizontalAlign from '../_statics/HorizontalAlign';
import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortingType from '../_statics/SortingType';

// Vendors
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';
import Util from '../_vendors/Util';

class ScrollTable extends Component {

    static Fragment = TableFragment;
    static Align = HorizontalAlign;
    static Fixed = HorizontalAlign;
    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.headScroller = createRef();
        this.bodyScroller = createRef();
        this.footScroller = createRef();

        this.lastScrollerEl = {};

    }

    componentDidMount() {

        this.updateEl();

        const {onInit} = this.props;
        onInit && onInit();

    }

    componentDidUpdate() {
        this.updateEl();
    }

    updateFragmentEl = fragment => {

        const {onGetScrollerEl} = this.props,
            instance = this?.[`${fragment}Scroller`]?.current,
            el = instance && findDOMNode(instance);

        if (!onGetScrollerEl || !el || this.lastScrollerEl[fragment] == el) {
            return;
        }

        onGetScrollerEl(fragment, el);
        this.lastScrollerEl[fragment] = el;

    };

    updateEl = () => {

        const {isHeadFixed, isFootFixed} = this.props;

        this.updateFragmentEl(TableFragment.BODY);
        isHeadFixed && this.updateFragmentEl(TableFragment.HEAD);
        isFootFixed && this.updateFragmentEl(TableFragment.FOOT);

    };

    hasVerticalScroll = () => {

        const scrollEl = this.lastScrollerEl[TableFragment.BODY];

        if (!scrollEl) {
            return false;
        }

        return scrollEl.scrollHeight > scrollEl.offsetHeight;

    };

    handleColumnsSpan = (...restArgs) => {
        const {fixed, onRequestColumnsSpan} = this.props;
        return onRequestColumnsSpan && onRequestColumnsSpan(fixed, ...restArgs);
    };

    render() {

        const {

            horizontalScrollStyle, verticalScrollStyle, fixed, columns, headColumns, bodyColumns,
            isHeadHidden, isFootHidden, isLayoutFixed, isHeadFixed, isFootFixed, data, scroll, hasFixedRightColumn,
            useDynamicRender, dynamicRenderIndex, scrollHeight, rowHeight, scrollBuffer, defaultColumnWidth,
            onScroll, onWheel, onColumnMeasure,

            // not passing down these props
            hasFixedLeftColumn, onInit, onGetScrollerEl,

            ...restProps

        } = this.props;

        if (!columns && !headColumns && !bodyColumns) {
            return null;
        }

        const hasVerticalScroll = this.hasVerticalScroll(),
            hasHead = !isHeadHidden && isHeadFixed,
            hasFoot = !isFootHidden && isFootFixed;

        return (
            <Fragment>

                {
                    hasHead ?
                        <ScrollableTable ref={this.headScroller}
                                         className="scroll-table-head"
                                         fragment={TableFragment.HEAD}
                                         scroll={scroll}
                                         useDynamicRender={useDynamicRender}
                                         scrollHeight={scrollHeight}
                                         rowHeight={rowHeight}
                                         scrollBuffer={scrollBuffer}
                                         onScroll={onScroll}>
                            {
                                scrollEl =>
                                    <BaseTable {...restProps}
                                               fixed={fixed}
                                               fragment={TableFragment.HEAD}
                                               columns={columns}
                                               headColumns={headColumns}
                                               bodyColumns={bodyColumns}
                                               hasFixedRightColumn={hasFixedRightColumn}
                                               data={data}
                                               scrollEl={scrollEl}
                                               useDynamicRender={useDynamicRender}
                                               scrollHeight={scrollHeight}
                                               rowHeight={rowHeight}
                                               scrollBuffer={scrollBuffer}
                                               hasVerticalScroll={hasVerticalScroll}
                                               isBodyHidden={true}
                                               isFootHidden={true}
                                               isLayoutFixed={isLayoutFixed}
                                               defaultColumnWidth={defaultColumnWidth}
                                               useColumnsWidth={true}
                                               onRequestColumnsSpan={this.handleColumnsSpan}/>
                            }
                        </ScrollableTable>
                        :
                        null
                }

                <ScrollableTable ref={this.bodyScroller}
                                 className={classNames('scroll-table-body', {
                                     'has-head': hasHead,
                                     'has-foot': hasFoot
                                 })}
                                 style={verticalScrollStyle}
                                 scroll={scroll}
                                 useDynamicRender={useDynamicRender}
                                 scrollHeight={scrollHeight}
                                 rowHeight={rowHeight}
                                 scrollBuffer={scrollBuffer}
                                 onScroll={onScroll}
                                 onWheel={onWheel}>
                    {
                        scrollEl =>
                            <DynamicRenderTableProvider data={data}
                                                        useDynamicRender={useDynamicRender}
                                                        rowHeight={rowHeight}>
                                <BaseTable {...restProps}
                                           style={{
                                               width: horizontalScrollStyle?.width,
                                               minWidth: horizontalScrollStyle?.width ? '100%' : null,
                                               transform: useDynamicRender && dynamicRenderIndex ?
                                                   `translateY(${dynamicRenderIndex.startWithBuffer * rowHeight}px)`
                                                   :
                                                   null
                                           }}
                                           fixed={fixed}
                                           fragment={TableFragment.BODY}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}
                                           hasFixedRightColumn={hasFixedRightColumn}
                                           isLayoutFixed={isLayoutFixed}
                                           isHeadHidden={isHeadHidden || isHeadFixed}
                                           isFootHidden={isFootHidden || isFootFixed}
                                           data={data}
                                           scrollEl={scrollEl}
                                           useDynamicRender={useDynamicRender}
                                           scrollHeight={scrollHeight}
                                           rowHeight={rowHeight}
                                           scrollBuffer={scrollBuffer}
                                           defaultColumnWidth={defaultColumnWidth}
                                           onRequestColumnsSpan={this.handleColumnsSpan}
                                           onColumnMeasure={onColumnMeasure}/>
                            </DynamicRenderTableProvider>
                    }
                </ScrollableTable>

                {
                    hasFoot ?
                        <ScrollableTable ref={this.footScroller}
                                         className="scroll-table-foot"
                                         fragment={TableFragment.FOOT}
                                         scroll={scroll}
                                         useDynamicRender={useDynamicRender}
                                         scrollHeight={scrollHeight}
                                         rowHeight={rowHeight}
                                         scrollBuffer={scrollBuffer}
                                         onScroll={onScroll}>
                            {
                                scrollEl =>
                                    <BaseTable {...restProps}
                                               fixed={fixed}
                                               fragment={TableFragment.FOOT}
                                               columns={columns}
                                               headColumns={headColumns}
                                               bodyColumns={bodyColumns}
                                               hasFixedRightColumn={hasFixedRightColumn}
                                               ignoreColumnSpan={true}
                                               data={data}
                                               scrollEl={scrollEl}
                                               useDynamicRender={useDynamicRender}
                                               scrollHeight={scrollHeight}
                                               rowHeight={rowHeight}
                                               scrollBuffer={scrollBuffer}
                                               hasVerticalScroll={hasVerticalScroll}
                                               isHeadHidden={true}
                                               isBodyHidden={true}
                                               isLayoutFixed={isLayoutFixed}
                                               defaultColumnWidth={defaultColumnWidth}
                                               useColumnsWidth={true}
                                               onRequestColumnsSpan={this.handleColumnsSpan}/>
                            }
                        </ScrollableTable>
                        :
                        null
                }

            </Fragment>
        );

    }
}

ScrollTable.propTypes = {

    horizontalScrollStyle: PropTypes.object,
    verticalScrollStyle: PropTypes.object,

    fixed: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(Util.enumerateValue(HorizontalAlign))]),

    /**
     * The theme of the table select radio or checkbox.
     */
    selectTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The select mode of table.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The select all mode of table, all or current page.
     */
    selectAllMode: PropTypes.oneOf(Util.enumerateValue(SelectAllMode)),

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.shape({

        /**
         * unique keyof column.
         */
        key: PropTypes.string,

        /**
         * fixed position of column ( 'left' / 'right' ).
         */
        fixed: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * width of column.
         */
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

        /**
         * minimum width of column.
         */
        minWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

        /**
         * align of current column.
         */
        align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * no wrap of current column.
         */
        noWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of header.
         */
        headClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headStyle: PropTypes.object,

        /**
         * align of table header cell
         */
        headAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headRenderer: PropTypes.any,

        /**
         * The title in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headTitle: PropTypes.any,

        /**
         * column span of table header.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table header.
         */
        headNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of td.
         */
        bodyClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        bodyStyle: PropTypes.object,

        /**
         * align of table body cell.
         */
        bodyAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyRenderer: PropTypes.any,

        /**
         * The title in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyTitle: PropTypes.any,

        /**
         * column span of table body.
         *  (1) function callback:
         *      function (rowData, colIndex, rowIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table body.
         */
        bodyNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footStyle: PropTypes.object,

        /**
         * align of table footer cell
         */
        footAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footRenderer: PropTypes.any,

        /**
         * The title in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footTitle: PropTypes.any,

        /**
         * column span of table foot.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table foot.
         */
        footNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * If true,this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sorting property.
         */
        sortingProp: PropTypes.string,

        defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType))

    })),
    headColumns: PropTypes.array,
    bodyColumns: PropTypes.array,
    columnKeyField: PropTypes.string,
    columnsWidth: PropTypes.object,
    data: PropTypes.array,
    dynamicRenderData: PropTypes.array,
    value: PropTypes.array,
    idField: PropTypes.string,
    expandRows: PropTypes.array,

    /**
     * scroll
     */
    scroll: PropTypes.shape({
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        maxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
    }),

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    isClickSorting: PropTypes.bool,

    /**
     * fixed
     */
    isLayoutFixed: PropTypes.bool,
    isHeadFixed: PropTypes.bool,
    isFootFixed: PropTypes.bool,

    /**
     * hidden
     */
    isHeadHidden: PropTypes.bool,
    isFootHidden: PropTypes.bool,

    /**
     * has renderer
     */
    hasHeadRenderer: PropTypes.bool,
    hasBodyRenderer: PropTypes.bool,
    hasFootRenderer: PropTypes.bool,

    /**
     * fixed column
     */
    hasFixedLeftColumn: PropTypes.bool,
    hasFixedRightColumn: PropTypes.bool,

    /**
     * Dynamic Render
     */
    useDynamicRender: PropTypes.bool,
    dynamicRenderIndex: PropTypes.object,
    scrollHeight: PropTypes.number,
    rowHeight: PropTypes.number,
    scrollBuffer: PropTypes.number,

    /**
     * column resizable
     */
    isColumnResizable: PropTypes.bool,
    defaultColumnWidth: PropTypes.number,
    minColumnWidth: PropTypes.number,
    maxColumnWidth: PropTypes.number,
    resizingColumn: PropTypes.object,

    /**
     * callback
     */
    onInit: PropTypes.func,
    onGetScrollerEl: PropTypes.func,
    onExpandChange: PropTypes.func,
    onScroll: PropTypes.func,
    onWheel: PropTypes.func,
    onSortChange: PropTypes.func,
    onRequestColumnsSpan: PropTypes.func,
    onColumnsWidthChange: PropTypes.func,
    onColumnResizeStart: PropTypes.func,
    onColumnResizeEnd: PropTypes.func,
    onColumnMeasure: PropTypes.func

};

ScrollTable.defaultProps = {

    columnKeyField: 'key',
    selectMode: SelectMode.SINGLE_SELECT,
    selectAllMode: SelectAllMode.CURRENT_PAGE,
    idField: 'id',
    expandRows: [],

    /**
     * sorting
     */
    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    isClickSorting: true,

    /**
     * fixed
     */
    isLayoutFixed: true,
    isHeadFixed: false,
    isFootFixed: false,

    /**
     * hidden
     */
    isHeadHidden: false,
    isFootHidden: false,

    /**
     * has renderer
     */
    hasHeadRenderer: true,
    hasBodyRenderer: true,
    hasFootRenderer: true,

    /**
     * fixed column
     */
    hasFixedLeftColumn: false,
    hasFixedRightColumn: false,

    /**
     * Dynamic Render
     */
    useDynamicRender: false,
    scrollHeight: 500,
    rowHeight: 50,
    scrollBuffer: 8,

    /**
     * column resizable
     */
    isColumnResizable: false,
    defaultColumnWidth: 100,
    minColumnWidth: 64,
    maxColumnWidth: Infinity

};

export default ScrollTable;
<|endoftext|>


<commit_before>'use strict';
const ClientValidate = require('../../../api/domain/client/client-validate');

describe('api domain client validate', () => {
  const APP = {};
  let CLIENT;
  let clientValidate;

  beforeEach(() => {
    dottie.set(APP, 'domain.client.ClientModel', {});

    CLIENT = {
      active: true,
      color: '',
      id: '61361f65-cb46-4d24-8cac-b085c1c4961c',
      name: ''
    };

    clientValidate = new ClientValidate(APP);
  });

  it('should be defined', () => {
    expect(clientValidate).to.not.be.undefined;
  });

  it('name should be required', done => {
    delete CLIENT.name;

    clientValidate.nameIsRequired(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.name.required');
        expect(result.message).to.equal('Name is required');
        return done();
      })
      .catch(done);
  });

  it('name should be maximum 100 characters', done => {
    CLIENT.name = properties.BIG_TEXT;

    clientValidate.nameMustHaveMaximum100Characters(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.name.maxlength');
        expect(result.message).to.equal('Name must have a maximum of 100 characters');
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending a new name', done => {
    const anotherClient = clone(CLIENT);
    anotherClient.name = 'Internal';
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith();

    clientValidate.nameMustBeUnique(anotherClient)
      .then(() => {
        expect(APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending same name with equal ID', done => {
    const anotherClient = clone(CLIENT);
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith(CLIENT);

    clientValidate.nameMustBeUnique(anotherClient)
      .then(result => {
        expect(APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending same name with different ID´s', done => {
    const anotherClient = clone(CLIENT);
    anotherClient.id = '2103c936-6613-4479-975c-cd1a87fe1e41';
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith(CLIENT);

    clientValidate.nameMustBeUnique(anotherClient)
      .then(result => {
        expect( APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        expect(result.code).to.equal('client.name.unique');
        expect(result.message).to.equal('Name must be unique');
        return done();
      })
      .catch(done);
  });

  it('color should be maximum 20 characters', done => {
    CLIENT.color = properties.BIG_TEXT;

    clientValidate.colorMustHaveMaximum20Characters(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.color.maxlength');
        expect(result.message).to.equal('Color must have a maximum of 20 characters');
        return done();
      })
      .catch(done);
  });
});
<commit_msg>add more test unit in client<commit_after>'use strict';
const ClientValidate = require('../../../api/domain/client/client-validate');

describe('api domain client validate', () => {
  const APP = {};
  let CLIENT;
  let clientValidate;

  beforeEach(() => {
    dottie.set(APP, 'domain.client.ClientModel', {});

    CLIENT = {
      active: true,
      color: '',
      id: '61361f65-cb46-4d24-8cac-b085c1c4961c',
      name: 'Grower games'
    };

    clientValidate = new ClientValidate(APP);
  });

  it('should be defined', () => {
    expect(clientValidate).to.not.be.undefined;
  });

  it('name should be required', done => {
    delete CLIENT.name;

    clientValidate.nameIsRequired(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.name.required');
        expect(result.message).to.equal('Name is required');
        return done();
      })
      .catch(done);
  });

  it('name should be maximum 100 characters', done => {
    CLIENT.name = properties.BIG_TEXT;

    clientValidate.nameMustHaveMaximum100Characters(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.name.maxlength');
        expect(result.message).to.equal('Name must have a maximum of 100 characters');
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending a new name', done => {
    const anotherClient = clone(CLIENT);
    anotherClient.name = 'Internal';
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith();

    clientValidate.nameMustBeUnique(anotherClient)
      .then(() => {
        expect(APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending same name with equal ID', done => {
    const anotherClient = clone(CLIENT);
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith(CLIENT);

    clientValidate.nameMustBeUnique(anotherClient)
      .then(result => {
        expect(APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        return done();
      })
      .catch(done);
  });

  it('name should be unique, Sending same name with different ID´s', done => {
    const anotherClient = clone(CLIENT);
    anotherClient.id = '2103c936-6613-4479-975c-cd1a87fe1e41';
    APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith(CLIENT);

    clientValidate.nameMustBeUnique(anotherClient)
      .then(result => {
        expect( APP.domain.client.ClientModel.findOne.callCount).to.equal(1);
        expect(result.code).to.equal('client.name.unique');
        expect(result.message).to.equal('Name must be unique');
        return done();
      })
      .catch(done);
  });

  it('color should be maximum 20 characters', done => {
    CLIENT.color = properties.BIG_TEXT;

    clientValidate.colorMustHaveMaximum20Characters(CLIENT)
      .then(result => {
        expect(result.code).to.equal('client.color.maxlength');
        expect(result.message).to.equal('Color must have a maximum of 20 characters');
        return done();
      })
      .catch(done);
  });

  describe('# onCreate', () => {
    beforeEach(() => {
      delete CLIENT.id;
      APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith();
    });

    it('create a new valid client', done => {
      clientValidate.onCreate(CLIENT)
        .then(() => done())
        .catch(done);
    });

    it('create a new invalid client', done => {
      delete CLIENT.name;

       clientValidate.onCreate(CLIENT)
        .then(() => done('should be error'))
        .catch(error => {
          expect(error.name).to.equal('BusinessError');
          expect(error.errors.length).to.equal(1);
          expect(error.errors[0].code).to.equal('client.name.required');
          return done();
        });
    });
  });

  describe('# onUpdate', () => {
    beforeEach(() => {
       APP.domain.client.ClientModel.findOne = simpleMock.stub().resolveWith();
    });

    it('update a valid client', done => {
      clientValidate.onUpdate(CLIENT)
        .then(() => done())
        .catch(error => done(error));
    });

    it('update a invalid client', done => {
      delete CLIENT.name;

      clientValidate.onUpdate(CLIENT)
        .then(() => done())
        .catch(error => {
          expect(error.name).to.equal('BusinessError');
          expect(error.errors.length).to.equal(1);
          expect(error.errors[0].code).to.equal('client.name.required');
          return done();
        });
    });
  });
});
<|endoftext|>


<commit_before>export { default as OCLE } from './libs/OCLE';
export { OCLUtils, OCL } from './libs/OCLUtils';
export { default as SD } from './libs/SD';
export { default as elnPlugin } from './libs/elnPlugin';
export { default as Image } from './libs/Image';
export { default as MolecularFormula } from './libs/MolecularFormula';
export { default as convertToJcamp } from './libs/convertToJcamp';
export { parseXY } from './libs/parseXY';
export { convert } from './libs/jcampconverter';
export { SpectraProcessor } from './libs/SpectraProcessor';
<commit_msg>chore: remove SpectraProcessor from vh<commit_after>export { default as OCLE } from './libs/OCLE';
export { OCLUtils, OCL } from './libs/OCLUtils';
export { default as SD } from './libs/SD';
export { default as elnPlugin } from './libs/elnPlugin';
export { default as Image } from './libs/Image';
export { default as MolecularFormula } from './libs/MolecularFormula';
export { default as convertToJcamp } from './libs/convertToJcamp';
export { parseXY } from './libs/parseXY';
export { convert } from './libs/jcampconverter';
<|endoftext|>


<commit_before>import { closest as domClosest } from 'min-dom';

const EVENTS = [
  'click',
  'dblclick',
  'contextmenu',
  'mousedown',
  'mouseup',
  'mouseenter',
  'mouseleave',
  'mouseout',
  'mouseover',
  'mousemove',
  'drag',
  'dragstart',
  'dragend',
  'dragover',
  'dragenter',
  'dragleave',
  'drop'
];

export default class InteractionEvents {

  constructor(eventBus) {
    this._eventBus = eventBus;

    this._handleEvent = this._handleEvent.bind(this);

    this._addEventListeners(EVENTS);

    eventBus.on('diagram.destroy', () => {
      this._removeEventListeners(EVENTS);
    });
  }

  _addEventListeners(events) {
    events.forEach(event => {
      window.addEventListener(event, this._handleEvent);
    });
  }

  _removeEventListeners(events) {
    events.forEach(event => {
      window.removeEventListener(event, this._handleEvent);
    });
  }

  _handleEvent(event) {
    const { target, type } = event;

    const node = findClosestCell(target);

    if (!node) {
      return;
    }

    const { elementId } = node.dataset;

    if (elementId) {
      this._eventBus.fire(`cell.${type}`, {
        id: elementId,
        event,
        node
      });
    }
  }

}

InteractionEvents.$inject = [
  'eventBus'
];

// helpers /////////////

function findClosestCell(element) {
  const closest = domClosest(element, 'th') || domClosest(element, 'td');

  const isCell = (
    element.tagName
      && (element.tagName.toLowerCase() === 'th'
        || element.tagName.toLowerCase() === 'td')
  );

  if (isCell) {
    return element;
  } else if (closest) {
    return closest;
  }
}<commit_msg>fix(interaction-events): don't bind to window<commit_after>import {
  closest as domClosest
} from 'min-dom';

const EVENTS = [
  'click',
  'dblclick',
  'contextmenu',
  'mousedown',
  'mouseup',
  'mouseenter',
  'mouseleave',
  'mouseout',
  'mouseover',
  'mousemove',
  'drag',
  'dragstart',
  'dragend',
  'dragover',
  'dragenter',
  'dragleave',
  'drop'
];

/**
 * Provides interaction events on the table.
 *
 * @param {RenderConfig} config
 * @param {EventBus} eventBus
 */
export default class InteractionEvents {

  constructor(config, eventBus) {
    this._eventBus = eventBus;
    this._container = config.container;

    this._addEventListeners(EVENTS);

    eventBus.on('diagram.destroy', () => {
      this._removeEventListeners(EVENTS);
    });
  }

  _addEventListeners(events) {
    const container = this._container;

    events.forEach(event => {
      container.addEventListener(event, this._handleEvent);
    });
  }

  _removeEventListeners(events) {
    const container = this._container;

    events.forEach(event => {
      container.removeEventListener(event, this._handleEvent);
    });
  }

  _handleEvent = (event) => {
    const { target, type } = event;

    const node = findClosestCell(target);

    if (!node) {
      return;
    }

    const { elementId } = node.dataset;

    if (elementId) {
      this._eventBus.fire(`cell.${type}`, {
        id: elementId,
        event,
        node
      });
    }
  }
}

InteractionEvents.$inject = [
  'config.renderer',
  'eventBus'
];

// helpers /////////////

function findClosestCell(element) {
  const closest = domClosest(element, 'th') || domClosest(element, 'td');

  const isCell = (
    element.tagName
      && (element.tagName.toLowerCase() === 'th'
        || element.tagName.toLowerCase() === 'td')
  );

  if (isCell) {
    return element;
  } else if (closest) {
    return closest;
  }
}<|endoftext|>


<commit_before>'use strict';

/**
 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level
 * directory of this distribution and at
 * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
 */
(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(factory);
    } else if (typeof exports === "object") {
        module.exports = factory();
    } else {
        root.ResizeSensor = factory();
    }
}(typeof window !== 'undefined' ? window : this, function () {

    // Make sure it does not throw in a SSR (Server Side Rendering) situation
    if (typeof window === "undefined") {
        return null;
    }
    // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
    // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
    // would generate too many unnecessary events.
    var requestAnimationFrame = window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (fn) {
            return window.setTimeout(fn, 20);
        };

    /**
     * Iterate over each of the provided element(s).
     *
     * @param {HTMLElement|HTMLElement[]} elements
     * @param {Function}                  callback
     */
    function forEachElement(elements, callback){
        var elementsType = Object.prototype.toString.call(elements);
        var isCollectionTyped = ('[object Array]' === elementsType
            || ('[object NodeList]' === elementsType)
            || ('[object HTMLCollection]' === elementsType)
            || ('[object Object]' === elementsType)
            || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
            || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
        );
        var i = 0, j = elements.length;
        if (isCollectionTyped) {
            for (; i < j; i++) {
                callback(elements[i]);
            }
        } else {
            callback(elements);
        }
    }

    /**
    * Get element size
    * @param {HTMLElement} element
    * @returns {Object} {width, height}
    */
    function getElementSize(element) {
        if (!element.getBoundingClientRect) {
            return {
                width: element.offsetWidth,
                height: element.offsetHeight
            }
        }

        var rect = element.getBoundingClientRect();
        return {
            width: Math.round(rect.width),
            height: Math.round(rect.height)
        }
    }

    /**
     * Class for dimension change detection.
     *
     * @param {Element|Element[]|Elements|jQuery} element
     * @param {Function} callback
     *
     * @constructor
     */
    var ResizeSensor = function(element, callback) {
        /**
         *
         * @constructor
         */
        function EventQueue() {
            var q = [];
            this.add = function(ev) {
                q.push(ev);
            };

            var i, j;
            this.call = function(sizeInfo) {
                for (i = 0, j = q.length; i < j; i++) {
                    q[i].call(this, sizeInfo);
                }
            };

            this.remove = function(ev) {
                var newQueue = [];
                for(i = 0, j = q.length; i < j; i++) {
                    if(q[i] !== ev) newQueue.push(q[i]);
                }
                q = newQueue;
            };

            this.length = function() {
                return q.length;
            }
        }

        /**
         *
         * @param {HTMLElement} element
         * @param {Function}    resized
         */
        function attachResizeEvent(element, resized) {
            if (!element) return;
            if (element.resizedAttached) {
                element.resizedAttached.add(resized);
                return;
            }

            element.resizedAttached = new EventQueue();
            element.resizedAttached.add(resized);

            element.resizeSensor = document.createElement('div');
            element.resizeSensor.dir = 'ltr';
            element.resizeSensor.className = 'resize-sensor';
            var style = 'pointer-events: none; position: absolute; left: 0px; top: 0px; right: 0; bottom: 0; ' +
                'overflow: hidden; z-index: -1; visibility: hidden; max-width: 100%;';
            var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;';

            element.resizeSensor.style.cssText = style;
            element.resizeSensor.innerHTML =
                '
' +
                    '

' +
                '
' +
                '
' +
                    '

' +
                '
';
            element.appendChild(element.resizeSensor);

            var computedStyle = window.getComputedStyle(element);
            var position = computedStyle ? computedStyle.getPropertyValue('position') : null;
            if ('absolute' !== position && 'relative' !== position && 'fixed' !== position) {
                element.style.position = 'relative';
            }

            var expand = element.resizeSensor.childNodes[0];
            var expandChild = expand.childNodes[0];
            var shrink = element.resizeSensor.childNodes[1];
            var dirty, rafId;
            var size = getElementSize(element);
            var lastWidth = size.width;
            var lastHeight = size.height;
            var initialHiddenCheck = true;
            var lastAnimationFrame = 0;

            var resetExpandShrink = function () {
                var width = element.offsetWidth;
                var height = element.offsetHeight;

                expandChild.style.width = (width + 10) + 'px';
                expandChild.style.height = (height + 10) + 'px';

                expand.scrollLeft = width + 10;
                expand.scrollTop = height + 10;

                shrink.scrollLeft = width + 10;
                shrink.scrollTop = height + 10;
            };

            var reset = function() {
                // Check if element is hidden
                if (initialHiddenCheck) {
                    var invisible = element.offsetWidth === 0 && element.offsetHeight === 0;
                    if (invisible) {
                        // Check in next frame
                        if (!lastAnimationFrame){
                            lastAnimationFrame = requestAnimationFrame(function(){
                                lastAnimationFrame = 0;

                                reset();
                            });
                        }

                        return;
                    } else {
                        // Stop checking
                        initialHiddenCheck = false;
                    }
                }

                resetExpandShrink();
            };
            element.resizeSensor.resetSensor = reset;

            var onResized = function() {
                rafId = 0;

                if (!dirty) return;

                lastWidth = size.width;
                lastHeight = size.height;

                if (element.resizedAttached) {
                    element.resizedAttached.call(size);
                }
            };

            var onScroll = function() {
                size = getElementSize(element);
                dirty = size.width !== lastWidth || size.height !== lastHeight;

                if (dirty && !rafId) {
                    rafId = requestAnimationFrame(onResized);
                }

                reset();
            };

            var addEvent = function(el, name, cb) {
                if (el.attachEvent) {
                    el.attachEvent('on' + name, cb);
                } else {
                    el.addEventListener(name, cb);
                }
            };

            addEvent(expand, 'scroll', onScroll);
            addEvent(shrink, 'scroll', onScroll);

            // Fix for custom Elements
            requestAnimationFrame(reset);
        }

        forEachElement(element, function(elem){
            attachResizeEvent(elem, callback);
        });

        this.detach = function(ev) {
            ResizeSensor.detach(element, ev);
        };

        this.reset = function() {
            element.resizeSensor.resetSensor();
        };
    };

    ResizeSensor.reset = function(element) {
        forEachElement(element, function(elem){
            elem.resizeSensor.resetSensor();
        });
    };

    ResizeSensor.detach = function(element, ev) {
        forEachElement(element, function(elem){
            if (!elem) return;
            if(elem.resizedAttached && typeof ev === "function"){
                elem.resizedAttached.remove(ev);
                if(elem.resizedAttached.length()) return;
            }
            if (elem.resizeSensor) {
                if (elem.contains(elem.resizeSensor)) {
                    elem.removeChild(elem.resizeSensor);
                }
                delete elem.resizeSensor;
                delete elem.resizedAttached;
            }
        });
    };

    if (typeof MutationObserver !== "undefined") {
        var observer = new MutationObserver(function (mutations) {
            for (var i in mutations) {
                var items = mutations[i].addedNodes;
                for (var j = 0; j < items.length; j++) {
                    if (items[j].resizeSensor) {
                        ResizeSensor.reset(items[j]);
                    }
                }

            }
        });

        document.addEventListener("DOMContentLoaded", function (event) {
            observer.observe(document.body, {
                childList: true,
                subtree: true,
            });
        });
    }

    return ResizeSensor;

}));
<commit_msg>Make the MutationObserver of ResizeSensor compatible with new Chrome version (#249)<commit_after>'use strict';

/**
 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level
 * directory of this distribution and at
 * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
 */
(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(factory);
    } else if (typeof exports === "object") {
        module.exports = factory();
    } else {
        root.ResizeSensor = factory();
    }
}(typeof window !== 'undefined' ? window : this, function () {

    // Make sure it does not throw in a SSR (Server Side Rendering) situation
    if (typeof window === "undefined") {
        return null;
    }
    // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
    // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
    // would generate too many unnecessary events.
    var requestAnimationFrame = window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (fn) {
            return window.setTimeout(fn, 20);
        };

    /**
     * Iterate over each of the provided element(s).
     *
     * @param {HTMLElement|HTMLElement[]} elements
     * @param {Function}                  callback
     */
    function forEachElement(elements, callback){
        var elementsType = Object.prototype.toString.call(elements);
        var isCollectionTyped = ('[object Array]' === elementsType
            || ('[object NodeList]' === elementsType)
            || ('[object HTMLCollection]' === elementsType)
            || ('[object Object]' === elementsType)
            || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
            || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
        );
        var i = 0, j = elements.length;
        if (isCollectionTyped) {
            for (; i < j; i++) {
                callback(elements[i]);
            }
        } else {
            callback(elements);
        }
    }

    /**
    * Get element size
    * @param {HTMLElement} element
    * @returns {Object} {width, height}
    */
    function getElementSize(element) {
        if (!element.getBoundingClientRect) {
            return {
                width: element.offsetWidth,
                height: element.offsetHeight
            }
        }

        var rect = element.getBoundingClientRect();
        return {
            width: Math.round(rect.width),
            height: Math.round(rect.height)
        }
    }

    /**
     * Class for dimension change detection.
     *
     * @param {Element|Element[]|Elements|jQuery} element
     * @param {Function} callback
     *
     * @constructor
     */
    var ResizeSensor = function(element, callback) {
        /**
         *
         * @constructor
         */
        function EventQueue() {
            var q = [];
            this.add = function(ev) {
                q.push(ev);
            };

            var i, j;
            this.call = function(sizeInfo) {
                for (i = 0, j = q.length; i < j; i++) {
                    q[i].call(this, sizeInfo);
                }
            };

            this.remove = function(ev) {
                var newQueue = [];
                for(i = 0, j = q.length; i < j; i++) {
                    if(q[i] !== ev) newQueue.push(q[i]);
                }
                q = newQueue;
            };

            this.length = function() {
                return q.length;
            }
        }

        /**
         *
         * @param {HTMLElement} element
         * @param {Function}    resized
         */
        function attachResizeEvent(element, resized) {
            if (!element) return;
            if (element.resizedAttached) {
                element.resizedAttached.add(resized);
                return;
            }

            element.resizedAttached = new EventQueue();
            element.resizedAttached.add(resized);

            element.resizeSensor = document.createElement('div');
            element.resizeSensor.dir = 'ltr';
            element.resizeSensor.className = 'resize-sensor';
            var style = 'pointer-events: none; position: absolute; left: 0px; top: 0px; right: 0; bottom: 0; ' +
                'overflow: hidden; z-index: -1; visibility: hidden; max-width: 100%;';
            var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;';

            element.resizeSensor.style.cssText = style;
            element.resizeSensor.innerHTML =
                '
' +
                    '

' +
                '
' +
                '
' +
                    '

' +
                '
';
            element.appendChild(element.resizeSensor);

            var computedStyle = window.getComputedStyle(element);
            var position = computedStyle ? computedStyle.getPropertyValue('position') : null;
            if ('absolute' !== position && 'relative' !== position && 'fixed' !== position) {
                element.style.position = 'relative';
            }

            var expand = element.resizeSensor.childNodes[0];
            var expandChild = expand.childNodes[0];
            var shrink = element.resizeSensor.childNodes[1];
            var dirty, rafId;
            var size = getElementSize(element);
            var lastWidth = size.width;
            var lastHeight = size.height;
            var initialHiddenCheck = true;
            var lastAnimationFrame = 0;

            var resetExpandShrink = function () {
                var width = element.offsetWidth;
                var height = element.offsetHeight;

                expandChild.style.width = (width + 10) + 'px';
                expandChild.style.height = (height + 10) + 'px';

                expand.scrollLeft = width + 10;
                expand.scrollTop = height + 10;

                shrink.scrollLeft = width + 10;
                shrink.scrollTop = height + 10;
            };

            var reset = function() {
                // Check if element is hidden
                if (initialHiddenCheck) {
                    var invisible = element.offsetWidth === 0 && element.offsetHeight === 0;
                    if (invisible) {
                        // Check in next frame
                        if (!lastAnimationFrame){
                            lastAnimationFrame = requestAnimationFrame(function(){
                                lastAnimationFrame = 0;

                                reset();
                            });
                        }

                        return;
                    } else {
                        // Stop checking
                        initialHiddenCheck = false;
                    }
                }

                resetExpandShrink();
            };
            element.resizeSensor.resetSensor = reset;

            var onResized = function() {
                rafId = 0;

                if (!dirty) return;

                lastWidth = size.width;
                lastHeight = size.height;

                if (element.resizedAttached) {
                    element.resizedAttached.call(size);
                }
            };

            var onScroll = function() {
                size = getElementSize(element);
                dirty = size.width !== lastWidth || size.height !== lastHeight;

                if (dirty && !rafId) {
                    rafId = requestAnimationFrame(onResized);
                }

                reset();
            };

            var addEvent = function(el, name, cb) {
                if (el.attachEvent) {
                    el.attachEvent('on' + name, cb);
                } else {
                    el.addEventListener(name, cb);
                }
            };

            addEvent(expand, 'scroll', onScroll);
            addEvent(shrink, 'scroll', onScroll);

            // Fix for custom Elements
            requestAnimationFrame(reset);
        }

        forEachElement(element, function(elem){
            attachResizeEvent(elem, callback);
        });

        this.detach = function(ev) {
            ResizeSensor.detach(element, ev);
        };

        this.reset = function() {
            element.resizeSensor.resetSensor();
        };
    };

    ResizeSensor.reset = function(element) {
        forEachElement(element, function(elem){
            elem.resizeSensor.resetSensor();
        });
    };

    ResizeSensor.detach = function(element, ev) {
        forEachElement(element, function(elem){
            if (!elem) return;
            if(elem.resizedAttached && typeof ev === "function"){
                elem.resizedAttached.remove(ev);
                if(elem.resizedAttached.length()) return;
            }
            if (elem.resizeSensor) {
                if (elem.contains(elem.resizeSensor)) {
                    elem.removeChild(elem.resizeSensor);
                }
                delete elem.resizeSensor;
                delete elem.resizedAttached;
            }
        });
    };

    if (typeof MutationObserver !== "undefined") {
        var observer = new MutationObserver(function (mutations) {
            for (var i in mutations) {
                if (mutations.hasOwnProperty(i)) {
                    var items = mutations[i].addedNodes;
                    for (var j = 0; j < items.length; j++) {
                        if (items[j].resizeSensor) {
                            ResizeSensor.reset(items[j]);
                        }
                    }
                }
            }
        });

        document.addEventListener("DOMContentLoaded", function (event) {
            observer.observe(document.body, {
                childList: true,
                subtree: true,
            });
        });
    }

    return ResizeSensor;

}));
<|endoftext|>


<commit_before>const logger = require('./logger')(module)
const Promise = require('bluebird')
const enums = require('./enums')
const dbResult = require('./db-result')

module.exports = function queueGetNextJob (q) {
  logger('getNextJob')
  logger(`Concurrency: [${q.concurrency}] Running: [${q.running}]`)
  let quantity = q.concurrency - q.running
  logger(`Query Limit: [${quantity}]`)
  if (quantity < 1) {
    return Promise.resolve([])
  }
  return Promise.resolve().then(() => {
    return q.r
    .table(q.name)
    .orderBy({index: enums.index.indexInactivePriorityDateCreated})
    .limit(quantity)
    .filter(
      q.r.row('dateEnable').le(q.r.now())
    )
    .update({
      status: enums.status.active,
      dateStarted: q.r.now(),
      dateEnable: q.r.now()
      .add(
        q.r.row('timeout').div(1000)
      )
      .add(
        q.r.row('retryDelay').div(1000).mul(q.r.row('retryCount'))
      ),
      queueId: q.id,
      processCount: q.r.row('processCount').add(1),
      log: q.r.row('log').append({
        date: q.r.now(),
        queueId: q.id,
        type: enums.log.information,
        status: enums.status.active,
        retryCount: q.r.row('retryCount'),
        processCount: q.r.row('processCount'),
        message: enums.message.active
      })
    }, {returnChanges: true})
    .default({})
    .run(q.queryRunOptions)
  }).then((updateResult) => {
    logger('updateResult', updateResult)
    return dbResult.toJob(q, updateResult)
  }).then((updatedJobs) => {
    for (let job of updatedJobs) {
      logger(`Event: active [${job.id}]`)
      q.emit(enums.status.active, q.id, job.id)
    }
    return updatedJobs
  })
}
<commit_msg>Fixed get-next-job to be atomic<commit_after>const logger = require('./logger')(module)
const Promise = require('bluebird')
const enums = require('./enums')
const dbResult = require('./db-result')

module.exports = function queueGetNextJob (q) {
  logger('getNextJob')
  logger(`Concurrency: [${q.concurrency}] Running: [${q.running}]`)
  let quantity = q.concurrency - q.running
  logger(`Query Limit: [${quantity}]`)
  if (quantity < 1) {
    return Promise.resolve([])
  }
  return Promise.resolve().then(() => {
    return q.r
    .table(q.name)
    .orderBy({index: enums.index.indexInactivePriorityDateCreated})
    .limit(quantity)
    .filter(
      q.r.row('dateEnable').le(q.r.now())
    )
    .update(getJobUpdate(q), {returnChanges: true})
    .default({})
    .run(q.queryRunOptions)
  }).then((updateResult) => {
    logger('updateResult', updateResult)
    return dbResult.toJob(q, updateResult)
  }).then((updatedJobs) => {
    for (let job of updatedJobs) {
      logger(`Event: active [${job.id}]`)
      q.emit(enums.status.active, q.id, job.id)
    }
    return updatedJobs
  })
}

function getJobUpdate (q) {
  return function (job) {
    return q.r.branch(
      job('status').ne(enums.status.active),
      {
        status: enums.status.active,
        dateStarted: q.r.now(),
        dateEnable: q.r.now()
        .add(
          job('timeout').div(1000)
        )
        .add(
          job('retryDelay').div(1000).mul(job('retryCount'))
        ),
        queueId: q.id,
        processCount: job('processCount').add(1),
        log: job('log').append({
          date: q.r.now(),
          queueId: q.id,
          type: enums.log.information,
          status: enums.status.active,
          retryCount: job('retryCount'),
          processCount: job('processCount'),
          message: enums.message.active
        })
      },
      null
    )
  }
}
<|endoftext|>


<commit_before>/* jshint mocha: true, expr: true, strict: false */

describe('test suite', function() {
  it('should assert true', function () {
    true.should.be.true;
    false.should.be.false;
  });
});

describe('hello', function () {
  it('should return world', function () {
    hello().should.equal('world');
  });
});

describe('getStock', function () {
  it('should return the stock object', function (done){
    getStock('AAPL', function(stock){
      stock.Name.should.equal('Apple Inc');
      done();
    });
   });
    it('should return another stock object', function (done){
    getStock('MSFT', function(stock){
      stock.Name.should.equal('Microsrp Corp');
      done();
    });
  });
});
  describe('addStockToTable', function() {
    it('should use stock info to append the table', function() {
      var stock = { Name: "SuperCorp", Symbol: "SCRP", LastPrice: 34.32 };
      $('tr').length.should.equal(0);
      addStockToTable(stock);
      $('tr').length.should.equal(1);
    });
  });

<commit_msg>added additional tests to check appending elements created with ajax response data<commit_after>/* jshint mocha: true, expr: true, strict: false */

describe('test suite', function() {
  it('should assert true', function () {
    true.should.be.true;
    false.should.be.false;
  });
});

describe('hello', function () {
  it('should return world', function () {
    hello().should.equal('world');
  });
});

describe('getStock', function () {
  it('should return the stock object', function (done){
    getStock('AAPL', function(stock){
      stock.Name.should.equal('Apple Inc');
      done();
    });
   });
    it('should return another stock object', function (done){
    getStock('MSFT', function(stock){
      stock.Name.should.equal('Microsoft Corp');
      done();
    });
  });
});
  describe('addStockToTable', function() {
    it('should add a row to the table', function() {
      var stock = { Name: "SuperCorp", Symbol: "SCRP", LastPrice: 34.32 };
      $('tr').length.should.equal(0);
      addStockToTable(stock);
      $('tr').length.should.equal(1);
    });
    it('should add two stocks to the table, using stock data from ajax call', function() {
      var stock = { Name: "SuperCorp", Symbol: "SCRP", LastPrice: 34.32 };
           $row = addStockToTable(stock);
           $tds = $row.find('td');
      $tds.length.should.equal(3);
      $($tds[0]).text().should.equal('SuperCorp');
      $($tds[1]).text().should.equal('SCRP');
      $($tds[2]).text().should.equal('34.32');
    });
  });

<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, regexp: true plusplus: true */
/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoShell client API for cluster operation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var arangosh = require("org/arangodb/arangosh");
var db = require("org/arangodb").db;

function Planner (userConfig) {
  "use strict";
  if (typeof userConfig !== "object") {
    throw "userConfig must be an object";
  }
  var r = db._connection.POST("/_admin/clusterPlanner",
                              JSON.stringify(userConfig));
  r = arangosh.checkRequestResult(r);
  this.clusterPlan = r.clusterPlan;
  this.config = r.config;
}

Planner.prototype.getPlan = function () {
  return this.clusterPlan;
};

function Kickstarter (clusterPlan, myname) {
  "use strict";
  if (typeof clusterPlan !== "object") {
    throw "clusterPlan must be an object";
  }
  this.clusterPlan = clusterPlan;
  if (myname === undefined) {
    this.myname = "me";
  }
  else {
    this.myname = myname;
  }
}

Kickstarter.prototype.launch = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "launch",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  arangosh.checkRequestResult(r);
  this.runInfo = r.runInfo;
  return r;
};

Kickstarter.prototype.shutdown = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "shutdown",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname,
                                              "runInfo": this.runInfo}));
  arangosh.checkRequestResult(r);
  return r;
};

Kickstarter.prototype.relaunch = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "relaunch",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  arangosh.checkRequestResult(r);
  this.runInfo = r.runInfo;
  return r;
};

Kickstarter.prototype.cleanup = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "cleanup",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  arangosh.checkRequestResult(r);
  return r;
};

Kickstarter.prototype.isHealthy = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "isHealthy",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname,
                                              "runInfo": this.runInfo}));
  arangosh.checkRequestResult(r);
  return r;
};

exports.Planner = Planner;
exports.Kickstarter = Kickstarter;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:
<commit_msg>Improve error reporting in arangosh with kickstarter.<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, regexp: true plusplus: true */
/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoShell client API for cluster operation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var arangosh = require("org/arangodb/arangosh");
var db = require("org/arangodb").db;

function Planner (userConfig) {
  "use strict";
  if (typeof userConfig !== "object") {
    throw "userConfig must be an object";
  }
  var r = db._connection.POST("/_admin/clusterPlanner",
                              JSON.stringify(userConfig));
  r = arangosh.checkRequestResult(r);
  this.clusterPlan = r.clusterPlan;
  this.config = r.config;
}

Planner.prototype.getPlan = function () {
  return this.clusterPlan;
};

function Kickstarter (clusterPlan, myname) {
  "use strict";
  if (typeof clusterPlan !== "object") {
    throw "clusterPlan must be an object";
  }
  this.clusterPlan = clusterPlan;
  if (myname === undefined) {
    this.myname = "me";
  }
  else {
    this.myname = myname;
  }
}

Kickstarter.prototype.launch = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "launch",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  this.runInfo = r.runInfo;
  return r;
};

Kickstarter.prototype.shutdown = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "shutdown",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname,
                                              "runInfo": this.runInfo}));
  return r;
};

Kickstarter.prototype.relaunch = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "relaunch",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  this.runInfo = r.runInfo;
  return r;
};

Kickstarter.prototype.cleanup = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "cleanup",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname}));
  return r;
};

Kickstarter.prototype.isHealthy = function () {
  "use strict";
  var r = db._connection.POST("/_admin/clusterDispatch",
                              JSON.stringify({"action": "isHealthy",
                                              "clusterPlan": this.clusterPlan,
                                              "myname": this.myname,
                                              "runInfo": this.runInfo}));
  return r;
};

exports.Planner = Planner;
exports.Kickstarter = Kickstarter;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:
<|endoftext|>