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

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

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

// 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 debounce from 'lodash/debounce';
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();

    }

    updateEl = debounce(() => {

        const {
            isHeadFixed, isFootFixed,
            onGetBodyScrollerEl, onGetHeadScrollerEl, onGetFootScrollerEl
        } = this.props;

        onGetBodyScrollerEl && this.bodyScroller && this.bodyScroller.current
        && onGetBodyScrollerEl(findDOMNode(this.bodyScroller.current));

        isHeadFixed && onGetHeadScrollerEl && this.headScroller && this.headScroller.current
        && onGetHeadScrollerEl(findDOMNode(this.headScroller.current));

        isFootFixed && onGetFootScrollerEl && this.footScroller && this.footScroller.current
        && onGetFootScrollerEl(findDOMNode(this.footScroller.current));

    }, 250);

    componentDidUpdate() {
        this.updateEl();
    }

    render() {

        const {

            className, style, bodyScrollerStyle, maskStyle, tableStyle, footStyle,
            fixed, columns, headColumns, bodyColumns, isHeadHidden, isFootHidden, isHeadFixed, isFootFixed,
            scrolling, scroll, hasFixedLeftColumn, hasFixedRightColumn, onScroll, onWheel,

            // not passing down these props
            onGetHeadScrollerEl, onGetBodyScrollerEl, onGetFootScrollerEl,

            ...restProps

        } = this.props;

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

        const overflowHidden = fixed === HorizontalAlign.LEFT,
            horizontalOverflowScroll = !fixed || fixed === HorizontalAlign.CENTER;

        return (

                {
                    !isHeadHidden && isHeadFixed ?

                            <ScrollableTable ref={this.headScroller}
                                             className="scroll-table-head-scroller"
                                             scroll={scroll}
                                             overflowHidden={overflowHidden}
                                             horizontalOverflowScroll={horizontalOverflowScroll}
                                             onScroll={onScroll}>
                                <BaseTable {...restProps}
                                           style={tableStyle}
                                           fixed={fixed}
                                           fragment={TableFragment.HEAD}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}/>
                            </ScrollableTable>

                        :
                        null
                }

                    <ScrollableTable ref={this.bodyScroller}
                                     className="scroll-table-body-scroller"
                                     style={bodyScrollerStyle}
                                     scroll={scroll}
                                     onScroll={onScroll}
                                     onWheel={onWheel}>

                            <BaseTable {...restProps}
                                       style={tableStyle}
                                       fixed={fixed}
                                       columns={columns}
                                       headColumns={headColumns}
                                       bodyColumns={bodyColumns}
                                       isHeadFixed={isHeadFixed}
                                       isFootFixed={isFootFixed}
                                       isHeadHidden={isHeadHidden}
                                       isFootHidden={isFootHidden}/>

                    </ScrollableTable>

                {
                    !isFootHidden && isFootFixed ?

                            <ScrollableTable ref={this.footScroller}
                                             className="scroll-table-foot-scroller"
                                             scroll={scroll}
                                             overflowHidden={overflowHidden}
                                             horizontalOverflowScroll={horizontalOverflowScroll}
                                             onScroll={onScroll}>
                                <BaseTable {...restProps}
                                           style={tableStyle}
                                           fixed={fixed}
                                           fragment={TableFragment.FOOT}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}/>
                            </ScrollableTable>

                        :
                        null
                }

        );

    }
}

ScrollTable.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    bodyScrollerStyle: PropTypes.object,
    maskStyle: PropTypes.object,
    tableStyle: PropTypes.object,
    footStyle: 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({

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

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

        /**
         * 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,

        /**
         * 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,

        /**
         * 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,

        /**
         * 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,

    data: PropTypes.array,
    value: PropTypes.array,
    hoverRowIndex: PropTypes.number,
    baseColIndex: PropTypes.number,
    expandRows: PropTypes.array,

    /**
     * scroll
     */
    scrolling: PropTypes.bool,
    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,

    /**
     * fixed
     */
    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,

    /**
     * callback
     */
    onGetBodyScrollerEl: PropTypes.func,
    onGetHeadScrollerEl: PropTypes.func,
    onGetFootScrollerEl: PropTypes.func,
    onExpandChange: PropTypes.func,
    onScroll: PropTypes.func,
    onWheel: PropTypes.func,
    onSortChange: PropTypes.func,
    onRowHover: PropTypes.func

};

ScrollTable.defaultProps = {

    selectMode: SelectMode.SINGLE_SELECT,
    selectAllMode: SelectAllMode.CURRENT_PAGE,

    baseColIndex: 0,
    expandRows: [],

    /**
     * scroll
     */
    scrolling: false,

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

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

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

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

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

};

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

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

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

// 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 debounce from 'lodash/debounce';
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();

    }

    updateEl = debounce(() => {

        const {
            isHeadFixed, isFootFixed,
            onGetBodyScrollerEl, onGetHeadScrollerEl, onGetFootScrollerEl
        } = this.props;

        onGetBodyScrollerEl && this.bodyScroller && this.bodyScroller.current
        && onGetBodyScrollerEl(findDOMNode(this.bodyScroller.current));

        isHeadFixed && onGetHeadScrollerEl && this.headScroller && this.headScroller.current
        && onGetHeadScrollerEl(findDOMNode(this.headScroller.current));

        isFootFixed && onGetFootScrollerEl && this.footScroller && this.footScroller.current
        && onGetFootScrollerEl(findDOMNode(this.footScroller.current));

    }, 250);

    componentDidUpdate() {
        this.updateEl();
    }

    render() {

        const {

            className, style, bodyScrollerStyle, maskStyle, tableStyle, footStyle,
            fixed, columns, headColumns, bodyColumns, isHeadHidden, isFootHidden, isHeadFixed, isFootFixed,
            scrolling, scroll, hasFixedLeftColumn, hasFixedRightColumn, onScroll, onWheel,

            // not passing down these props
            onGetHeadScrollerEl, onGetBodyScrollerEl, onGetFootScrollerEl,

            ...restProps

        } = this.props;

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

        const overflowHidden = fixed === HorizontalAlign.LEFT,
            horizontalOverflowScroll = !fixed || fixed === HorizontalAlign.CENTER;

        return (

                {
                    !isHeadHidden && isHeadFixed ?

                            <ScrollableTable ref={this.headScroller}
                                             className="scroll-table-head-scroller"
                                             scroll={scroll}
                                             overflowHidden={overflowHidden}
                                             horizontalOverflowScroll={horizontalOverflowScroll}
                                             onScroll={onScroll}>
                                <BaseTable {...restProps}
                                           style={tableStyle}
                                           fixed={fixed}
                                           fragment={TableFragment.HEAD}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}/>
                            </ScrollableTable>

                        :
                        null
                }

                    <ScrollableTable ref={this.bodyScroller}
                                     className="scroll-table-body-scroller"
                                     style={bodyScrollerStyle}
                                     scroll={scroll}
                                     onScroll={onScroll}
                                     onWheel={onWheel}>

                            <BaseTable {...restProps}
                                       style={tableStyle}
                                       fixed={fixed}
                                       columns={columns}
                                       headColumns={headColumns}
                                       bodyColumns={bodyColumns}
                                       isHeadFixed={isHeadFixed}
                                       isFootFixed={isFootFixed}
                                       isHeadHidden={isHeadHidden}
                                       isFootHidden={isFootHidden}/>

                    </ScrollableTable>

                {
                    !isFootHidden && isFootFixed ?

                            <ScrollableTable ref={this.footScroller}
                                             className="scroll-table-foot-scroller"
                                             scroll={scroll}
                                             overflowHidden={overflowHidden}
                                             horizontalOverflowScroll={horizontalOverflowScroll}
                                             onScroll={onScroll}>
                                <BaseTable {...restProps}
                                           style={tableStyle}
                                           fixed={fixed}
                                           fragment={TableFragment.FOOT}
                                           columns={columns}
                                           headColumns={headColumns}
                                           bodyColumns={bodyColumns}/>
                            </ScrollableTable>

                        :
                        null
                }

        );

    }
}

ScrollTable.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    bodyScrollerStyle: PropTypes.object,
    maskStyle: PropTypes.object,
    tableStyle: PropTypes.object,
    footStyle: 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({

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

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

        /**
         * 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,

        /**
         * 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,

        /**
         * 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,

        /**
         * 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,

    data: PropTypes.array,
    value: PropTypes.array,
    hoverRowIndex: PropTypes.number,
    baseColIndex: PropTypes.number,
    expandRows: PropTypes.array,

    /**
     * scroll
     */
    scrolling: PropTypes.bool,
    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
     */
    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,

    /**
     * callback
     */
    onGetBodyScrollerEl: PropTypes.func,
    onGetHeadScrollerEl: PropTypes.func,
    onGetFootScrollerEl: PropTypes.func,
    onExpandChange: PropTypes.func,
    onScroll: PropTypes.func,
    onWheel: PropTypes.func,
    onSortChange: PropTypes.func,
    onRowHover: PropTypes.func

};

ScrollTable.defaultProps = {

    selectMode: SelectMode.SINGLE_SELECT,
    selectAllMode: SelectAllMode.CURRENT_PAGE,

    baseColIndex: 0,
    expandRows: [],

    /**
     * scroll
     */
    scrolling: false,

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

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

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

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

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

};

export default ScrollTable;
<|endoftext|>


<commit_before>// TODO: create a event handlers to proxy mouseDragged, et al
// TODO: create a scheduler so that after we step through "draw" we cna step through "mouseDragged" if necessary

// setup editor
var editor = ace.edit("editor");
editor.setTheme("ace/theme/chrome");
var session = editor.getSession();
session.setMode("ace/mode/javascript");

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext('2d');
var processing = new Processing(canvas);

// init canvas
processing.size(400,400);
processing.resetMatrix();

var getFunctionBody = function(func) {
    var funcString = func.toString();
    var start = funcString.indexOf("{") + 2;
    var end = funcString.lastIndexOf("}");
    return funcString.substring(start, end);
};

// code to run
var code = getFunctionBody(function () {
background(255);
noStroke();

var randomColor = function () {
    var r;
    r = random(255);
    var g = random(255);
    var b = random(255);
    fill(r,g,b);
};

for (var i = 0; i < 3; i++) {
    randomColor();
    ellipse(random(400),random(400),75,75);
}

draw = function () {
    randomColor();
    var p = new PVector(random(400), random(400));
    ellipse(p.x, p.y, 75, 75);
    p.x += 10;
    p.y += 20;
    var x = p.x;
    var y = p.y;
    ellipse(x, y, 75, 75);
};
});

editor.getSession().setValue(code);
var stepper = new Stepper(processing);

var finishedMain = false;

function timeout() {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 100 / 60);  // 60 fps
        // TODO: grab the actual fps from processing
    });
}

function loop() {
    editor.setHighlightActiveLine(false);
    disableButtons();

    if (finishedMain) {
        stepper.runGenWithPromises(processing.draw())
            .then(function () {
                return timeout();
            })
            .then(function () {
                enableButtons();
                if (stepper.halted()) {
                    loop();
                } else {
                    updateView(stepper);
                }
            }, function () {
                console.log("stopped");
            });
    } else {
        stepper.runWithPromises()
            .then(function () {
                enableButtons();
                if (stepper.halted()) {
                    finishedMain = true;
                    loop();
                } else {
                    updateView(stepper);
                }
            }, function () {
                console.log("stopped");
            });
    }
}

$("#startButton").click(function () {
    // reset processing
    processing.size(400,400);
    processing.resetMatrix();

    // reload the code and run it
    code = session.getValue();
    stepper.load(code);
    finishedMain = false;

    loop();
});

// TODO: make continue run until it halts
$("#continueButton").click(function () {
    var action = stepper.stepOut();
    if (stepper.halted()) {
        finishedMain = true;
        disableButtons();
        editor.setHighlightActiveLine(false);
        loop();
        return;
    }

    updateView(stepper, action);
});

$("#stepInButton").click(function () {
    var action = stepper.stepIn();
    if (stepper.halted()) {
        finishedMain = true;
        disableButtons();
        editor.setHighlightActiveLine(false);
        loop();
        return;
    }

    updateView(stepper, action);
});

$("#stepOverButton").click(function () {
    var action = stepper.stepOver();
    if (stepper.halted()) {
        disableButtons();
        editor.setHighlightActiveLine(false);
        if (finishedMain) {
            loop();
        }
        return;
    }

    updateView(stepper, action);
});

$("#stepOutButton").click(function () {
    var action = stepper.stepOut();
    if (stepper.halted()) {
        disableButtons();
        editor.setHighlightActiveLine(false);
        if (finishedMain) {
            loop();
        }
        return;
    }

    updateView(stepper, action);
});

function disableButtons() {
    $("#continueButton,#stepOverButton,#stepInButton,#stepOutButton").attr("disabled", "");
}

function enableButtons() {
    $("#continueButton,#stepOverButton,#stepInButton,#stepOutButton").removeAttr("disabled");
}

// set/clear breakpoints by clicking in the gutter
editor.on("guttermousedown", function(e){
    var target = e.domEvent.target;
    if (target.className.indexOf("ace_gutter-cell") == -1) {
        return;
    }

    // only set a breakpoint when clicking on the left side of the target
    if (e.clientX > 25 + target.getBoundingClientRect().left) {
        return;
    }

    var row = parseInt(e.domEvent.target.innerText);

    if (e.editor.session.getBreakpoints()[row - 1]) {
        e.editor.session.clearBreakpoint(row - 1);
        stepper.clearBreakpoint(row);
    } else {
        e.editor.session.setBreakpoint(row - 1);
        stepper.setBreakpoint(row);
    }

    e.stop();
});

function updateLocals(stepper, action) {
    if (stepper.halted()) {
        return;
    }
    var scope = stepper.stack.peek().scope;
    var $variableList = $("#variableList");

    if (action && action.type === "stepOver") {
        // don't take any action
    } else {
        $variableList.empty();
        if (!scope) {
            return;
        }
        $variableList.append(genPropsList(scope));
    }
}

function updateCallStack(stepper) {
    var $callStack = $("#callStack");
    $callStack.empty();

    if (stepper.halted()) {
        return;
    }

    var scope = stepper.stack.peek().scope;

    if (!scope) {
        return;
    }

    var $ul = $("

");
    stepper.stack.values.forEach(function (frame) {
        var $name = $("").text(frame.name);
        var $line = $("").text(frame.line).css({ float: "right" });
        $ul.prepend($("

").append($name, $line));
    });
    $callStack.append($ul);
}

function updateView(stepper, action) {
    updateLocals(stepper, action);
    updateCallStack(stepper);
    editor.gotoLine(stepper.line());
    editor.setHighlightActiveLine(true);
}
<commit_msg>fixed continue so that it will run to the next breakpoint or to the end of the outermost function and halt<commit_after>// TODO: create a event handlers to proxy mouseDragged, et al
// TODO: create a scheduler so that after we step through "draw" we cna step through "mouseDragged" if necessary

// setup editor
var editor = ace.edit("editor");
editor.setTheme("ace/theme/chrome");
var session = editor.getSession();
session.setMode("ace/mode/javascript");

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext('2d');
var processing = new Processing(canvas);

// init canvas
processing.size(400,400);
processing.resetMatrix();

var getFunctionBody = function(func) {
    var funcString = func.toString();
    var start = funcString.indexOf("{") + 2;
    var end = funcString.lastIndexOf("}");
    return funcString.substring(start, end);
};

// code to run
var code = getFunctionBody(function () {
background(255);
noStroke();

var randomColor = function () {
    var r;
    r = random(255);
    var g = random(255);
    var b = random(255);
    fill(r,g,b);
};

for (var i = 0; i < 3; i++) {
    randomColor();
    ellipse(random(400),random(400),75,75);
}

draw = function () {
    randomColor();
    var p = new PVector(random(400), random(400));
    ellipse(p.x, p.y, 75, 75);
    p.x += 10;
    p.y += 20;
    var x = p.x;
    var y = p.y;
    ellipse(x, y, 75, 75);
};
});

editor.getSession().setValue(code);
var stepper = new Stepper(processing);

var finishedMain = false;

function timeout() {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 100 / 60);  // 60 fps
        // TODO: grab the actual fps from processing
    });
}

function loop() {
    editor.setHighlightActiveLine(false);
    disableButtons();

    if (finishedMain) {
        if (stepper.halted()) {
            stepper.runGenWithPromises(processing.draw())
                .then(function () {
                    return timeout();
                })
                .then(function () {
                    enableButtons();
                    if (stepper.halted()) {
                        loop();
                    } else {
                        updateView(stepper);
                    }
                }, function () {
                    console.log("stopped");
                });
        } else {
            stepper.runWithPromises()
                .then(function () {
                    enableButtons();
                    if (stepper.halted()) {
                        loop();
                    } else {
                        updateView(stepper);
                    }
                }, function () {
                    console.log("stopped");
                });
        }
    } else {
        stepper.runWithPromises()
            .then(function () {
                enableButtons();
                if (stepper.halted()) {
                    finishedMain = true;
                    loop();
                } else {
                    updateView(stepper);
                }
            }, function () {
                console.log("stopped");
            });
    }
}

$("#startButton").click(function () {
    // reset processing
    processing.size(400,400);
    processing.resetMatrix();

    // reload the code and run it
    code = session.getValue();
    stepper.load(code);
    finishedMain = false;

    loop();
});

$("#continueButton").click(function () {
    loop();
});

$("#stepInButton").click(function () {
    var action = stepper.stepIn();
    if (stepper.halted()) {
        finishedMain = true;
        disableButtons();
        editor.setHighlightActiveLine(false);
        loop();
        return;
    }

    updateView(stepper, action);
});

$("#stepOverButton").click(function () {
    var action = stepper.stepOver();
    if (stepper.halted()) {
        disableButtons();
        editor.setHighlightActiveLine(false);
        if (finishedMain) {
            loop();
        }
        return;
    }

    updateView(stepper, action);
});

$("#stepOutButton").click(function () {
    var action = stepper.stepOut();
    if (stepper.halted()) {
        disableButtons();
        editor.setHighlightActiveLine(false);
        if (finishedMain) {
            loop();
        }
        return;
    }

    updateView(stepper, action);
});

function disableButtons() {
    $("#continueButton,#stepOverButton,#stepInButton,#stepOutButton").attr("disabled", "");
}

function enableButtons() {
    $("#continueButton,#stepOverButton,#stepInButton,#stepOutButton").removeAttr("disabled");
}

// set/clear breakpoints by clicking in the gutter
editor.on("guttermousedown", function(e){
    var target = e.domEvent.target;
    if (target.className.indexOf("ace_gutter-cell") == -1) {
        return;
    }

    // only set a breakpoint when clicking on the left side of the target
    if (e.clientX > 25 + target.getBoundingClientRect().left) {
        return;
    }

    var row = parseInt(e.domEvent.target.innerText);

    if (e.editor.session.getBreakpoints()[row - 1]) {
        e.editor.session.clearBreakpoint(row - 1);
        stepper.clearBreakpoint(row);
    } else {
        e.editor.session.setBreakpoint(row - 1);
        stepper.setBreakpoint(row);
    }

    e.stop();
});

function updateLocals(stepper, action) {
    if (stepper.halted()) {
        return;
    }
    var scope = stepper.stack.peek().scope;
    var $variableList = $("#variableList");

    if (action && action.type === "stepOver") {
        // don't take any action
    } else {
        $variableList.empty();
        if (!scope) {
            return;
        }
        $variableList.append(genPropsList(scope));
    }
}

function updateCallStack(stepper) {
    var $callStack = $("#callStack");
    $callStack.empty();

    if (stepper.halted()) {
        return;
    }

    var scope = stepper.stack.peek().scope;

    if (!scope) {
        return;
    }

    var $ul = $("

");
    stepper.stack.values.forEach(function (frame) {
        var $name = $("").text(frame.name);
        var $line = $("").text(frame.line).css({ float: "right" });
        $ul.prepend($("

").append($name, $line));
    });
    $callStack.append($ul);
}

function updateView(stepper, action) {
    updateLocals(stepper, action);
    updateCallStack(stepper);
    editor.gotoLine(stepper.line());
    editor.setHighlightActiveLine(true);
}
<|endoftext|>


<commit_before>var _ = require('underscore');

function extractName(areaJson) {
  return areaJson.Name;
}

function extractId(areaJson) {
  if (parseInt(areaJson.Id, 10) < 10) {
    return "0" + parseInt(areaJson.Id, 10);
  } else {
    return areaJson.Id;
  }
}

function extractWarningLevel(warningJson) {
  if (warningJson.hasOwnProperty('DangerLevel')) {
    return warningJson.DangerLevel;
  } else if (warningJson.hasOwnProperty('ActivityLevel')) {
    return warningJson.ActivityLevel;
  } else if (warningJson.hasOwnProperty('Rating')) {
    return warningJson.Rating;
  }
}

function extractTypeId(areaJson) {
  if (areaJson.hasOwnProperty('TypeId')) {
    return areaJson.TypeId;
  }
}

function cleanWarning(warningJson) {
  // Deleting unused and/or unnecessary fields
  warningJson.Rating = extractWarningLevel(warningJson);

  // Avalanche
  delete warningJson.DangerLevel;
  delete warningJson.UtmEast;
  delete warningJson.UtmNorth;
  delete warningJson.UtmZone;

  // Flood, Landlside
  delete warningJson.ActivityLevel;
  delete warningJson.MunicipalityCsvString;
  delete warningJson.MunicipalityList;
  delete warningJson.CountyList;
  delete warningJson.StationList;
  delete warningJson.Id;
  delete warningJson.MasterId;
  delete warningJson.EventId;

  return warningJson;
}

function cleanForecast(forecastJson) {
  var cleanedForecastJson = {};
  _.each(forecastJson, function(warningJson, key) {
    cleanedForecastJson["day" + key] = cleanWarning(warningJson);
  });

  return cleanedForecastJson;
}

function extractForecast(areaJson) {
  if (areaJson.hasOwnProperty('AvalancheWarningList')) {
    return areaJson.AvalancheWarningList;
  } else if (areaJson.hasOwnProperty('WarningList')) {
    return areaJson.WarningList;
  } else {
    return [];
  }
}

function extractChildAreasJson(areaJson) {
  if (areaJson.hasOwnProperty('MunicipalityList')) {
    return areaJson.MunicipalityList;
  }
}

function createHighestLevelForecast(forecasts) {
  var highestForecast = [];
  _.each(forecasts, function(forecast) {
    _.each(forecast, function(warning, i) {
      if (!highestForecast[i] || (highestForecast[i] < extractWarningLevel(warning))) {
        highestForecast[i] = warning;
      }
    });
  });
  return highestForecast;
}

function transformToForecast(areasJson) {
  if (!areasJson || areasJson.length === 0) {
    return [];
  }

  var areas = [];

  _.each(areasJson, function(areaJson) {
    var area = {
      Id: extractId(areaJson),
      Name: extractName(areaJson),
      Forecast: cleanForecast(extractForecast(areaJson)),
      Children: transformToForecast(extractChildAreasJson(areaJson))
    };

    if(extractTypeId(areaJson)) {
      area.TypeId = extractTypeId(areaJson);
    }

    if (area.Children.length > 0) {
      area.Forecast = createHighestLevelForecast(_.pluck(area.Children, 'Forecast'));
    }

    areas.push(area);
  });

  return areas;
}

function transformToAreas(areasJson) {
  if (!areasJson || areasJson.length === 0) {
    return [];
  }

  var areas = [];

  _.each(areasJson, function(areaJson) {
    var area = {
      Id: extractId(areaJson),
      Name: extractName(areaJson),
      Children: transformToAreas(extractChildAreasJson(areaJson))
    };

    areas.push(area);
  });

  return areas;
}

function denormalize(areasJson) {
  var parents = {};
  var children = {};

  _.each(areasJson, function(areaJson) {
    parents["id" + areaJson.Id] = areaJson;
    children["id" + areaJson.Id] = {};

    _.each(areaJson.Children, function(childArea) {
      children["id" + areaJson.Id]["id" + childArea.Id] = childArea;
    });

    delete parents["id" + areaJson.Id].Children;
  });

  return {
    parents: parents,
    children: children
  };
}

module.exports = {
  transformToForecast: function(json) {
    return denormalize(transformToForecast(json));
  },
  transformToAreas: function(json) {
    return denormalize(transformToAreas(json));
  }

};
<commit_msg>Removed some more fields from avalanche forecasts<commit_after>var _ = require('underscore');

function extractName(areaJson) {
  return areaJson.Name;
}

function extractId(areaJson) {
  if (parseInt(areaJson.Id, 10) < 10) {
    return "0" + parseInt(areaJson.Id, 10);
  } else {
    return areaJson.Id;
  }
}

function extractWarningLevel(warningJson) {
  if (warningJson.hasOwnProperty('DangerLevel')) {
    return warningJson.DangerLevel;
  } else if (warningJson.hasOwnProperty('ActivityLevel')) {
    return warningJson.ActivityLevel;
  } else if (warningJson.hasOwnProperty('Rating')) {
    return warningJson.Rating;
  }
}

function extractTypeId(areaJson) {
  if (areaJson.hasOwnProperty('TypeId')) {
    return areaJson.TypeId;
  }
}

function cleanWarning(warningJson) {
  // Deleting unused and/or unnecessary fields
  warningJson.Rating = extractWarningLevel(warningJson);

  // Avalanche
  delete warningJson.DangerLevel;
  delete warningJson.UtmEast;
  delete warningJson.UtmNorth;
  delete warningJson.UtmZone;
  delete warningJson.LangKey;
  delete warningJson.RegId;
  delete warningJson.RegionId;
  delete warningJson.RegionName;
  delete warningJson.RegionTypeId;
  delete warningJson.RegionTypeName;
  delete warningJson.MunicipalityName;

  // Flood, Landlside
  delete warningJson.ActivityLevel;
  delete warningJson.MunicipalityCsvString;
  delete warningJson.MunicipalityList;
  delete warningJson.CountyList;
  delete warningJson.StationList;
  delete warningJson.Id;
  delete warningJson.MasterId;
  delete warningJson.EventId;
  delete warningJson.Version;

  return warningJson;
}

function cleanForecast(forecastJson) {
  var cleanedForecastJson = {};
  _.each(forecastJson, function(warningJson, key) {
    cleanedForecastJson["day" + key] = cleanWarning(warningJson);
  });

  return cleanedForecastJson;
}

function extractForecast(areaJson) {
  if (areaJson.hasOwnProperty('AvalancheWarningList')) {
    return areaJson.AvalancheWarningList;
  } else if (areaJson.hasOwnProperty('WarningList')) {
    return areaJson.WarningList;
  } else {
    return [];
  }
}

function extractChildAreasJson(areaJson) {
  if (areaJson.hasOwnProperty('MunicipalityList')) {
    return areaJson.MunicipalityList;
  }
}

function createHighestLevelForecast(forecasts) {
  var highestForecast = [];
  _.each(forecasts, function(forecast) {
    _.each(forecast, function(warning, i) {
      if (!highestForecast[i] || (highestForecast[i] < extractWarningLevel(warning))) {
        highestForecast[i] = warning;
      }
    });
  });
  return highestForecast;
}

function transformToForecast(areasJson) {
  if (!areasJson || areasJson.length === 0) {
    return [];
  }

  var areas = [];

  _.each(areasJson, function(areaJson) {
    var area = {
      Id: extractId(areaJson),
      Name: extractName(areaJson),
      Forecast: cleanForecast(extractForecast(areaJson)),
      Children: transformToForecast(extractChildAreasJson(areaJson))
    };

    if(extractTypeId(areaJson)) {
      area.TypeId = extractTypeId(areaJson);
    }

    if (area.Children.length > 0) {
      area.Forecast = createHighestLevelForecast(_.pluck(area.Children, 'Forecast'));
    }

    areas.push(area);
  });

  return areas;
}

function transformToAreas(areasJson) {
  if (!areasJson || areasJson.length === 0) {
    return [];
  }

  var areas = [];

  _.each(areasJson, function(areaJson) {
    var area = {
      Id: extractId(areaJson),
      Name: extractName(areaJson),
      Children: transformToAreas(extractChildAreasJson(areaJson))
    };

    areas.push(area);
  });

  return areas;
}

function denormalize(areasJson) {
  var parents = {};
  var children = {};

  _.each(areasJson, function(areaJson) {
    parents["id" + areaJson.Id] = areaJson;
    children["id" + areaJson.Id] = {};

    _.each(areaJson.Children, function(childArea) {
      children["id" + areaJson.Id]["id" + childArea.Id] = childArea;
    });

    delete parents["id" + areaJson.Id].Children;
  });

  return {
    parents: parents,
    children: children
  };
}

module.exports = {
  transformToForecast: function(json) {
    return denormalize(transformToForecast(json));
  },
  transformToAreas: function(json) {
    return denormalize(transformToAreas(json));
  }

};
<|endoftext|>


<commit_before><commit_msg>AG-3316 agGridReact needs to be updated to use the updated react lifecycle hooks<commit_after><|endoftext|>


<commit_before>define([
	"qunit",
	"inputmask.dependencyLib",
	"inputmask",
	"../dist/inputmask/inputmask.date.extensions",
	"../dist/inputmask/inputmask.extensions",
	"../dist/inputmask/inputmask.numeric.extensions",
	"../dist/inputmask/inputmask.phone.extensions",
	"../dist/inputmask/inputmask.regex.extensions",
	"prototypeExtensions",
	"simulator"
], function (qunit, $, Inputmask) {

	qunit.module("Optional");
	qunit.test("inputmask(\"(99) 9999[9]-99999\") - input 121234-12345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("(99) 9999[9]-99999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("121234-12345");

		assert.equal(testmask.value, "(12) 1234-12345", "Result " + testmask.value);
	});
	qunit.test("inputmask(\"(99) 9999[9]-99999\") - input 121234512345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("(99) 9999[9]-99999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("121234512345");

		assert.equal(testmask.value, "(12) 12345-12345", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: true }) - input 123", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123");
		assert.equal(testmask.value, "123__", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123");
		assert.equal(testmask.value, "123__", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 12345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12345");
		assert.equal(testmask.value, "12345", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		assert.equal(testmask.value, "12345-6", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456789", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456789");
		assert.equal(testmask.value, "12345-6789", "Result " + testmask.value);
	});

	qunit.test("inputmask(\"9[9][9] 999[9] 9999\") - input 123123 space 1234 - vipink70", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("9[9][9] 999[9] 9999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("123123");
		$("#testmask").SendKey(Inputmask.keyCode.SPACE);
		$("#testmask").Type("1234");
		assert.equal(testmask.value, "123 123 1234", "Result " + testmask.value);
	});

	qunit.test("inputmask('[9-]AAA.999') ", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('[9-]AAA.999').mask(testmask);

		$("#testmask").Type("1abc123");
		$.caret(testmask, 4, 5);
		$("#testmask").Type("d");
		assert.equal(testmask.value, "1-ABD.123", "Result " + testmask.value);
	});

	qunit.test("inputmask('9[9]:99') ", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('9[9]:99').mask(testmask);

		$("#testmask").Type("3:44");
		$.caret(testmask, 1);
		$("#testmask").Type("3");
		assert.equal(testmask.value, "33:44", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		testmask.blur();
		$("#testmask").trigger("mouseenter");
		assert.equal(testmask.value, "12345-6___", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"9'9{1,2}\"\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9'9{1,2}\"",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "1'2\"", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99{1,2}lb\\s\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99{1,2}lb\\s",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "12lbs", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"9'9[9]\"\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9'9[9]\"",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "1'2\"", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99[9]lb\\s\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99[9]lb\\s",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "12lbs", "Result " + testmask.value);
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false }); - type 123456 backspace iscomplete?", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		assert.equal(testmask.inputmask.isComplete(), true, "Result " + testmask.inputmask.isComplete());
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false }); type 123456 backspace blur", function (assert) {
		var $fixture = $("#qunit-fixture"), done = assert.async();
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		testmask.blur();
		setTimeout(function () {
			assert.equal($("#testmask")[0].inputmask._valueGet(), "12345", "Result " + $("#testmask")[0].inputmask._valueGet());
			done();
		}, 0);
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false, autoUnmask: true }); type 123456 backspace", function (assert) {
		var $fixture = $("#qunit-fixture"), done = assert.async();
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false,
			autoUnmask: true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		setTimeout(function () {
			assert.equal(testmask.value, "12345", "Result " + testmask.value);
			done();
		}, 0);
	});

	qunit.test(".inputmask('999-999-9999[ ext 9{1,5}]'); - type 12345678901 backspace iscomplete? - antch", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('999-999-9999[ ext 9{1,5}]').mask(testmask);

		testmask.focus();
		$("#testmask").Type("12345678901");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		assert.equal(testmask.inputmask.isComplete(), true, "Result " + testmask.inputmask.isComplete());
	});

	qunit.test("inputmask({ mask: \"9999[ 9999][ 9999]\"}) - input 1234 space space - GMTA", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9999[ 9999][ 9999]"
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("1234  ");
		assert.equal(testmask.value, "1234", "Result " + testmask.value);
	});

});
<commit_msg>Added test for #1375<commit_after>define([
	"qunit",
	"inputmask.dependencyLib",
	"inputmask",
	"../dist/inputmask/inputmask.date.extensions",
	"../dist/inputmask/inputmask.extensions",
	"../dist/inputmask/inputmask.numeric.extensions",
	"../dist/inputmask/inputmask.phone.extensions",
	"../dist/inputmask/inputmask.regex.extensions",
	"prototypeExtensions",
	"simulator"
], function (qunit, $, Inputmask) {

	qunit.module("Optional");
	qunit.test("inputmask(\"(99) 9999[9]-99999\") - input 121234-12345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("(99) 9999[9]-99999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("121234-12345");

		assert.equal(testmask.value, "(12) 1234-12345", "Result " + testmask.value);
	});
	qunit.test("inputmask(\"(99) 9999[9]-99999\") - input 121234512345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("(99) 9999[9]-99999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("121234512345");

		assert.equal(testmask.value, "(12) 12345-12345", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: true }) - input 123", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123");
		assert.equal(testmask.value, "123__", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123");
		assert.equal(testmask.value, "123__", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 12345", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12345");
		assert.equal(testmask.value, "12345", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		assert.equal(testmask.value, "12345-6", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456789", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456789");
		assert.equal(testmask.value, "12345-6789", "Result " + testmask.value);
	});

	qunit.test("inputmask(\"9[9][9] 999[9] 9999\") - input 123123 space 1234 - vipink70", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("9[9][9] 999[9] 9999").mask(testmask);

		testmask.focus();
		$("#testmask").Type("123123");
		$("#testmask").SendKey(Inputmask.keyCode.SPACE);
		$("#testmask").Type("1234");
		assert.equal(testmask.value, "123 123 1234", "Result " + testmask.value);
	});

	qunit.test("inputmask('[9-]AAA.999') ", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('[9-]AAA.999').mask(testmask);

		$("#testmask").Type("1abc123");
		$.caret(testmask, 4, 5);
		$("#testmask").Type("d");
		assert.equal(testmask.value, "1-ABD.123", "Result " + testmask.value);
	});

	qunit.test("inputmask('9[9]:99') ", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('9[9]:99').mask(testmask);

		$("#testmask").Type("3:44");
		$.caret(testmask, 1);
		$("#testmask").Type("3");
		assert.equal(testmask.value, "33:44", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99999[-9999]",
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		testmask.blur();
		$("#testmask").trigger("mouseenter");
		assert.equal(testmask.value, "12345-6___", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"9'9{1,2}\"\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9'9{1,2}\"",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "1'2\"", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99{1,2}lb\\s\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99{1,2}lb\\s",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "12lbs", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"9'9[9]\"\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9'9[9]\"",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "1'2\"", "Result " + testmask.value);
	});

	qunit.test("inputmask({ mask: \"99[9]lb\\s\", greedy: false, skipOptionalPartCharacter: \"\", \"clearIncomplete\": true  }) - input 12 blur - thomstark", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "99[9]lb\\s",
			greedy: false,
			skipOptionalPartCharacter: "",
			"clearIncomplete": true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("12");
		testmask.blur();
		assert.equal(testmask.value, "12lbs", "Result " + testmask.value);
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false }); - type 123456 backspace iscomplete?", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		assert.equal(testmask.inputmask.isComplete(), true, "Result " + testmask.inputmask.isComplete());
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false }); type 123456 backspace blur", function (assert) {
		var $fixture = $("#qunit-fixture"), done = assert.async();
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		testmask.blur();
		setTimeout(function () {
			assert.equal($("#testmask")[0].inputmask._valueGet(), "12345", "Result " + $("#testmask")[0].inputmask._valueGet());
			done();
		}, 0);
	});

	qunit.test(".inputmask(\"99999[-9999]\", { greedy: false, autoUnmask: true }); type 123456 backspace", function (assert) {
		var $fixture = $("#qunit-fixture"), done = assert.async();
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask("99999[-9999]", {
			greedy: false,
			autoUnmask: true
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("123456");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		setTimeout(function () {
			assert.equal(testmask.value, "12345", "Result " + testmask.value);
			done();
		}, 0);
	});

	qunit.test(".inputmask('999-999-9999[ ext 9{1,5}]'); - type 12345678901 backspace iscomplete? - antch", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask('999-999-9999[ ext 9{1,5}]').mask(testmask);

		testmask.focus();
		$("#testmask").Type("12345678901");
		$("#testmask").SendKey(Inputmask.keyCode.BACKSPACE);
		assert.equal(testmask.inputmask.isComplete(), true, "Result " + testmask.inputmask.isComplete());
	});

	qunit.test("inputmask({ mask: \"9999[ 9999][ 9999]\"}) - input 1234 space space - GMTA", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: "9999[ 9999][ 9999]"
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("1234  ");
		assert.equal(testmask.value, "1234", "Result " + testmask.value);
	});

	qunit.test("9999[ 9999][ 9999][ 9999][ 999] - Enfree", function (assert) {
		var $fixture = $("#qunit-fixture");
		$fixture.append('<input type="text" id="testmask" />');
		var testmask = document.getElementById("testmask");
		Inputmask({
			mask: '9999[ 9999][ 9999][ 9999][ 999]',
			placeholder: '', greedy: false
		}).mask(testmask);

		testmask.focus();
		$("#testmask").Type("45464748");
		$.caret(testmask, 2);
		$("#testmask").Type("0909");

		assert.equal(testmask.value, "4546 0909 4748", "Result " + testmask.value);
	});

})
;
<|endoftext|>


<commit_before>(function () {

  'use strict';

  /**
   * @ngdoc function
   * @name atacamaApp.controller:WidgetController
   * @description
   * # WidgetController
   * Controller of the atacamaApp
   */
  angular.module('atacamaApp')
    .controller('OhlcWidgetController', OhlcWidgetController);

  function OhlcWidgetController(
    $scope, ngstomp, $resource, $log, Restangular,
    elasticsearchService, chartService, turbineService, utilService, widgetService) {
    var vm = this;

    // adjustments to make the chart fit better in the widget...
    // TODO it works in the browser, but PhantomJS gives this error
    // if we use ES6 keyword 'const' for these variables..
    // PhantomJS 2.1.1 (Linux 0.0.0) ERROR SyntaxError: Unexpected token 'const'
    const adjustX = -35;
    var adjustY = -65;

    // TODO select market in UI
    var market = 'FTSE100';

    var topic = '';
    var esError = '';
    var stompError = '';

    vm.Status = _.keyBy(['WAITING', 'LOADING', 'LOADED', 'ERROR'], _.identity);

    vm.status = vm.Status.WAITING;

    //vm.isLoaded = false;
    //vm.hasError = false;

    // load the saved values...
    vm.selectedSymbol = $scope.item.symbol;
    vm.dateFrom = $scope.item.dateFrom;

    $scope.$watchGroup(['vm.selectedSymbol', 'vm.dateFrom'], function (newValues, oldValues) {
      if (!vm.selectedSymbol || !vm.dateFrom) {
        return;
      }
      $scope.item.symbol = vm.selectedSymbol;
      $scope.item.dateFrom = vm.dateFrom;
      vm.dateFrom.setHours(0);
      vm.dateFrom.setMinutes(0);
      vm.dateFrom.setSeconds(0);
      $log.log('detected updates: old:{0}, new:{1}'.format(
        angular.toJson(oldValues), angular.toJson(newValues)));
      doChart($scope.item);
    }, false);

    // $scope.$watch('vm.data', function (data) {
    //   $log.info("vm.data change:" + angular.toJson(vm.data));
    // }, false);

    // vm.selectSymbol = function (selectedSymbol) {
    //   vm.selectedSymbol = selectedSymbol;
    //   $log.log('select symbol: ', vm.selectedSymbol);
    //   doChart($scope.item);
    // };

    // TODO centralise the rest call data more so widgets can share the results...
    // {"stocks":[{"market":"FTSE100","symbol":"ABC"},{"market":"FTSE100","symbol":"DEF"}]}
    // {"indicators":[{"overlay":true,"name":"BollingerBands"},{"overlay":false,"name":"SMA12"}]}
    // {"strategies":[{"name":"SMAStrategy"},{"name":"CCICorrectionStrategy"}]}

    // fetchStocks();

    // $scope.strategies = [
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'}
    // ];

    // set the size of the chart as the widget is resized...
    $scope.$on('gridster-item-resized', function (item, gridsterWidget) {
      // $log.debug('gridster-item-resized offset {0}x{1}'.format($scope.offsetParent.prop('offsetWidth'), $scope.offsetParent.prop('offsetHeight')));
      // $log.debug('gridster-item-resized dimensions {0}x{1}'.format(gridsterWidget.getElementSizeX(), gridsterWidget.getElementSizeY()));
      //vm.options.chart.height = firstHeight + ((item.targetScope.gridsterItem.sizeY - 1) * nextHeight);
      //vm.options.chart.width = firstWidth + ((item.targetScope.gridsterItem.sizeX - 1) * nextWidth);
      //console.log('offsetHeight:' + $scope.offsetParent.prop('offsetHeight'));
      //console.log('offsetWidth:' + $scope.offsetParent.prop('offsetWidth'));

      $log.debug('gridster-item-resized {0}x{1}'.format(
        gridsterWidget.getElementSizeX(), gridsterWidget.getElementSizeY()));
      vm.options.chart.width = gridsterWidget.getElementSizeX() + adjustX;
      vm.options.chart.height = gridsterWidget.getElementSizeY() + adjustY;
      // TODO now causes an error... is this needed?
      // $scope.api.update();
    });

    // $scope.$watch('vm.values', function (newValues) {
    //   if (newValues) {
    //     vm.data = [{
    //       key: vm.selectedSymbol,
    //       values: newValues
    //     }];
    //   }
    // }, true);

    // ---------------------- datepicker stuff below ------------------
    vm.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
    vm.format = vm.formats[0];
    vm.altInputFormats = ['M!/d!/yyyy'];

    vm.dateOptions = {
      // dateDisabled: isDisabled,
      formatYear: 'yy',
      // maxDate: new Date(2020, 5, 22),
      // minDate: new Date(),
      startingDay: 1
    };

    vm.popup1 = {
      opened: false
    };

    // Disable weekend selection
    vm.isDisabled = function(date, mode) {
      return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);
    };

    vm.today = function() {
      var dateFrom = new Date();
      dateFrom.setHours(0);
      dateFrom.setMinutes(0);
      dateFrom.setSeconds(0);
      vm.dateFrom = dateFrom;
    };

    vm.clear = function() {
      vm.dateFrom = null;
    };

    vm.open1 = function() {
      vm.popup1.opened = true;
    };

    vm.today();

    // ---------------------- datepicker stuff above ------------------

    vm.reset = function () {
      $log.debug('reset()');

      vm.status = vm.Status.WAITING;
      // vm.isLoaded = false;
      // vm.hasError = false;

      vm.options = {
        chart: {
          // TODO error message appears in console...
        }
      };

      vm.config = {
        deepWatchData: true,
        // deepWatchDataDepth: 1,
        refreshDataOnly: false,
        disabled: true
      };

      vm.data = [];
      // vm.data = {key: vm.selectedSymbol, values: [{}]};
      // vm.data = {key: '', values: [{}]};

    };

    vm.reset();

    function initialise() {
      vm.config = {
        deepWatchData: true,
        // deepWatchDataDepth: 1,
        refreshDataOnly: false,
        disabled: false
      };

      vm.options = {
        chart: {
          type: 'candlestickBarChart',
          // type: 'ohlcBarChart',
          // width: $scope.offsetParent.prop('offsetWidth') + adjustX,
          // height: $scope.offsetParent.prop('offsetHeight') + adjustY,
          width: $scope.gridsterItem.getElementSizeX() + adjustX,
          height: $scope.gridsterItem.getElementSizeY() + adjustY,
          margin: {
            top: 20,
            right: 40,
            bottom: 40,
            left: 40
          },
          x: function (d) {
            return d.date;
          },
          y: function (d) {
            return d.close;
          },
          showValues: true,
          transitionDuration: 500,
          xAxis: {
            // axisLabel: 'Dates',
            tickFormat: function (d) {
              return d3.time.format('%X')(new Date(d));
            },
          },
          yAxis: {
            // axisLabel: 'Stock Price',
            tickFormat: function (d, i) {
              return '$' + d3.format(',.1f')(d);
            }
          }
        }
      };
    }

    // for smart-table...
    // $scope.addStrategies = function(widget) {
    //    console.log("widget.js::addStrategies");
    //    reset();
    //    $scope.typeStrategies = true;
    //    unsubscribeTopic();
    //  };

    // I don't think this is necessary anymore...
    // $scope.$on('$destroy', function() {
    //   utilService.unsubscribeTopic(topic);
    // });

    // function fetchStocks() {
    //   turbineService.symbols(market).then(function (response) {
    //     // console.log(angular.toJson(response.stocks));
    //     vm.symbols = _.map(response.stocks, 'symbol');
    //     // $scope.selectedSymbol = $scope.symbols[0];
    //   }, function (err) {
    //     esError = 'unable to load symbols: {0}'.format(err.message);
    //     $log.error(esError);
    //   });
    // }

    function fetchHistoricDataFromES(from) {
      var promise = elasticsearchService.getTicksAfter(market, vm.selectedSymbol, from);

      promise.then(function (response) {
        utilService.traceLog($scope.item, "elasticsearch");
        var result = elasticsearchService.parseResults(response);
        vm.data = [{
          key: vm.selectedSymbol,
          values: result
        }];

      }, function (err) {
        esError = 'unable to load data: {0}:{1}'.format(vm.selectedSymbol, err.message);
        $log.error(esError);
      });
    }

    function subscribeToStompUpdates() {
      topic = '/topic/ticks.' + market + '.' + vm.selectedSymbol;
      //ngstomp.subscribe(topic, onMessage, {}, $scope);

      try {
        ngstomp
          .subscribeTo(topic)
          .callback(onMessage)
          .withBodyInJson()
          .bindTo($scope)
          .connect();
        // throw new Error("unable to subscribe to topic: " + topic);
      } catch (err) {
        stompError = 'unable to connect to: {0}:{1}'.format(topic, err.message);
        $log.error(stompError);
      }
    }

    function onMessage(message) {
      // TODO avoid $scope?
      utilService.traceLog($scope.item, "rabbit");
      // vm.data[0].values.push(JSON.parse(message.body));
      vm.data[0].values.push(message.body);
      $scope.$apply();
    }

    function doChart(item) {
      if (!vm.selectedSymbol) {
        return;
      }

      $log.debug("ohlc.controller.js::doChart");
      vm.status = vm.Status.LOADING;
      // $scope.item = item;
      // item.name = vm.selectedSymbol;
      vm.reset();
      // vm.typeOHLC = true;
      utilService.unsubscribeTopic(topic);

      initialise();

      // $scope.message = moment();

      // var ticks = Restangular.one('tick').one($scope.selectedSymbol).one(sod);

      // ticks.get().then(function(response) {
      //     vm.data[0].values = response.ticks;
      // });

      utilService.traceLog(item, "elasticsearch");

      // var sod = moment(0, "HH").format("x");
      var from = moment(vm.dateFrom).format("x");
      fetchHistoricDataFromES(from);

      subscribeToStompUpdates();

      vm.status = vm.Status.LOADED;
      // vm.isLoaded = true;

      // TODO catch all errors and set the property and message as required
      if (esError !== '' || stompError !== '') {
        vm.status = vm.Status.ERROR;
        vm.hasError = true;
      }

    }

  }

})();
<commit_msg>issue #16 remove 'const' keyword (again!)<commit_after>(function () {

  'use strict';

  /**
   * @ngdoc function
   * @name atacamaApp.controller:WidgetController
   * @description
   * # WidgetController
   * Controller of the atacamaApp
   */
  angular.module('atacamaApp')
    .controller('OhlcWidgetController', OhlcWidgetController);

  function OhlcWidgetController(
    $scope, ngstomp, $resource, $log, Restangular,
    elasticsearchService, chartService, turbineService, utilService, widgetService) {
    var vm = this;

    // adjustments to make the chart fit better in the widget...
    // TODO it works in the browser, but PhantomJS gives this error
    // if we use ES6 keyword 'const' for these variables..
    // PhantomJS 2.1.1 (Linux 0.0.0) ERROR SyntaxError: Unexpected token 'const'
    var adjustX = -35;
    var adjustY = -65;

    // TODO select market in UI
    var market = 'FTSE100';

    var topic = '';
    var esError = '';
    var stompError = '';

    vm.Status = _.keyBy(['WAITING', 'LOADING', 'LOADED', 'ERROR'], _.identity);

    vm.status = vm.Status.WAITING;

    //vm.isLoaded = false;
    //vm.hasError = false;

    // load the saved values...
    vm.selectedSymbol = $scope.item.symbol;
    vm.dateFrom = $scope.item.dateFrom;

    $scope.$watchGroup(['vm.selectedSymbol', 'vm.dateFrom'], function (newValues, oldValues) {
      if (!vm.selectedSymbol || !vm.dateFrom) {
        return;
      }
      $scope.item.symbol = vm.selectedSymbol;
      $scope.item.dateFrom = vm.dateFrom;
      vm.dateFrom.setHours(0);
      vm.dateFrom.setMinutes(0);
      vm.dateFrom.setSeconds(0);
      $log.log('detected updates: old:{0}, new:{1}'.format(
        angular.toJson(oldValues), angular.toJson(newValues)));
      doChart($scope.item);
    }, false);

    // $scope.$watch('vm.data', function (data) {
    //   $log.info("vm.data change:" + angular.toJson(vm.data));
    // }, false);

    // vm.selectSymbol = function (selectedSymbol) {
    //   vm.selectedSymbol = selectedSymbol;
    //   $log.log('select symbol: ', vm.selectedSymbol);
    //   doChart($scope.item);
    // };

    // TODO centralise the rest call data more so widgets can share the results...
    // {"stocks":[{"market":"FTSE100","symbol":"ABC"},{"market":"FTSE100","symbol":"DEF"}]}
    // {"indicators":[{"overlay":true,"name":"BollingerBands"},{"overlay":false,"name":"SMA12"}]}
    // {"strategies":[{"name":"SMAStrategy"},{"name":"CCICorrectionStrategy"}]}

    // fetchStocks();

    // $scope.strategies = [
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'},
    //   { action: 'sell', symbol: 'ABC', market: 'FTSE100'},
    //   { action: 'buy', symbol: 'DEF', market: 'FTSE100'}
    // ];

    // set the size of the chart as the widget is resized...
    $scope.$on('gridster-item-resized', function (item, gridsterWidget) {
      // $log.debug('gridster-item-resized offset {0}x{1}'.format($scope.offsetParent.prop('offsetWidth'), $scope.offsetParent.prop('offsetHeight')));
      // $log.debug('gridster-item-resized dimensions {0}x{1}'.format(gridsterWidget.getElementSizeX(), gridsterWidget.getElementSizeY()));
      //vm.options.chart.height = firstHeight + ((item.targetScope.gridsterItem.sizeY - 1) * nextHeight);
      //vm.options.chart.width = firstWidth + ((item.targetScope.gridsterItem.sizeX - 1) * nextWidth);
      //console.log('offsetHeight:' + $scope.offsetParent.prop('offsetHeight'));
      //console.log('offsetWidth:' + $scope.offsetParent.prop('offsetWidth'));

      $log.debug('gridster-item-resized {0}x{1}'.format(
        gridsterWidget.getElementSizeX(), gridsterWidget.getElementSizeY()));
      vm.options.chart.width = gridsterWidget.getElementSizeX() + adjustX;
      vm.options.chart.height = gridsterWidget.getElementSizeY() + adjustY;
      // TODO now causes an error... is this needed?
      // $scope.api.update();
    });

    // $scope.$watch('vm.values', function (newValues) {
    //   if (newValues) {
    //     vm.data = [{
    //       key: vm.selectedSymbol,
    //       values: newValues
    //     }];
    //   }
    // }, true);

    // ---------------------- datepicker stuff below ------------------
    vm.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
    vm.format = vm.formats[0];
    vm.altInputFormats = ['M!/d!/yyyy'];

    vm.dateOptions = {
      // dateDisabled: isDisabled,
      formatYear: 'yy',
      // maxDate: new Date(2020, 5, 22),
      // minDate: new Date(),
      startingDay: 1
    };

    vm.popup1 = {
      opened: false
    };

    // Disable weekend selection
    vm.isDisabled = function(date, mode) {
      return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);
    };

    vm.today = function() {
      var dateFrom = new Date();
      dateFrom.setHours(0);
      dateFrom.setMinutes(0);
      dateFrom.setSeconds(0);
      vm.dateFrom = dateFrom;
    };

    vm.clear = function() {
      vm.dateFrom = null;
    };

    vm.open1 = function() {
      vm.popup1.opened = true;
    };

    vm.today();

    // ---------------------- datepicker stuff above ------------------

    vm.reset = function () {
      $log.debug('reset()');

      vm.status = vm.Status.WAITING;
      // vm.isLoaded = false;
      // vm.hasError = false;

      vm.options = {
        chart: {
          // TODO error message appears in console...
        }
      };

      vm.config = {
        deepWatchData: true,
        // deepWatchDataDepth: 1,
        refreshDataOnly: false,
        disabled: true
      };

      vm.data = [];
      // vm.data = {key: vm.selectedSymbol, values: [{}]};
      // vm.data = {key: '', values: [{}]};

    };

    vm.reset();

    function initialise() {
      vm.config = {
        deepWatchData: true,
        // deepWatchDataDepth: 1,
        refreshDataOnly: false,
        disabled: false
      };

      vm.options = {
        chart: {
          type: 'candlestickBarChart',
          // type: 'ohlcBarChart',
          // width: $scope.offsetParent.prop('offsetWidth') + adjustX,
          // height: $scope.offsetParent.prop('offsetHeight') + adjustY,
          width: $scope.gridsterItem.getElementSizeX() + adjustX,
          height: $scope.gridsterItem.getElementSizeY() + adjustY,
          margin: {
            top: 20,
            right: 40,
            bottom: 40,
            left: 40
          },
          x: function (d) {
            return d.date;
          },
          y: function (d) {
            return d.close;
          },
          showValues: true,
          transitionDuration: 500,
          xAxis: {
            // axisLabel: 'Dates',
            tickFormat: function (d) {
              return d3.time.format('%X')(new Date(d));
            },
          },
          yAxis: {
            // axisLabel: 'Stock Price',
            tickFormat: function (d, i) {
              return '$' + d3.format(',.1f')(d);
            }
          }
        }
      };
    }

    // for smart-table...
    // $scope.addStrategies = function(widget) {
    //    console.log("widget.js::addStrategies");
    //    reset();
    //    $scope.typeStrategies = true;
    //    unsubscribeTopic();
    //  };

    // I don't think this is necessary anymore...
    // $scope.$on('$destroy', function() {
    //   utilService.unsubscribeTopic(topic);
    // });

    // function fetchStocks() {
    //   turbineService.symbols(market).then(function (response) {
    //     // console.log(angular.toJson(response.stocks));
    //     vm.symbols = _.map(response.stocks, 'symbol');
    //     // $scope.selectedSymbol = $scope.symbols[0];
    //   }, function (err) {
    //     esError = 'unable to load symbols: {0}'.format(err.message);
    //     $log.error(esError);
    //   });
    // }

    function fetchHistoricDataFromES(from) {
      var promise = elasticsearchService.getTicksAfter(market, vm.selectedSymbol, from);

      promise.then(function (response) {
        utilService.traceLog($scope.item, "elasticsearch");
        var result = elasticsearchService.parseResults(response);
        vm.data = [{
          key: vm.selectedSymbol,
          values: result
        }];

      }, function (err) {
        esError = 'unable to load data: {0}:{1}'.format(vm.selectedSymbol, err.message);
        $log.error(esError);
      });
    }

    function subscribeToStompUpdates() {
      topic = '/topic/ticks.' + market + '.' + vm.selectedSymbol;
      //ngstomp.subscribe(topic, onMessage, {}, $scope);

      try {
        ngstomp
          .subscribeTo(topic)
          .callback(onMessage)
          .withBodyInJson()
          .bindTo($scope)
          .connect();
        // throw new Error("unable to subscribe to topic: " + topic);
      } catch (err) {
        stompError = 'unable to connect to: {0}:{1}'.format(topic, err.message);
        $log.error(stompError);
      }
    }

    function onMessage(message) {
      // TODO avoid $scope?
      utilService.traceLog($scope.item, "rabbit");
      // vm.data[0].values.push(JSON.parse(message.body));
      vm.data[0].values.push(message.body);
      $scope.$apply();
    }

    function doChart(item) {
      if (!vm.selectedSymbol) {
        return;
      }

      $log.debug("ohlc.controller.js::doChart");
      vm.status = vm.Status.LOADING;
      // $scope.item = item;
      // item.name = vm.selectedSymbol;
      vm.reset();
      // vm.typeOHLC = true;
      utilService.unsubscribeTopic(topic);

      initialise();

      // $scope.message = moment();

      // var ticks = Restangular.one('tick').one($scope.selectedSymbol).one(sod);

      // ticks.get().then(function(response) {
      //     vm.data[0].values = response.ticks;
      // });

      utilService.traceLog(item, "elasticsearch");

      // var sod = moment(0, "HH").format("x");
      var from = moment(vm.dateFrom).format("x");
      fetchHistoricDataFromES(from);

      subscribeToStompUpdates();

      vm.status = vm.Status.LOADED;
      // vm.isLoaded = true;

      // TODO catch all errors and set the property and message as required
      if (esError !== '' || stompError !== '') {
        vm.status = vm.Status.ERROR;
        vm.hasError = true;
      }

    }

  }

})();
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import Input from 'components/Input';
import Button from 'components/Button';
import { slugify } from 'utils/helpers';

export default class NewBlockModal extends Component {
  static propTypes = {
    confirm: PropTypes.func.isRequired,
    close: PropTypes.func,
  }

  static defaultProps = {
    close: null,
  }

  constructor(props) {
    super(props);
    this.confirm = this.confirm.bind(this);
    this.handleTitleChange = this.handleTitleChange.bind(this);
  }

  state = { title: '' }

  confirm() {
    this.props.confirm({
      name: this.name.value,
      handle: slugify(this.state.title),
      fields: [{
        label: 'Blank',
        handle: 'blank-0',
      }],
    });
    this.props.close();
  }

  handleTitleChange(title) {
    this.setState({ title });
  }

  render() {
    const { close } = this.props;

    return (

        <Input
          name="name"
          label="Name"
          required
          ref={(r) => { this.name = r; }}
          instructions="What this block will be called in the dashboard."
          onChange={this.handleTitleChange}
          full
          autoFocus
        />
        <Input
          name="handle"
          label="Handle"
          required
          readOnly
          ref={(r) => { this.handle = r; }}
          instructions="How you'll refer to this block type in your templates."
          full
          code
          value={slugify(this.state.title)}
        />

          <Button small onClick={this.confirm}>Confirm</Button>
          <Button small onClick={close} kind="subtle">Cancel</Button>

    );
  }
}
<commit_msg>:musical_keyboard: Add Enter handler to confirm<commit_after>import React, { Component, PropTypes } from 'react';
import Input from 'components/Input';
import Button from 'components/Button';
import { slugify } from 'utils/helpers';

export default class NewBlockModal extends Component {
  static propTypes = {
    confirm: PropTypes.func.isRequired,
    close: PropTypes.func,
  }

  static defaultProps = {
    close: null,
  }

  constructor(props) {
    super(props);
    this.confirm = this.confirm.bind(this);
    this.handleTitleChange = this.handleTitleChange.bind(this);
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }

  state = { title: '' }

  confirm() {
    this.props.confirm({
      name: this.name.value,
      handle: slugify(this.state.title),
      fields: [{
        label: 'Blank',
        handle: 'blank-0',
      }],
    });
    this.props.close();
  }

  handleTitleChange(title) {
    this.setState({ title });
  }

  handleKeyPress(e) {
    if (e.key === 'Enter') this.confirm();
  }

  render() {
    const { close } = this.props;

    return (

        <Input
          name="name"
          label="Name"
          required
          ref={(r) => { this.name = r; }}
          instructions="What this block will be called in the dashboard."
          onChange={this.handleTitleChange}
          full
          autoFocus
          onKeyPress={this.handleKeyPress}
        />
        <Input
          name="handle"
          label="Handle"
          required
          readOnly
          ref={(r) => { this.handle = r; }}
          instructions="How you'll refer to this block type in your templates."
          full
          code
          value={slugify(this.state.title)}
        />

          <Button small onClick={this.confirm}>Confirm</Button>
          <Button small onClick={close} kind="subtle">Cancel</Button>

    );
  }
}
<|endoftext|>