<commit_before>/**
 * @file TableLayout vendor
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import sum from 'lodash/sum';
import addClass from 'dom-helpers/class/addClass';
import removeClass from 'dom-helpers/class/removeClass';

import TableFragment from '../_statics/TableFragment';
import HorizontalAlign from '../_statics/HorizontalAlign';
import Direction from '../_statics/Direction';
import ScrollBar from './ScrollBar';

/**
 * whether a table has a fixed head or a fixed foot or fixed left columns or fixed right columns
 * @param props
 * @param columns
 * @returns {boolean}
 */
function hasFixed(props, columns) {

    if (props && (props.isHeadFixed || props.isFootFixed)) {
        return true;
    }

    if (!columns) {
        return false;
    }

    if ((columns[HorizontalAlign.LEFT] && columns[HorizontalAlign.LEFT].length > 0)
        || (columns[HorizontalAlign.RIGHT] && columns[HorizontalAlign.RIGHT].length > 0)) {
        return true;
    }

    return false;

}

/**
 * calculate each head, body and foot column width
 * @returns {null|{[p: string]: *|*}}
 */
function getColumnsWidth(tableEl) {

    if (!tableEl) {
        return null;
    }

    return {
        [TableFragment.HEAD]: [].map.call(tableEl.querySelector('thead tr').querySelectorAll('th'),
            el => el.offsetWidth),
        [TableFragment.BODY]: [].map.call(tableEl.querySelector('tbody tr').querySelectorAll('td'),
            el => el.offsetWidth),
        [TableFragment.FOOT]: [].map.call(tableEl.querySelector('tfoot tr').querySelectorAll('td'),
            el => el.offsetWidth)
    };

}

/**
 * calculate each head, body and foot row height
 * @returns {null|{[p: string]: *|*}}
 */
function getRowsHeight(tableEl) {

    if (!tableEl) {
        return null;
    }

    return {
        [TableFragment.HEAD]: [].map.call(tableEl.querySelectorAll('thead tr'),
            el => el.offsetHeight),
        [TableFragment.BODY]: [].map.call(tableEl.querySelectorAll('tbody tr'),
            el => el.offsetHeight),
        [TableFragment.FOOT]: [].map.call(tableEl.querySelectorAll('tfoot tr'),
            el => el.offsetHeight)
    };

}

/**
 * calculate table body scroller height
 * @param headHeight
 * @param footHeight
 * @returns {{height: string}}
 */
function getbodyScollerHeight(headHeight, footHeight) {
    return `calc(100%${headHeight ? ` - ${sum(headHeight)}px` : ''}${footHeight ? ` - ${sum(footHeight)}px` : ''})`;
}

function maskCenterBody(wrapperEl, tableEl, fixedHeadHeight, fixedFootHeight) {
    const el = wrapperEl.querySelector('.table-content-center .scrollable-table-body-mask');
    if (el) {
        el.style.height = `${tableEl.offsetHeight - fixedHeadHeight - fixedFootHeight - 2}px`;
        const table = el.querySelector('table');
        if (table) {
            table.style.marginTop = `${-fixedHeadHeight - 1}px`;
        }
    }
}

function fixFragmentWidth(wrapperEl, columnsWidth, fixed, fragment, selector) {

    const el = wrapperEl.querySelector(`${selector} .scrollable-table-${fragment}-scroller`);

    if (el) {
        const cols = el.querySelectorAll('col');
        if (cols) {
            if (fixed === HorizontalAlign.RIGHT) {
                cols.forEach((el, index) => {
                    if (el) {
                        el.style.width = `${columnsWidth[fragment]
                            [columnsWidth[fragment].length - (cols.length - index)]}px`;
                    }
                });
            } else {
                cols.forEach((el, index) => {
                    if (el) {
                        el.style.width = `${columnsWidth[fragment][index]}px`;
                    }
                });
            }
        }
    }

}

function fixTableWidth(wrapperEl, columnsWidth, fixed, props) {

    if (!wrapperEl) {
        return;
    }

    const selector = `.table-content-${fixed || 'center'}`;

    /**
     * head
     */
    if (props && props.isHeadFixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.HEAD, selector);
    }

    /**
     * body
     */
    if (fixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.BODY, selector);
    }

    /**
     * foot
     */
    if (props && props.isHeadFixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.FOOT, selector);
    }

}

function fixFragmentHeight(wrapperEl, rowsHeight, fixed, fragment, selector) {

    const el = wrapperEl.querySelector(`${selector} .scrollable-table-${fragment} t${fragment}`);

    if (el) {
        const trs = el.querySelectorAll('tr');
        if (trs) {
            trs.forEach((el, index) => {
                if (el) {
                    el.style.height = `${rowsHeight[fragment][index]}px`;
                }
            });
        }
    }

}

function fixTableHeight(wrapperEl, rowsHeight, fixed, props) {

    if (!wrapperEl) {
        return;
    }

    const selector = `.table-content-${fixed || 'center'}`;

    /**
     * head
     */
    if (props && props.isHeadFixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.HEAD, selector);
    }

    /**
     * body
     */
    if (fixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.BODY, selector);
    }

    /**
     * foot
     */
    if (props && props.isHeadFixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.FOOT, selector);
    }

}

function handleHorizontalScrollStyle(el, shouldScroll, size = ScrollBar.getSize(Direction.HORIZONTAL)) {

    if (!el) {
        return;
    }

    if (!shouldScroll) {
        el.style.marginBottom = 0;
        el.style.paddingBottom = 0;
    } else if (size && size > 0) {
        el.style.marginBottom = `${-size}px`;
        el.style.paddingBottom = 0;
    } else {
        el.style.marginBottom = '-20px';
        el.style.paddingBottom = '20px';
    }

}

function fixTableHorizontalScroll(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    // no need to fix the scroll problem in mac
    const horizontalScrollBarSize = ScrollBar.getSize(Direction.HORIZONTAL);
    if (!horizontalScrollBarSize || horizontalScrollBarSize <= 0) {
        return;
    }

    const centerBody = wrapperEl.querySelector('.table-content-center .scrollable-table-body-scroller'),
        shouldScroll = centerBody.offsetWidth - horizontalScrollBarSize < centerBody.scrollWidth;

    /**
     * center head scroller
     */
    if (props && props.isHeadFixed) {
        const centerHead = wrapperEl.querySelector('.table-content-center .scrollable-table-head-scroller');
        if (centerHead) {
            handleHorizontalScrollStyle(centerHead, shouldScroll, horizontalScrollBarSize);
        }
    }

    /**
     * center foot scroller
     */
    if (props && props.isFootFixed) {
        const centerFoot = wrapperEl.querySelector('.table-content-center .scrollable-table-foot-scroller');
        if (centerFoot) {
            handleHorizontalScrollStyle(centerFoot, shouldScroll, horizontalScrollBarSize);
        }
    }

    /**
     * left body scroller
     */
    const leftBody = wrapperEl.querySelector('.table-content-left .scrollable-table-body-scroller');
    if (leftBody) {
        handleHorizontalScrollStyle(leftBody, shouldScroll, horizontalScrollBarSize);
    }

    /**
     * left body mask
     */
    const leftBodyMask = wrapperEl.querySelector('.table-content-left .scrollable-table-body-mask');
    if (leftBodyMask) {
        leftBodyMask.style.paddingBottom = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * left foot
     */
    const leftFoot = wrapperEl.querySelector('.table-content-left .scrollable-table-foot');
    if (leftFoot) {
        leftFoot.style.marginTop = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * right body scroller
     */
    const rightBody = wrapperEl.querySelector('.table-content-right .scrollable-table-body-scroller');
    if (rightBody) {
        handleHorizontalScrollStyle(rightBody, shouldScroll, horizontalScrollBarSize);
    }

    /**
     * right body mask
     */
    const rightBodyMask = wrapperEl.querySelector('.table-content-right .scrollable-table-body-mask');
    if (rightBodyMask) {
        rightBodyMask.style.paddingBottom = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * right foot
     */
    const rightFoot = wrapperEl.querySelector('.table-content-right .scrollable-table-foot');
    if (rightFoot) {
        rightFoot.style.marginTop = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

}

function fixTableVerticalScroll(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    const verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

    /**
     * fix center head width
     */
    if (props && props.isHeadFixed && verticalScrollBarSize && verticalScrollBarSize > 0) {
        const centerHead = wrapperEl.querySelector('.table-content-center .scrollable-table-head-scroller');
        if (centerHead) {
            centerHead.style.width = `calc(100% - ${verticalScrollBarSize}px)`;
        }
    }

    /**
     * fix center foot width
     */
    if (props && props.isFootFixed && verticalScrollBarSize && verticalScrollBarSize > 0) {
        const centerFoot = wrapperEl.querySelector('.table-content-center .scrollable-table-foot-scroller');
        if (centerFoot) {
            centerFoot.style.width = `calc(100% - ${verticalScrollBarSize}px)`;
        }
    }

    /**
     * fix left body horizontal scroll bar
     */
    const leftBody = wrapperEl.querySelector('.table-content-left .scrollable-table-body-scroller');
    if (leftBody) {
        if (verticalScrollBarSize && verticalScrollBarSize > 0) {
            leftBody.style.marginRight = `-${verticalScrollBarSize}px`;
            leftBody.style.paddingRight = 0;
        } else {
            const leftBodyTable = leftBody.querySelector('table');
            if (leftBodyTable) {
                const restWidth = wrapperEl.offsetWidth - leftBodyTable.offsetWidth;
                leftBody.style.marginRight = `-${restWidth}px`;
                leftBody.style.paddingRight = `${restWidth}px`;
            }
        }
    }

}

function fixLayout(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    const tableEl = wrapperEl.querySelector('.table-content-center .scrollable-table-body table');

    if (!tableEl) {
        return;
    }

    const columnsWidth = getColumnsWidth(tableEl),
        rowsHeight = getRowsHeight(tableEl),

        fixedHeadHeight = sum(rowsHeight[TableFragment.HEAD]) || 0,
        fixedFootHeight = sum(rowsHeight[TableFragment.FOOT]) || 0;

    /**
     * fix horizontal scroll style
     */
    fixTableHorizontalScroll(wrapperEl, props);

    /**
     * center
     */
    maskCenterBody(wrapperEl, tableEl, fixedHeadHeight, fixedFootHeight);
    fixTableWidth(wrapperEl, columnsWidth, null, props);
    fixTableHeight(wrapperEl, rowsHeight, null, props);

    /**
     * left
     */
    fixTableWidth(wrapperEl, columnsWidth, HorizontalAlign.LEFT, props);
    fixTableHeight(wrapperEl, rowsHeight, HorizontalAlign.LEFT, props);

    /**
     * right
     */
    fixTableWidth(wrapperEl, columnsWidth, HorizontalAlign.RIGHT, props);
    fixTableHeight(wrapperEl, rowsHeight, HorizontalAlign.RIGHT, props);

    /**
     * fix vertical scroll style
     */
    fixTableVerticalScroll(wrapperEl, props);

}

function updateHorizontalScrollClassNames(wrapperEl, scrollerEl) {

    if (!wrapperEl || !scrollerEl) {
        return;
    }

    removeClass(wrapperEl, 'scroll-left');
    removeClass(wrapperEl, 'scroll-center');
    removeClass(wrapperEl, 'scroll-right');

    const {scrollWidth, offsetWidth, scrollLeft} = scrollerEl,
        verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

    if (scrollLeft === 0) {
        addClass(wrapperEl, 'scroll-left');
    } else if (scrollLeft === scrollWidth - offsetWidth + verticalScrollBarSize) {
        addClass(wrapperEl, 'scroll-right');
    } else {
        addClass(wrapperEl, 'scroll-center');
    }

}

export default {
    hasFixed,
    getColumnsWidth,
    getRowsHeight,
    getbodyScollerHeight,
    fixLayout,
    updateHorizontalScrollClassNames
};
<commit_msg>update TableLayout<commit_after>/**
 * @file TableLayout vendor
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import sum from 'lodash/sum';
import addClass from 'dom-helpers/class/addClass';
import removeClass from 'dom-helpers/class/removeClass';

import TableFragment from '../_statics/TableFragment';
import HorizontalAlign from '../_statics/HorizontalAlign';
import Direction from '../_statics/Direction';
import ScrollBar from './ScrollBar';

/**
 * whether a table has a fixed head or a fixed foot or fixed left columns or fixed right columns
 * @param props
 * @param columns
 * @returns {boolean}
 */
function hasFixed(props, columns) {

    if (props && (props.isHeadFixed || props.isFootFixed)) {
        return true;
    }

    if (!columns) {
        return false;
    }

    if ((columns[HorizontalAlign.LEFT] && columns[HorizontalAlign.LEFT].length > 0)
        || (columns[HorizontalAlign.RIGHT] && columns[HorizontalAlign.RIGHT].length > 0)) {
        return true;
    }

    return false;

}

/**
 * calculate each head, body and foot column width
 * @returns {null|{[p: string]: *|*}}
 */
function getColumnsWidth(tableEl) {

    if (!tableEl) {
        return null;
    }

    return {
        [TableFragment.HEAD]: [].map.call(tableEl.querySelector('thead tr').querySelectorAll('th'),
            el => el.offsetWidth),
        [TableFragment.BODY]: [].map.call(tableEl.querySelector('tbody tr').querySelectorAll('td'),
            el => el.offsetWidth),
        [TableFragment.FOOT]: [].map.call(tableEl.querySelector('tfoot tr').querySelectorAll('td'),
            el => el.offsetWidth)
    };

}

/**
 * calculate each head, body and foot row height
 * @returns {null|{[p: string]: *|*}}
 */
function getRowsHeight(tableEl) {

    if (!tableEl) {
        return null;
    }

    return {
        [TableFragment.HEAD]: [].map.call(tableEl.querySelectorAll('thead tr'),
            el => el.offsetHeight),
        [TableFragment.BODY]: [].map.call(tableEl.querySelectorAll('tbody tr'),
            el => el.offsetHeight),
        [TableFragment.FOOT]: [].map.call(tableEl.querySelectorAll('tfoot tr'),
            el => el.offsetHeight)
    };

}

/**
 * calculate table body scroller height
 * @param headHeight
 * @param footHeight
 * @returns {{height: string}}
 */
function getbodyScollerHeight(headHeight, footHeight) {
    return `calc(100%${headHeight ? ` - ${sum(headHeight)}px` : ''}${footHeight ? ` - ${sum(footHeight)}px` : ''})`;
}

function maskCenterBody(wrapperEl, tableEl, fixedHeadHeight, fixedFootHeight) {
    const el = wrapperEl.querySelector('.table-content-center .scrollable-table-body-mask');
    if (el) {
        el.style.height = `${tableEl.offsetHeight - fixedHeadHeight - fixedFootHeight - 2}px`;
        const table = el.querySelector('table');
        if (table) {
            table.style.marginTop = `${-fixedHeadHeight - 1}px`;
        }
    }
}

function fixFragmentWidth(wrapperEl, columnsWidth, fixed, fragment, selector) {

    const el = wrapperEl.querySelector(`${selector} .scrollable-table-${fragment}-scroller`);

    if (el) {
        const cols = el.querySelectorAll('col');
        if (cols) {
            if (fixed === HorizontalAlign.RIGHT) {
                cols.forEach((el, index) => {
                    if (el) {
                        el.style.width = `${columnsWidth[fragment]
                            [columnsWidth[fragment].length - (cols.length - index)]}px`;
                    }
                });
            } else {
                cols.forEach((el, index) => {
                    if (el) {
                        el.style.width = `${columnsWidth[fragment][index]}px`;
                    }
                });
            }
        }
    }

}

function fixTableWidth(wrapperEl, columnsWidth, fixed, props) {

    if (!wrapperEl) {
        return;
    }

    const selector = `.table-content-${fixed || 'center'}`;

    /**
     * head
     */
    if (props && props.isHeadFixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.HEAD, selector);
    }

    /**
     * body
     */
    if (fixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.BODY, selector);
    }

    /**
     * foot
     */
    if (props && props.isHeadFixed) {
        fixFragmentWidth(wrapperEl, columnsWidth, fixed, TableFragment.FOOT, selector);
    }

}

function fixFragmentHeight(wrapperEl, rowsHeight, fixed, fragment, selector) {

    const el = wrapperEl.querySelector(`${selector} .scrollable-table-${fragment} t${fragment}`);

    if (el) {
        const trs = el.querySelectorAll('tr');
        if (trs) {
            trs.forEach((el, index) => {
                if (el) {
                    el.style.height = `${rowsHeight[fragment][index]}px`;
                }
            });
        }
    }

}

function fixTableHeight(wrapperEl, rowsHeight, fixed, props) {

    if (!wrapperEl) {
        return;
    }

    const selector = `.table-content-${fixed || 'center'}`;

    /**
     * head
     */
    if (props && props.isHeadFixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.HEAD, selector);
    }

    /**
     * body
     */
    if (fixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.BODY, selector);
    }

    /**
     * foot
     */
    if (props && props.isHeadFixed) {
        fixFragmentHeight(wrapperEl, rowsHeight, fixed, TableFragment.FOOT, selector);
    }

}

function handleHorizontalScrollStyle(el, shouldScroll, size = ScrollBar.getSize(Direction.HORIZONTAL)) {

    if (!el) {
        return;
    }

    if (!shouldScroll) {
        el.style.marginBottom = 0;
        el.style.paddingBottom = 0;
    } else if (size && size > 0) {
        el.style.marginBottom = `${-size}px`;
        el.style.paddingBottom = 0;
    } else {
        el.style.marginBottom = '-20px';
        el.style.paddingBottom = '20px';
    }

}

function fixTableHorizontalScroll(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    // no need to fix the scroll problem in mac
    const horizontalScrollBarSize = ScrollBar.getSize(Direction.HORIZONTAL);
    if (!horizontalScrollBarSize || horizontalScrollBarSize <= 0) {
        return;
    }

    const centerBody = wrapperEl.querySelector('.table-content-center .scrollable-table-body-scroller'),
        shouldScroll = centerBody.offsetWidth - horizontalScrollBarSize < centerBody.scrollWidth;

    /**
     * center head scroller
     */
    if (props && props.isHeadFixed) {
        const centerHead = wrapperEl.querySelector('.table-content-center .scrollable-table-head-scroller');
        if (centerHead) {
            handleHorizontalScrollStyle(centerHead, shouldScroll, horizontalScrollBarSize);
        }
    }

    /**
     * center foot scroller
     */
    if (props && props.isFootFixed) {
        const centerFoot = wrapperEl.querySelector('.table-content-center .scrollable-table-foot-scroller');
        if (centerFoot) {
            handleHorizontalScrollStyle(centerFoot, shouldScroll, horizontalScrollBarSize);
        }
    }

    /**
     * left body scroller
     */
    const leftBody = wrapperEl.querySelector('.table-content-left .scrollable-table-body-scroller');
    if (leftBody) {
        handleHorizontalScrollStyle(leftBody, shouldScroll, horizontalScrollBarSize);
    }

    /**
     * left body mask
     */
    const leftBodyMask = wrapperEl.querySelector('.table-content-left .scrollable-table-body-mask');
    if (leftBodyMask) {
        leftBodyMask.style.paddingBottom = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * left foot
     */
    const leftFoot = wrapperEl.querySelector('.table-content-left .scrollable-table-foot');
    if (leftFoot) {
        leftFoot.style.marginTop = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * right body scroller
     */
    const rightBody = wrapperEl.querySelector('.table-content-right .scrollable-table-body-scroller');
    if (rightBody) {
        handleHorizontalScrollStyle(rightBody, shouldScroll, horizontalScrollBarSize);
    }

    /**
     * right body mask
     */
    const rightBodyMask = wrapperEl.querySelector('.table-content-right .scrollable-table-body-mask');
    if (rightBodyMask) {
        rightBodyMask.style.paddingBottom = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

    /**
     * right foot
     */
    const rightFoot = wrapperEl.querySelector('.table-content-right .scrollable-table-foot');
    if (rightFoot) {
        rightFoot.style.marginTop = shouldScroll ? `${horizontalScrollBarSize}px` : 0;
    }

}

function fixTableVerticalScroll(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    const verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

    /**
     * fix center head width
     */
    if (props && props.isHeadFixed && verticalScrollBarSize && verticalScrollBarSize > 0) {
        const centerHead = wrapperEl.querySelector('.table-content-center .scrollable-table-head-scroller');
        if (centerHead) {
            centerHead.style.width = `calc(100% - ${verticalScrollBarSize}px)`;
        }
    }

    /**
     * fix center foot width
     */
    if (props && props.isFootFixed && verticalScrollBarSize && verticalScrollBarSize > 0) {
        const centerFoot = wrapperEl.querySelector('.table-content-center .scrollable-table-foot-scroller');
        if (centerFoot) {
            centerFoot.style.width = `calc(100% - ${verticalScrollBarSize}px)`;
        }
    }

    /**
     * fix left body horizontal scroll bar
     */
    const leftBody = wrapperEl.querySelector('.table-content-left .scrollable-table-body-scroller');
    if (leftBody) {
        if (verticalScrollBarSize && verticalScrollBarSize > 0) {
            leftBody.style.marginRight = `-${verticalScrollBarSize}px`;
            leftBody.style.paddingRight = 0;
        } else {
            const leftBodyTable = leftBody.querySelector('table');
            if (leftBodyTable) {
                const restWidth = wrapperEl.offsetWidth - leftBodyTable.offsetWidth;
                leftBody.style.marginRight = `-${restWidth}px`;
                leftBody.style.paddingRight = `${restWidth}px`;
            }
        }
    }

}

function fixLayout(wrapperEl, props) {

    if (!wrapperEl) {
        return;
    }

    const tableEl = wrapperEl.querySelector('.table-content-center .scrollable-table-body table');

    if (!tableEl) {
        return;
    }

    const columnsWidth = getColumnsWidth(tableEl),
        rowsHeight = getRowsHeight(tableEl),

        fixedHeadHeight = sum(rowsHeight[TableFragment.HEAD]) || 0,
        fixedFootHeight = sum(rowsHeight[TableFragment.FOOT]) || 0;

    /**
     * fix horizontal scroll style
     */
    fixTableHorizontalScroll(wrapperEl, props);

    /**
     * center
     */
    maskCenterBody(wrapperEl, tableEl, fixedHeadHeight, fixedFootHeight);
    fixTableWidth(wrapperEl, columnsWidth, null, props);
    fixTableHeight(wrapperEl, rowsHeight, null, props);

    /**
     * left
     */
    fixTableWidth(wrapperEl, columnsWidth, HorizontalAlign.LEFT, props);
    fixTableHeight(wrapperEl, rowsHeight, HorizontalAlign.LEFT, props);

    /**
     * right
     */
    fixTableWidth(wrapperEl, columnsWidth, HorizontalAlign.RIGHT, props);
    fixTableHeight(wrapperEl, rowsHeight, HorizontalAlign.RIGHT, props);

    /**
     * fix vertical scroll style
     */
    fixTableVerticalScroll(wrapperEl, props);

}

function updateHorizontalScrollClassNames(wrapperEl, scrollerEl) {

    if (!wrapperEl || !scrollerEl) {
        return;
    }

    removeClass(wrapperEl, 'scroll-left');
    removeClass(wrapperEl, 'scroll-center');
    removeClass(wrapperEl, 'scroll-right');

    const {scrollWidth, offsetWidth, scrollLeft} = scrollerEl,
        verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

    // no scroll
    if (scrollWidth === offsetWidth - verticalScrollBarSize) {
        return;
    }

    if (scrollLeft === 0) {
        addClass(wrapperEl, 'scroll-left');
    } else if (scrollLeft === scrollWidth - offsetWidth + verticalScrollBarSize) {
        addClass(wrapperEl, 'scroll-right');
    } else {
        addClass(wrapperEl, 'scroll-center');
    }

}

export default {
    hasFixed,
    getColumnsWidth,
    getRowsHeight,
    getbodyScollerHeight,
    fixLayout,
    updateHorizontalScrollClassNames
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function (grunt) {
    //grunt.loadNpmTasks('grunt-usemin');

    grunt.initConfig({
        clean: {
            build: ['src/main/webapp/dist', '.tmp']
        },

        copy: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'src/main/webapp/app',
                        src: [
                            'assets/images/**',
                            '**/*.html',
                            '**/*Columns.json',
                            '!testFramework/**/*',
                            'customerManagement/orgsManagement/orgNotes/fixtureData.json'
                        ],
                        dest: 'src/main/webapp/dist'
                    },
                    {
                        expand: true,
                        cwd: 'src/main/webapp/app/testFramework',
                        src: [
                            '**'
                        ],
                        dest: 'src/main/webapp/dist/testFramework'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: [
                            'src/main/webapp/app/bower_components/angular-i18n/angular-locale_de.js',
                            'src/main/webapp/app/bower_components/angular-i18n/angular-locale_en.js',
                            'src/main/webapp/app/bower_components/angular-i18n/angular-locale_ru.js'
                        ],
                        dest: 'src/main/webapp/dist/assets/scripts/i18n'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: [
                            'src/main/webapp/app/updateBrowser/updateBrowserBanner.js'
                        ],
                        dest: 'src/main/webapp/dist/assets/scripts/updateBrowser'
                    },
                    {
                        expand: true,
                        cwd: 'src/main/webapp/app/updateBrowser',
                        src: [
                            '**',
                            '!updateBrowserBanner.js'
                        ],
                        dest: 'src/main/webapp/dist/updateBrowser'
                    },
                    {
                        expand: true,
                        cwd: 'src/main/webapp/app/tjvmDocument',
                        src: [
                            '**'
                        ],
                        dest: 'src/main/webapp/dist/tjvmDocument'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: 'src/main/webapp/app/bower_components/fontawesome/fonts/*',
                        dest: 'src/main/webapp/dist/assets/fonts'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: 'src/main/webapp/app/bower_components/bootstrap/dist/fonts/*',
                        dest: 'src/main/webapp/dist/assets/fonts'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: [
                            'src/main/webapp/app/bower_components/angular-ui-grid/ui-grid.ttf',
                            'src/main/webapp/app/bower_components/angular-ui-grid/ui-grid.woff'
                        ],
                        dest: 'src/main/webapp/dist/assets/styles'
                    },
                    {
                        expand: true,
                        flatten: true,
                        src: [
                            'src/main/webapp/app/bower_components/jquery-ui/themes/overcast/images/*'
                        ],
                        dest: 'src/main/webapp/dist/assets/images'
                    }
                ]
            },
            dist: {

                files: [
                    {
                        expand: true,
                        cwd: 'src/main/webapp/dist',
                        src: [
                            '**'
                        ],
                        dest: 'src/main/webapp/app'
                    }
                ]
            }
        },

        concat: {
            styles: {
                files: {
                    'src/main/webapp/dist/assets/styles/vendors.css': [
                        'src/main/webapp/app/components/ng-table/ng-table.min.css',
                        'src/main/webapp/app/components/nvd3/build/nv.d3.min.css',
                        'src/main/webapp/app/bower_components/bootstrap/dist/css/bootstrap.min.css',
                        'src/main/webapp/app/bower_components/fontawesome/css/font-awesome.min.css',
                        'src/main/webapp/app/bower_components/select2/select2.css',
                        'src/main/webapp/app/bower_components/ngprogress/ngProgress.css',
                        'src/main/webapp/app/bower_components/angular-bootstrap-toggle-switch/style/bootstrap3/angular-toggle-switch-bootstrap-3.css',
                        'src/main/webapp/app/bower_components/ng-joyride/ng-joyride.css',
                        'src/main/webapp/app/bower_components/angular-ui-select/dist/select.min.css',
                        'src/main/webapp/app/bower_components/angular-ui-grid/ui-grid.min.css',
                        'src/main/webapp/app/bower_components/ng-tags-input/ng-tags-input.min.css',
                        'src/main/webapp/app/bower_components/ng-tags-input/ng-tags-input.bootstrap.min.css',
                        'src/main/webapp/app/bower_components/jquery-ui/themes/overcast/jquery-ui.min.css'
                    ],
                    'src/main/webapp/dist/assets/styles/styles.css': [
                        'src/main/webapp/app/**/*.css',
                        '!src/main/webapp/app/vendors/**/*.css',
                        '!src/main/webapp/app/bower_components/**',
                        '!src/main/webapp/app/updateBrowser/updateBrowser.css',
                        '!src/main/webapp/app/tjvmDocument/tjvmDocument.css',
                        '!src/main/webapp/app/components/angular-nvd3/**',
                        '!src/main/webapp/app/components/nvd3/**',
                        '!src/main/webapp/app/components/d3/**'
                    ]
                },
                options: {
                    process: function (src) {
                        return src.replace(/(?:(?:(?:\.\.\/)+assets\/)|(?:(?:\.\.\/)*))images\//g, '../images/');
                    }
                }
            },
            scripts: {
                src: (function (pattern) {
                    var scriptsPaths = grunt.file.expand(pattern);
                    return scriptsPaths.sort(function (a, b) {
                        var am = a.match(/-/g) || [],
                            bm = b.match(/-/g) || [];
                        return am.length - bm.length;
                    });
                })([
                    'src/main/webapp/app/**/*.js',
                    '!src/main/webapp/app/testFramework/init.js',
                    '!src/main/webapp/app/components/vm-custom/**/*.js',
                    '!src/main/webapp/app/components/d3/**',
                    '!src/main/webapp/app/components/nvd3/**',
                    '!src/main/webapp/app/components/angular-nvd3/**',
                    '!src/main/webapp/app/vendors/**/*.js',
                    '!src/main/webapp/app/bower_components/**',
                    '!src/main/webapp/app/updateBrowser/updateBrowserBanner.js',
                    '!src/main/webapp/app/tjvmDocument/tjvmDocument.js'
                ]),
                dest: 'src/main/webapp/dist/assets/scripts/scripts.js'
            },
            vmscripts: {
                src: ['src/main/webapp/app/testFramework/init.js', 'src/main/webapp/app/components/vm-custom/**/*.js'],
                dest: 'src/main/webapp/dist/assets/scripts/vmscripts.js'
            },
            vendors: {
                src: [
                    'src/main/webapp/app/bower_components/jquery/dist/jquery.min.js',
                    'src/main/webapp/app/bower_components/jquery-ui/jquery-ui.min.js',
                    'src/main/webapp/app/bower_components/jquery-placeholder/jquery.placeholder.js',
                    'src/main/webapp/app/bower_components/angular/angular.min.js',
                    'src/main/webapp/app/bower_components/select2/select2.js',
                    'src/main/webapp/app/bower_components/angular-route/angular-route.min.js',
                    'src/main/webapp/app/bower_components/ngprogress/build/ngProgress.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-select2/src/select2.js',
                    'src/main/webapp/app/bower_components/bootstrap/dist/js/bootstrap.min.js',
                    'src/main/webapp/app/bower_components/angular-bootstrap/ui-bootstrap.min.js',
                    'src/main/webapp/app/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-event/dist/event.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-unique/unique.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-highlight/highlight.min.js',
                    'src/main/webapp/app/components/d3/d3.min.js',
                    'src/main/webapp/app/components/nvd3/build/nv.d3.min.js',
                    'src/main/webapp/app/components/angular-nvd3/dist/angular-nvd3.min.js',
                    'src/main/webapp/app/bower_components/angular-google-analytics/dist/angular-google-analytics.min.js',
                    'src/main/webapp/app/bower_components/angular-touch/angular-touch.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-sortable/sortable.min.js',
                    'src/main/webapp/app/bower_components/angularjs-placeholder/src/angularjs-placeholder.js',
                    'src/main/webapp/app/bower_components/angular-bootstrap-toggle-switch/angular-toggle-switch.min.js',
                    'src/main/webapp/app/bower_components/ng-joyride/ng-joyride.js',
                    'src/main/webapp/app/bower_components/momentjs/min/moment-with-locales.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-select/dist/select.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-grid/ui-grid.min.js',
                    'src/main/webapp/app/bower_components/angular-validation/angular-validation.min.js',
                    'src/main/webapp/app/bower_components/angular-validation/angular-validation-rule.min.js',
                    'src/main/webapp/app/bower_components/angular-file-upload/angular-file-upload.min.js',
                    'src/main/webapp/app/bower_components/file-saver/file-saver.js',
                    'src/main/webapp/app/bower_components/xml2json/xml2json.js',
                    'src/main/webapp/app/bower_components/ng-tags-input/ng-tags-input.min.js',
                    'src/main/webapp/app/bower_components/ng-focus-if/focusIf.min.js',
                    'src/main/webapp/app/bower_components/angular-ui-slider/src/slider.js'
                ],
                dest: 'src/main/webapp/dist/assets/scripts/modules.js'
            }
        },

        usemin: {
            html: ['src/main/webapp/dist/index.html']
        },

        ngAnnotate: {
            options: {
                singleQuotes: true
            },
            app: {
                files: {
                    'src/main/webapp/dist/assets/scripts/scripts.js': ['src/main/webapp/dist/assets/scripts/scripts.js'],
                    'src/main/webapp/dist/assets/scripts/vmscripts.js': ['src/main/webapp/dist/assets/scripts/vmscripts.js']
                }
            }
        },

        ngtemplates: {
            app: {
                src: 'src/main/webapp/dist/**/*.html',
                dest: 'src/main/webapp/dist/assets/scripts/templates.js',
                options: {
                    url: function (url) {
                        url = url.slice(url.indexOf('dist'));

                        return url.replace('dist/', '');
                    },
                    module: 'egx',
                    htmlmin: {
                        collapseBooleanAttributes: false, // Otherwise 'sortable' attribute values are deleted
                        collapseWhitespace: true,
                        removeAttributeQuotes: true,
                        removeComments: true, // Only if you don't use comment directives!
                        removeEmptyAttributes: false, // Because some directives look like empty attributes
                        removeRedundantAttributes: true,
                        removeScriptTypeAttributes: true,
                        removeStyleLinkTypeAttributes: true
                    }
                }
            }
        },

        uglify: {
            options: {
                sourceMap: true
            },
            build: {
                files: {
                    'src/main/webapp/dist/assets/scripts/scripts.min.js': ['src/main/webapp/dist/assets/scripts/scripts.js'],
                    'src/main/webapp/dist/assets/scripts/vmscripts.min.js': ['src/main/webapp/dist/assets/scripts/vmscripts.js'],
                    'src/main/webapp/dist/assets/scripts/modules.min.js': ['src/main/webapp/dist/assets/scripts/modules.js'],
                    'src/main/webapp/dist/assets/scripts/templates.min.js': ['src/main/webapp/dist/assets/scripts/templates.js']
                }
            }
        },

        cssmin: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'src/main/webapp/dist/assets/styles/',
                        src: ['*.css', '!*.min.css'],
                        dest: 'src/main/webapp/dist/assets/styles/',
                        ext: '.css'
                    }
                ]
            }
        },

        notify: {
            options: {
                enabled: true,
                title: 'EGX'
            }
        },

        remove: {
            // Removes the webapp/app directory. Careful. Used to replace app with dist
            // in official build.
            app: {
                dirList: ['src/main/webapp/app/']
            },
            dist: {
                dirList: ['src/main/webapp/dist/']
            }
        },

        cachebreaker: {
            scripts: {
                options: {
                    match: ['scripts.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/scripts.min.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            vmscripts: {
                options: {
                    match: ['vmscripts.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/vmscripts.min.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            modules: {
                options: {
                    match: ['modules.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/modules.min.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            updateBrowser: {
                options: {
                    match: ['updateBrowserBanner.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/updateBrowser/updateBrowserBanner.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            locale: {
                options: {
                    match: ['angular-locale_\\${locale}.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/i18n/angular-locale_en.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            templates: {
                options: {
                    match: ['templates.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/scripts/templates.min.js'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            vendors: {
                options: {
                    match: ['vendors.css'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/styles/vendors.css'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            styles: {
                options: {
                    match: ['styles.css'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/styles/styles.css'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            },
            favicon: {
                options: {
                    match: ['favicon.ico'],
                    replacement: 'md5',
                    src: {
                        path: 'src/main/webapp/dist/assets/images/favicon.ico'
                    }
                },
                files: {
                    src: ['src/main/webapp/dist/index.html']
                }
            }
        }
    });

    grunt.registerTask('build', [
        'clean:build',
        'copy:build',
        'concat',
        'ngAnnotate',
        'usemin',
        'ngtemplates',
        'uglify',
        'cssmin',
        'notify',
        'cachebreaker',
        'clobberApp'
    ]);

    grunt.registerTask('clobberApp', [
        'remove:app',
        'copy:dist',
        'remove:dist'
    ]);

};
<commit_msg>Grunt builds<commit_after>'use strict';

module.exports = function(grunt) {

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-usemin');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-notify');
    grunt.loadNpmTasks('grunt-remove');
    grunt.loadNpmTasks('grunt-cache-breaker');
    grunt.loadNpmTasks('grunt-ng-annotate');
    grunt.loadNpmTasks('grunt-angular-templates');

    grunt.initConfig({
        clean: {
            build: ['dist', '.tmp']
        },

        copy: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'frontend',
                        src: [
                            'common/images/**',
                            '**/**/*.html',
                            '**/*.html'
                        ],
                        dest: 'dist/frontend'
                    }
                    //{
                    //    expand: true,
                    //    flatten: true,
                    //    src: 'frontend/bower_components/fontawesome/fonts/*',
                    //    dest: 'dist/assets/fonts'
                    //},
                    //{
                    //    expand: true,
                    //    flatten: true,
                    //    src: [
                    //        'frontend/bower_components/jquery-ui/themes/overcast/images/*'
                    //    ],
                    //    dest: 'dist/assets/images'
                    //}
                ]
            },
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: 'dist/frontend',
                        src: [
                            '**'
                        ],
                        dest: 'frontend'
                    }
                ]
            }
        },

        concat: {
            styles: {
                files: {
                    'dist/styles/vendors.css': [
                        'frontend/bower_components/angular-ui-grid/ui-grid.min.css',
                        'frontend/bower_components/angular-ui-notification/dist/angular-ui-notification.min.css',
                        'frontend/bower_components/bootstrap/dist/css/bootstrap.min.css',
                        'frontend/bower_components/bootstrap-daterangepicker/daterangepicker-bs3.css'
                    ],
                    'dist/styles/styles.css': [
                        'frontend/**/**/*.css',
                        'frontend/**/*.css',
                        '!frontend/bower_components/**'
                    ]
                },
                options: {
                    process: function(src) {
                        return src.replace(/(?:(?:(?:\.\.\/)+common\/)|(?:(?:\.\.\/)*))images\//g, '../images/');
                    }
                }
            },
            scripts: {
                src: (function(pattern) {
                    var scriptsPaths = grunt.file.expand(pattern);
                    return scriptsPaths.sort(function(a, b) {
                        var am = a.match(/-/g) || [],
                            bm = b.match(/-/g) || [];
                        return am.length - bm.length;
                    });
                })([
                    'frontend/**/*.js',
                    '!frontend/bower_components/**'
                ]),
                dest: 'dist/scripts/scripts.js'
            },
            vendors: {
                src: [
                    'frontend/bower_components/jquery/dist/jquery.min.js',
                    'frontend/bower_components/angular/angular.min.js',
                    'frontend/bower_components/angular-route/angular-route.min.js',
                    'frontend/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js',
                    'frontend/bower_components/underscore/underscore-min.js',
                    'frontend/bower_components/moment/min/moment.min.js',
                    'frontend/bower_components/angular-moment/angular-moment.min.js',
                    'frontend/bower_components/angular-cookies/angular-cookies.min.js',
                    'frontend/bower_components/angular-ui-grid/ui-grid.min.js',
                    'frontend/bower_components/angular-click-outside/clickoutside.directive.js',
                    'frontend/bower_components/bootstrap-daterangepicker/daterangepicker.js',
                    'frontend/bower_components/ng-bs-daterangepicker/dist/ng-bs-daterangepicker.min.js',
                    'frontend/bower_components/angular-ui-notification/dist/angular-ui-notification.min.js'
                ],
                dest: 'dist/scripts/vendors.js'
            }
        },

        usemin: {
            html: ['dist/index.html']
        },

        ngAnnotate: {
            options: {
                singleQuotes: true
            },
            app: {
                files: {
                    'dist/scripts/scripts.js': ['dist/scripts/scripts.js']
                }
            }
        },

        //for later usage(caching html templates)
        ngtemplates: {
            app: {
                src: 'dist/**/*.html',
                dest: 'dist/scripts/templates.js',
                options: {
                    url: function(url) {
                        url = url.slice(url.indexOf('dist'));

                        return url.replace('dist/', '');
                    },
                    module: 'mifortTimelog',
                    htmlmin: {
                        collapseBooleanAttributes: false, // Otherwise 'sortable' attribute values are deleted
                        collapseWhitespace: true,
                        removeAttributeQuotes: true,
                        removeComments: true, // Only if you don't use comment directives!
                        removeEmptyAttributes: false, // Because some directives look like empty attributes
                        removeRedundantAttributes: true,
                        removeScriptTypeAttributes: true,
                        removeStyleLinkTypeAttributes: true
                    }
                }
            }
        },

        uglify: {
            options: {
                sourceMap: true
            },
            build: {
                files: {
                    'dist/scripts/scripts.min.js': ['dist/scripts/scripts.js'],
                    'dist/scripts/vendors.min.js': ['dist/scripts/vendors.js']
                }
            }
        },

        cssmin: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'dist/styles/',
                        src: ['*.css', '!*.min.css'],
                        dest: 'dist/styles/',
                        ext: '.css'
                    }
                ]
            }
        },

        notify: {
            options: {
                enabled: true,
                title: 'Mifort'
            }
        },

        remove: {
            // Removes the webapp/app directory. Careful. Used to replace app with dist
            // in official build.
            app: {
                dirList: ['frontend/']
            },
            dist: {
                dirList: ['dist/frontend']
            }
        },

        cachebreaker: {
            scripts: {
                options: {
                    match: ['scripts.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'dist/scripts/scripts.min.js'
                    }
                },
                files: {
                    src: ['dist/index.html']
                }
            },
            vendorsscripts: {
                options: {
                    match: ['vendors.min.js'],
                    replacement: 'md5',
                    src: {
                        path: 'dist/scripts/vendors.min.js'
                    }
                },
                files: {
                    src: ['dist/index.html']
                }
            },
            vendors: {
                options: {
                    match: ['vendors.css'],
                    replacement: 'md5',
                    src: {
                        path: 'dist/styles/vendors.css'
                    }
                },
                files: {
                    src: ['dist/index.html']
                }
            },
            styles: {
                options: {
                    match: ['styles.css'],
                    replacement: 'md5',
                    src: {
                        path: 'dist/styles/styles.css'
                    }
                },
                files: {
                    src: ['dist/index.html']
                }
            }
            //,
            //favicon: {
            //    options: {
            //        match: ['favicon.ico'],
            //        replacement: 'md5',
            //        src: {
            //            path: 'dist/assets/images/favicon.ico'
            //        }
            //    },
            //    files: {
            //        src: ['dist/index.html']
            //    }
            //}
        }
    });

    grunt.registerTask('build', [
        'clean:build',
        'copy:build',
        'concat',
        'ngAnnotate',
        'usemin',
        'ngtemplates',
        'uglify',
        'cssmin',
        'notify',
        'cachebreaker',
        'clobberApp'
    ]);

    grunt.registerTask('clobberApp', [
        'remove:app',
        'copy:dist',
        'remove:dist'
    ]);

};
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { remote } from 'electron';
import classNames from 'classnames';
import { Button } from '@blueprintjs/core';
import { hasReachedLastRound } from '../../../utils/countdown-timer.util';

export default class MediaControls extends PureComponent {
  constructor() {
    super();
    this.onMediaControlKey = e => e.key === ' ' && this.onMediaControlClick();
  }

  componentWillMount() {
    window.addEventListener('keyup', this.onMediaControlKey);
  }

  componentWillUnmount() {
    window.removeEventListener('keyup', this.onMediaControlKey);
  }

  onMediaControlClick() {
    const { isPlaying, pause, resume } = this.props;
    if (isPlaying) pause();
    else resume();
  }

  render() {
    const {
      compact,
      currentPhase,
      currentRound,
      isPlaying,
      totalRounds,
      goToNextPhase,
      openGeneralAlert,
      resetTimer
    } = this.props;

    const buttonStyles = classNames(
      'non-draggable',
      {
        'pt-minimal': compact,
        'pt-large': !compact
      }
    );

    return (

        <Button
          iconName="redo"
          onClick={() => {
            if (compact) {
              const opts = {
                type: 'warning',
                message: 'Are you sure you want to redo the current phase?',
                buttons: ['OK', 'Cancel']
              };
              const onAlertAnswer = response => response === 0 && resetTimer();
              remote.dialog.showMessageBox(opts, onAlertAnswer);
            } else {
              openGeneralAlert(
                'Are you sure you want to redo the current phase?',
                resetTimer,
                { cancelText: 'Cancel' }
              );
            }
          }}
          className={buttonStyles}
        />
        <Button
          active={isPlaying}
          iconName={isPlaying ? 'pause' : 'play'}
          onClick={() => this.onMediaControlClick()}
          className={buttonStyles.concat(' mx-3')}
        />
        <Button
          iconName="chevron-forward"
          disabled={hasReachedLastRound(
            currentPhase,
            currentRound,
            totalRounds
          )}
          onClick={goToNextPhase}
          className={buttonStyles}
        />

    );
  }
}

MediaControls.propTypes = {
  compact: PropTypes.bool,
  currentRound: PropTypes.number.isRequired,
  currentPhase: PropTypes.number.isRequired,
  isPlaying: PropTypes.bool.isRequired,
  totalRounds: PropTypes.number.isRequired,
  goToNextPhase: PropTypes.func.isRequired,
  openGeneralAlert: PropTypes.func.isRequired,
  pause: PropTypes.func.isRequired,
  resetTimer: PropTypes.func.isRequired,
  resume: PropTypes.func.isRequired
};
<commit_msg>enhancement: Remove bg color from all buttons<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { remote } from 'electron';
import classNames from 'classnames';
import { Button } from '@blueprintjs/core';
import { hasReachedLastRound } from '../../../utils/countdown-timer.util';

export default class MediaControls extends PureComponent {
  constructor() {
    super();
    this.onMediaControlKey = e => e.key === ' ' && this.onMediaControlClick();
  }

  componentWillMount() {
    window.addEventListener('keyup', this.onMediaControlKey);
  }

  componentWillUnmount() {
    window.removeEventListener('keyup', this.onMediaControlKey);
  }

  onMediaControlClick() {
    const { isPlaying, pause, resume } = this.props;
    if (isPlaying) pause();
    else resume();
  }

  render() {
    const {
      compact,
      currentPhase,
      currentRound,
      isPlaying,
      totalRounds,
      goToNextPhase,
      openGeneralAlert,
      resetTimer
    } = this.props;

    const buttonStyles = classNames(
      'non-draggable',
      'pt-minimal',
      {
        'pt-large': !compact
      }
    );

    return (

        <Button
          iconName="redo"
          onClick={() => {
            if (compact) {
              const opts = {
                type: 'warning',
                message: 'Are you sure you want to redo the current phase?',
                buttons: ['OK', 'Cancel']
              };
              const onAlertAnswer = response => response === 0 && resetTimer();
              remote.dialog.showMessageBox(opts, onAlertAnswer);
            } else {
              openGeneralAlert(
                'Are you sure you want to redo the current phase?',
                resetTimer,
                { cancelText: 'Cancel' }
              );
            }
          }}
          className={buttonStyles}
        />
        <Button
          active={isPlaying}
          iconName={isPlaying ? 'pause' : 'play'}
          onClick={() => this.onMediaControlClick()}
          className={buttonStyles.concat(' mx-3')}
        />
        <Button
          iconName="chevron-forward"
          disabled={hasReachedLastRound(
            currentPhase,
            currentRound,
            totalRounds
          )}
          onClick={goToNextPhase}
          className={buttonStyles}
        />

    );
  }
}

MediaControls.propTypes = {
  compact: PropTypes.bool,
  currentRound: PropTypes.number.isRequired,
  currentPhase: PropTypes.number.isRequired,
  isPlaying: PropTypes.bool.isRequired,
  totalRounds: PropTypes.number.isRequired,
  goToNextPhase: PropTypes.func.isRequired,
  openGeneralAlert: PropTypes.func.isRequired,
  pause: PropTypes.func.isRequired,
  resetTimer: PropTypes.func.isRequired,
  resume: PropTypes.func.isRequired
};
<|endoftext|>


<commit_before>if (typeof(require) == 'function') {
  var GridList = require('../src/gridList.js');
};

var ensureItemSizes = function(items) {
  /* Set width and height of each item if it doesn't have one */
  var item,
      i;
  for (i = 0; i < items.length; i++ ) {
    item = items[i];
    item.w = item.w !== undefined ? item.w : 1;
    item.h = item.h !== undefined ? item.h : 1;
  };
};

var getMaxHeight = function(items) {
  var height = 1,
      i;
  for (i = 0; i < items.length; i++) {
    if (items[i].y + items[i].h > height) {
      height = items[i].y + items[i].h;
    }
  }
  return height;
};

exports.toEqualPositions = function(expected) {
  /**
    We don't care about the other fields, only the positions and that the
    indexes correspond (e.g. the h changes for items with auto height)
  */
 var _expected,
     _actual,
     actual = this.actual;
 this.message = function () {
    /* To avoid writing fully specified items in each test, we'll add default
     * sizes for the grid to be able to print them, allowing us to at least
     * show to the developer from where the widget starts.*/
    ensureItemSizes(expected);
    ensureItemSizes(actual);
    console.log('\n\n' +
      'Expected: ' + (new GridList(expected, {rows: getMaxHeight(expected)})) +
      'Actual: ' + (new GridList(actual, {rows: getMaxHeight(actual)})));

    // Let Jasmine know which are the items that differ
    return JSON.stringify(_actual) +
           " should be at position " +
           JSON.stringify(_expected);
  };
  for (var i = 0; i < expected.length; i++) {
    if (expected[i].x != this.actual[i].x ||
        expected[i].y != this.actual[i].y) {
      _expected = expected[i];
      _actual = this.actual[i];
      return false;
    }
  }
  return true;
};
<commit_msg>Minimize referenced vars #30<commit_after>if (typeof(require) == 'function') {
  var GridList = require('../src/gridList.js');
};

var ensureItemSizes = function(items) {
  /* Set width and height of each item if it doesn't have one */
  var item,
      i;
  for (i = 0; i < items.length; i++ ) {
    item = items[i];
    item.w = item.w !== undefined ? item.w : 1;
    item.h = item.h !== undefined ? item.h : 1;
  };
};

var getMaxHeight = function(items) {
  var height = 1,
      i;
  for (i = 0; i < items.length; i++) {
    if (items[i].y + items[i].h > height) {
      height = items[i].y + items[i].h;
    }
  }
  return height;
};

exports.toEqualPositions = function(expected) {
  /**
    We don't care about the other fields, only the positions and that the
    indexes correspond (e.g. the h changes for items with auto height)
  */
 var actual = this.actual,
     _failingItem;
 this.message = function () {
    /* To avoid writing fully specified items in each test, we'll add default
     * sizes for the grid to be able to print them, allowing us to at least
     * show to the developer from where the widget starts.*/
    ensureItemSizes(expected);
    ensureItemSizes(actual);
    console.log('\n\n' +
      'Expected: ' + (new GridList(expected, {rows: getMaxHeight(expected)})) +
      'Actual: ' + (new GridList(actual, {rows: getMaxHeight(actual)})));

    // Let Jasmine know which are the items that differ
    return JSON.stringify(actual[_failingItem]) +
           " should be at position " +
           JSON.stringify(expected[_failingItem]);
  };
  for (var i = 0; i < expected.length; i++) {
    if (expected[i].x != this.actual[i].x ||
        expected[i].y != this.actual[i].y) {
      _failingItem = i;
      return false;
    }
  }
  return true;
};
<|endoftext|>


<commit_before>'use strict';
import Axios from 'axios';
import UUID from 'uuid/v4';
import * as RoutePaths from '../routing/RoutePaths';
import {
  loadSeedData,
  addSingleEvent_Success,
  deleteSingleEvent_Success,
  updateSingleEvent_Success,
  deleteBatchEvents_Success,
  fetchStarredEvents_Success,
  fetchRecentlyModifiedEvents_Sucess
} from './index';

// application/json;charset=UTF-8
const dispatchActionCreator = (dispatch, actionCreator) => (resp) => dispatch(actionCreator(resp.data));
const catchAsyncError = (msg) => (err) => { throw new Error(`${msg}:\t${err}`); };
const config = {
  responseType: 'json',
  timeout: 25000,
  maxRedirects: 5,
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json'
  },
  maxContentLength: Number.MAX_SAFE_INTEGER,
  validateStatus: (statusCode) => statusCode >= 200 && statusCode < 300,
  onUploadProgress: (progressEvt) => {
    let uploadProgress = Math.round((progressEvt.loaded * 100) / progressEvt.total);
    console.log(`Upload Completion Progress:\t${uploadProgress}`);
    // document.getElementById('output').innerHTML = percentCompleted;
  },
  onDownloadProgress: (progressEvt) => {
    let downloadProgress = Math.round((progressEvt.loaded * 100) / progressEvt.total);
    console.log(`Downloaded Completion Progress:\t${downloadProgress}`);
  }
};
const generateUuid = {
  transformRequest: [(data) => {
    data.uuid = UUID();
    return data;
  }]
}

const crudAsync = (operation, dispatch, actionCreator, opts = config) => operation
  .then(resp => {
    dispatch(actionCreator(resp.data));
  })
  .catch(err => {
    throw new Error(`Error encountered while making request:\t${err}`);
  });

const crudAsync2 = (operation, endpoint = RoutePaths.Events, dispatch, actionCreator, opts = config, ...curriedArgs) => {
  const request = operation.bind(null, endpoint, ...curriedArgs, config);
  console.log('EVT DATA:', curriedArgs);
  return request()
    .then(resp => {
      console.log('RESPONSE:', resp);
      dispatch(actionCreator(resp.data));
    })
    .catch(err => {
      console.error.call(console, `Error encountered while making request:\t${err}`);
    });
};

// Returns a function to be called within the Redux-Thunk middleware:
export const fetchSeedData = () => {
  return (dispatch) => {
    return Axios
      .get(RoutePaths.Events, {
        responseType: 'json',
        maxContentLength: Number.MAX_SAFE_INTEGER,
        onUploadProgress: (progressEvt) => { console.log('Upload in progress...'); },
        validateStatus: (statusCode) => statusCode >= 200 && statusCode < 300,
        maxRedirects: 3,
        timeout: 30000
      })
      .then(dispatchActionCreator(dispatch, loadSeedData))
      .catch(catchAsyncError('Error encountered while attempting to fetch seed data'));
  };
};

//
export const fetchStarredEvents = () => {
  console.log('Function `fetchStarredEvents()` Called');
  return (dispatch) => {
    return Axios
      .get(RoutePaths.StarredEvents, {
        responseType: 'json',
      })
      .then(dispatchActionCreator(dispatch, fetchStarredEvents_Success))
      .catch(catchAsyncError('Error encountered while attempting to fetch starred events'));
  };
};

//
export const fetchRecentlyModifiedEvents = () => {
  // headers: { 'X-Limit-Size': 3 }
  return (dispatch) => {
    return Axios
      .get(RoutePaths.RecentlyModifiedEvents, {
        responseType: 'json'
      })
      .then(response => {
        // dispatchActionCreator(dispatch, fetchRecentlyModifiedEvents_Sucess))
        dispatch(fetchRecentlyModifiedEvents_Sucess(response.data));
      })
      .catch(catchAsyncError('Error encountered while attempting to fetch recently modified events'));
  };
};

//
// export const addSingleEvent = (evtData) => {
//   let req = Axios.post('/api/events', evtData);
//   return (dispatch) => crudAsync(req, dispatch, addSingleEvent_Success);
// };
export const addSingleEvent = (evtData) => {
  return (dispatch) => crudAsync2(Axios.post, RoutePaths.Events, dispatch, addSingleEvent_Success, Object.assign({}, config, generateUuid), evtData);
};

//
// export const updateSingleEvent = (evtData) => {
//   let req = Axios.put(RoutePaths.getEditEvent(evtData.uuid), evtData);
//   return (dispatch) => crudAsync(req, dispatch, updateSingleEvent_Success);
// };
export const updateSingleEvent = (evtData) => {
  return (dispatch) => crudAsync2(Axios.put, RoutePaths.getEditEvent(evtData.uuid), dispatch, updateSingleEvent_Success, config, evtData);
};

//
export const deleteSingleEvt = (evt) => {
  return (dispatch) => {
    return Axios
      .delete(RoutePaths.getEditEvent(evt.uuid), {
        data: evt,
        headers: {
          'Content-Type': 'application/json'
        },
      })
      .then(dispatchActionCreator(dispatch, deleteSingleEvent_Success))
      .catch(catchAsyncError('Error encountered while attempting to execute DELETE request'));
  };
};

//
export const deleteBatchEvents = (evts) => {
  return (dispatch) => {
    return Axios
      .delete(RoutePaths.Events, {
        data: evts,
        headers: {
          'Content-Type': 'application/json'
        }
      })
      .then(dispatchActionCreator(dispatch, deleteBatchEvents_Success))
      .catch(catchAsyncError('Error encountered while attempting to execute multiple DELETE requests'));
  };
};
<commit_msg>refactor (Redux): Overhauled async action creator creators with abstracted wrapper<commit_after>'use strict';
import Axios from 'axios';
import * as RoutePaths from '../routing/RoutePaths';
import { dispatchActionCreator, catchAsyncError, config, generateUuid } from './asyncConfig';
import {
  loadSeedData,
  addSingleEvent_Success,
  deleteSingleEvent_Success,
  updateSingleEvent_Success,
  deleteBatchEvents_Success,
  fetchStarredEvents_Success,
  fetchRecentlyModifiedEvents_Sucess
} from './index';

const crudOperation = new Map([
  ['GET', Axios.get],
  ['POST', Axios.post],
  ['PUT', Axios.put],
  ['DELETE', Axios.delete],
  ['ALL', Axios.all],
  ['SPREAD', Axios.spread]
]);

const crudAsync2 = (operation, endpoint = RoutePaths.Events, dispatch, actionCreator, curriedArgs, ...configOpts) => {
  const reqData = { data: curriedArgs };
  const request = operation.bind(null, endpoint, reqData, Object.assign({}, config, reqData, ...configOpts));
  return request()
    .then(resp => {
      dispatch(actionCreator(resp.data));
    })
    .catch(err => {
      console.error.call(console, `\nError encountered while making request to the '${endpoint}' endpoint:\n>\t${err}`);
    });
};

// Returns a function to be called within the Redux-Thunk middleware:
export const fetchSeedData = () => {
  return (dispatch) => {
    return Axios
      .get(RoutePaths.Events, {
        responseType: 'json',
        maxContentLength: Number.MAX_SAFE_INTEGER,
        onUploadProgress: (progressEvt) => { console.log('Upload in progress...'); },
        validateStatus: (statusCode) => statusCode >= 200 && statusCode < 300,
        maxRedirects: 3,
        timeout: 30000
      })
      .then(dispatchActionCreator(dispatch, loadSeedData))
      .catch(catchAsyncError('Error encountered while attempting to fetch seed data'));
  };
};

const { Events, getEditEvent, StarredEvents, RecentlyModifiedEvents } = RoutePaths;

//
export const fetchStarredEvents = () => (dispatch) =>
  crudAsync2(Axios.get, StarredEvents, dispatch, fetchStarredEvents_Success);

//
export const fetchRecentlyModifiedEvents = () => (dispatch) =>
  crudAsync2(Axios.get, RecentlyModifiedEvents, dispatch, fetchRecentlyModifiedEvents_Sucess);
  // headers: { 'X-Limit-Size': 3 }

//
export const addSingleEvent = (evtData) => (dispatch) =>
  crudAsync2(Axios.post, Events, dispatch, addSingleEvent_Success, evtData);

//
export const updateSingleEvent = (evtData) => (dispatch) =>
  crudAsync2(Axios.put, getEditEvent(evtData.uuid), dispatch, updateSingleEvent_Success, evtData);

//
export const deleteSingleEvt = (evt) => (dispatch) =>
  crudAsync2(Axios.delete, getEditEvent(evt.uuid), dispatch, deleteSingleEvent_Success, evt);

//
export const deleteBatchEvents = (evts) => (dispatch) =>
  crudAsync2(Axios.delete, Events, dispatch, deleteBatchEvents_Success, evts);
<|endoftext|>


<commit_before>import {error} from '../util/msgs.js';
import * as actionTypes from '../constants/actionTypes';
import { ANAX_URL_BASE } from '../constants/configuration';
import * as pays from './servicesRequests';
import * as _ from 'lodash';

export function servicesFormFieldChange(segment, fieldName, value) {
  return dispatch => dispatch({
    type: actionTypes.SERVICES_FORM_UPDATE,
    segment: segment,
    fieldName: fieldName,
    value: value
  });
}

export function servicesFormMultiFieldChange(segment, updateObj) {
  return function(dispatch) {
    return dispatch({
      type: actionTypes.SERVICES_FORM_MULTI_UPDATE,
      updateObj: updateObj
    });
  };
}

// useGps is in here only for compat
export function servicesFormSubmit(attributes, servicesForm) {

	const loc = _.filter(attributes, (attr) => { return (attr.id === 'location' && attr.sensor_urls.length === 0); });
	if (loc.length !== 1) {
		throw error({}, 'Unexpected attributes state; looking for single location');
	}

	let doFetch = (body) => {
    return fetch(`${ANAX_URL_BASE}/service`,
			{
        method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(body)
			});
	}

	const promises = _.filter(_.map(servicesForm.fields, (wl, name) => {
		if (wl.enabled) {
			switch (name) {
				case 'citygram':
					return doFetch(pays.citygramService(wl.description, wl.email, wl.name, wl.password, 256));
					break;
				case 'cputemp':
					return doFetch(pays.cputempService(128));
					break;
				case 'netspeed':
					return doFetch(pays.netspeedService(wl.testalg, 128));
					break;
				case 'purpleair':
					return doFetch(pays.purpleairService(wl.devicehostname, 128));
					break;
        case 'pws':
          const modelType = wl.modelType.split(',');
					return doFetch(pays.pwsService(wl.wugname, modelType[0], modelType[1], 128));
					break;
				case 'sdr':
					return doFetch(pays.sdrService(128));
					break;
        case 'aural':
          return doFetch(pays.auralService(wl.sendAudio, 128));
				default:
					throw error({}, 'Unknown workload name', name);
			}
		}
	}), (pr) => { return !!pr; });

  // compat; only here so that it gets created at the same time as other services
  promises.push(doFetch(pays.locationService(loc[0].mappings.use_gps, 128)));

  // TODO: this will only work first-time; needs to be smarter about conflicts and such to be re-executable
  return function(dispatch) {
    return Promise.all(promises)
		.then((responses) => {

			_.each(responses, (resp, key) => {
				if (resp.ok) {
					console.log('Successful registration of service', resp);
				} else {
					throw error(resp, 'Service registration failed');
				}
			});
		});
  };
}
<commit_msg>pass in metered param to service registrar<commit_after>import {error} from '../util/msgs.js';
import * as actionTypes from '../constants/actionTypes';
import { ANAX_URL_BASE } from '../constants/configuration';
import * as pays from './servicesRequests';
import * as _ from 'lodash';

export function servicesFormFieldChange(segment, fieldName, value) {
  return dispatch => dispatch({
    type: actionTypes.SERVICES_FORM_UPDATE,
    segment: segment,
    fieldName: fieldName,
    value: value
  });
}

export function servicesFormMultiFieldChange(segment, updateObj) {
  return function(dispatch) {
    return dispatch({
      type: actionTypes.SERVICES_FORM_MULTI_UPDATE,
      updateObj: updateObj
    });
  };
}

// useGps is in here only for compat
export function servicesFormSubmit(attributes, servicesForm) {

	const loc = _.filter(attributes, (attr) => { return (attr.id === 'location' && attr.sensor_urls.length === 0); });
	if (loc.length !== 1) {
		throw error({}, 'Unexpected attributes state; looking for single location');
	}

	let doFetch = (body) => {
    return fetch(`${ANAX_URL_BASE}/service`,
			{
        method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(body)
			});
	}

	const promises = _.filter(_.map(servicesForm.fields, (wl, name) => {
		if (wl.enabled) {
			switch (name) {
				case 'citygram':
					return doFetch(pays.citygramService(wl.description, wl.email, wl.name, wl.password, wl.metered, 256));
					break;
				case 'cputemp':
					return doFetch(pays.cputempService(wl.metered, 128));
					break;
				case 'netspeed':
					return doFetch(pays.netspeedService(wl.testalg, wl.metered, 128));
					break;
				case 'purpleair':
					return doFetch(pays.purpleairService(wl.devicehostname, wl.metered, 128));
					break;
        case 'pws':
          const modelType = wl.modelType.split(',');
					return doFetch(pays.pwsService(wl.wugname, modelType[0], modelType[1], wl.metered, 128));
					break;
				case 'sdr':
					return doFetch(pays.sdrService(wl.metered, 128));
					break;
        case 'aural':
          return doFetch(pays.auralService(wl.sendAudio, wl.metered, 128));
				default:
					throw error({}, 'Unknown workload name', name);
			}
		}
	}), (pr) => { return !!pr; });

  // compat; only here so that it gets created at the same time as other services
  promises.push(doFetch(pays.locationService(loc[0].mappings.use_gps, wl.metered, 128)));

  // TODO: this will only work first-time; needs to be smarter about conflicts and such to be re-executable
  return function(dispatch) {
    return Promise.all(promises)
		.then((responses) => {

			_.each(responses, (resp, key) => {
				if (resp.ok) {
					console.log('Successful registration of service', resp);
				} else {
					throw error(resp, 'Service registration failed');
				}
			});
		});
  };
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var thriftrw = require('thriftrw');
var TField = thriftrw.TField;
var TYPE = thriftrw.TYPE;
var util = require('util');

function AField(opts) {
    var self = this;
    if (!(self instanceof AField)) {
        return new AField(opts);
    }
    opts = opts || {};
    this.id = opts.id;
    this.name = opts.name;
    this.type = opts.type;
    this.required = opts.required || false;
    // TODO: handle defaultValue
    this.defaultValue = opts.defaultValue || null;
}

function AStruct(opts) {
    var self = this;
    if (!(this instanceof AStruct)) {
        return new AStruct(opts);
    }
    self.typeid = TYPE.STRUCT;

    if (opts.fields === undefined) {
        throw new Error('AStruct requires fields');
    }
    self.name = opts.name || null;
    self.fields = opts.fields;
    self.fieldsById = {};
    self.fieldsByName = {};
    self.fieldNames = [];
    for (var index = 0; index < self.fields.length; index++) {
        var field = self.fields[index];
        self.fieldsById[field.id] = field;
        self.fieldsByName[field.name] = field;
        self.fieldNames[index] = field.name;
    }
}

AStruct.prototype.reify = function reify(tstruct) {
    var self = this;
    var result = {};
    for (var index = 0; index < tstruct.fields.length; index++) {
        var tfield = tstruct.fields[index];
        var afield = self.fieldsById[tfield.id];
        if (!afield) {
            continue;
        }
        if (afield.type.typeid !== tfield.typeid) {
            throw new Error(util.format(
                'AStruct::reify expects field %d typeid %d; received %d',
                tfield.id, afield.type.typeid, tfield.typeid));
        }
        result[afield.name] = afield.type.reify(tfield.val);
    }
    return result;
};

AStruct.prototype.uglify = function uglify(struct) {
    var self = this;
    var tstruct = new thriftrw.TStruct();
    for (var index = 0; index < self.fields.length; index++) {
        var field = self.fields[index];
        var value = struct[field.name];
        if (value == null) {
            if (field.required) {
                throw new Error(util.format('typename %s; missing required field %s',
                    self.name, field.name));
            }
        } else {
            var tvalue = field.type.uglify(value);
            var tfield = new TField(field.type.typeid, field.id, tvalue);
            tstruct.fields.push(tfield);
        }
    }
    return tstruct;
};

module.exports.AField = AField;
module.exports.AStruct = AStruct;
<commit_msg>Reintroduce try/catch for syntax error location<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var thriftrw = require('thriftrw');
var TField = thriftrw.TField;
var TYPE = thriftrw.TYPE;
var util = require('util');

function AField(opts) {
    var self = this;
    if (!(self instanceof AField)) {
        return new AField(opts);
    }
    opts = opts || {};
    this.id = opts.id;
    this.name = opts.name;
    this.type = opts.type;
    this.required = opts.required || false;
    // TODO: handle defaultValue
    this.defaultValue = opts.defaultValue || null;
}

function AStruct(opts) {
    var self = this;
    if (!(this instanceof AStruct)) {
        return new AStruct(opts);
    }
    self.typeid = TYPE.STRUCT;

    if (opts.fields === undefined) {
        throw new Error('AStruct requires fields');
    }
    self.name = opts.name || null;
    self.fields = opts.fields;
    self.fieldsById = {};
    self.fieldsByName = {};
    self.fieldNames = [];
    for (var index = 0; index < self.fields.length; index++) {
        var field = self.fields[index];
        self.fieldsById[field.id] = field;
        self.fieldsByName[field.name] = field;
        self.fieldNames[index] = field.name;
    }
}

AStruct.prototype.reify = function reify(tstruct) {
    var self = this;
    var result = {};
    for (var index = 0; index < tstruct.fields.length; index++) {
        var tfield = tstruct.fields[index];
        var afield = self.fieldsById[tfield.id];
        if (!afield) {
            continue;
        }
        if (afield.type.typeid !== tfield.typeid) {
            throw new Error(util.format(
                'AStruct::reify expects field %d typeid %d; received %d',
                tfield.id, afield.type.typeid, tfield.typeid));
        }
        result[afield.name] = afield.type.reify(tfield.val);
    }
    return result;
};

AStruct.prototype.uglify = function uglify(struct) {
    var self = this;
    var tstruct = new thriftrw.TStruct();
    for (var index = 0; index < self.fields.length; index++) {
        var field = self.fields[index];
        var value = struct[field.name];
        if (value == null) {
            if (field.required) {
                throw new Error(util.format('typename %s; missing required field %s',
                    self.name, field.name));
            }
        } else {
            var tvalue = field.type.uglify(value);
            var tfield;
            try {
                tfield = new TField(field.type.typeid, field.id, tvalue);
            } catch (e) {
                throw new Error(util.format('typename %s; failed to uglify field name %s id %d typeid %d val %s; inner error %s',
                    self.name, name, afield.id, afield.type.typeid, util.inspect(val), e.message));
            }
            tstruct.fields.push(tfield);
        }
    }
    return tstruct;
};

module.exports.AField = AField;
module.exports.AStruct = AStruct;
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  var config = {
    watch: {
    }
  };
  config.pkg = grunt.file.readJSON('package.json');
  grunt.initConfig(config);
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
};<commit_msg>fix: config definition<commit_after>module.exports = function(grunt) {
  var projectConfig = {
    watch: {
    }
  };
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    watch: projectConfig.watch
  });
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
};<|endoftext|>


<commit_before>'use strict'

// var request = require('request');
var Q = require('q');
var companySearch = require('../services/company-api-gh');
var postSearch = require('../services/post-api-gh');
var utilities = require('../brain/utilities');

function processRequest(genericRequest) {
  var queryResult = queryCompany(genericRequest);
  var genericResponse = structureGenericResponse(queryResult);
  return genericResponse;
}

/**
 * Processes generic request into Company object, with attached data
 *
 * @param genericRequest
 * @return {queryResult}
 */
function queryCompany(genericRequest) {
  var queryResult = {
    userInput: genericRequest.userInput,
    // Company object, with Posts and Other Companies attached
    data: {},
    // types: 'standard', 'no-input', 'not-found'
    type: '',
    context: genericRequest.context
  };
  var userInput = genericRequest.userInput;
  var company = {};

  // todo: do pre-response here (is this where it belongs?)
  utilities.preResponse(genericRequest.context);

  if (!userInput) {
    queryResult.type = 'no-input';
    return Q.when(queryResult);
  }

  return Q.when(companySearch.findByText(userInput))
  .then(function(companySearchResults) {
    // ----------------
    // Pick out Company of interest from search results
    // ( can we separate out this as function?)
    var exactMatch = companySearchResults.filter(function(eachCompany) {
      return eachCompany.name.toLowerCase() === userInput.toLowerCase();
    });

    if (!companySearchResults.length) {
      console.log('Nothing found in initial Company search');
      queryResult.type = 'nothing-found';
      // returning an empty object as Posts for the next step in chain
      return Q.when({});
    }
    else if (exactMatch && exactMatch.length) {
      company = exactMatch[0];
      console.log('Found an exact match from Companies search');
    }
    else {
      company = companySearchResults[0];
      console.log("Going with first result from Companies search");
    };
    // ----------------

    console.log('About to attach other companies list');
    company = attachOtherCompanies(company, companySearchResults, userInput);

    console.log('Other companies attached, about to query Posts of Company');
    return postSearch.findByCompany(company)
  })
  .then(function(posts) {
    console.log('Posts of Company returned in action handler');
    queryResult.type = 'standard';
    company.posts = posts;
    queryResult.data = company;
    // console.log('Result of API queries: ' + JSON.stringify(queryResult));
    return queryResult;
  });
}

function structureGenericResponse(queryResult) {
  var genericResponse = {
    userInput: queryResult.userInput,
    data: {
      name: queryResult.data.name || '' ,
      contactMethods: {
        phone: '',
        email: '',
        twitter: '',
        web: '',
        chat: '',
        facebook: ''
      },
      posts: [],
      otherCompanies: queryResult.data.otherCompanies
    },
    type: queryResult.type || '',
    context: queryResult.context || ''
  }
// Extract contact methods:
  genericResponse.data.contactMethods = utilities.extractContactMethods(queryResult.data);
// Extract Posts info
  var posts = queryResult.data.posts;
  if (posts && posts.length) {
    genericResponse.data.posts = posts.map((post) => {
      return {
        title: post.title || '',
        urlId: post.urlId || '',
      };
    })
  };
  return genericResponse;
}

// Should this exist in another module?
function attachOtherCompanies(company, companySearchResults, userInput) {
    var companyNames = companySearchResults.map((eachCompany) => {
      return eachCompany.name;
    });
    console.log("List of company names: " + JSON.stringify(companyNames));
    company.otherCompanies = companyNames.filter((name) => {
      return name.toLowerCase() !== userInput.toLowerCase();
    });
    return company;
};

// takes Company object, puts associated info into an result object
// should this exist in another module?
function extractContactMethods(queryResultData) {
  var contactInfo = {
    phone: '',
    email: '',
    twitter: '',
    web: '',
    chat: '',
    facebook: ''
  };
  var company = queryResultData;
  contactInfo.phone = company.callback.phone || '';

  let emailContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "email";
    });
  contactInfo.email = (emailContactMethods && emailContactMethods.length) ? emailContactMethods[0].target : '';

  let twitterContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "twitter";
    });
  contactInfo.twitter = (twitterContactMethods && twitterContactMethods.length) ? twitterContactMethods[0].target : '';

  let webContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "web";
    });
  contactInfo.web = (webContactMethods && webContactMethods.length) ? webContactMethods[0].target : '';

  let chatContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "chat";
    });
  contactInfo.chat = (chatContactMethods && chatContactMethods.length) ? chatContactMethods[0].target : '';

  let facebookContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "facebook";
    });
  contactInfo.facebook = (facebookContactMethods && facebookContactMethods.length) ? facebookContactMethods[0].target : '';

  console.log("Extracted contact info from company: " + JSON.stringify(contactInfo));
  return contactInfo;
}

module.exports = {
  processRequest: processRequest
};
<commit_msg>debug<commit_after>'use strict'

// var request = require('request');
var Q = require('q');
var companySearch = require('../services/company-api-gh');
var postSearch = require('../services/post-api-gh');
var utilities = require('../brain/utilities');

function processRequest(genericRequest) {
  return Q.when(queryCompany(genericRequest))
    .then((queryResult) => {
      return structureGenericResponse(queryResult)
    });
}

/**
 * Processes generic request into Company object, with attached data
 *
 * @param genericRequest
 * @return {queryResult}
 */
function queryCompany(genericRequest) {
  var queryResult = {
    userInput: genericRequest.userInput,
    // Company object, with Posts and Other Companies attached
    data: {},
    // types: 'standard', 'no-input', 'not-found'
    type: '',
    context: genericRequest.context
  };
  var userInput = genericRequest.userInput;
  var company = {};

  // todo: do pre-response here (is this where it belongs?)
  utilities.preResponse(genericRequest.context);

  if (!userInput) {
    queryResult.type = 'no-input';
    return Q.when(queryResult);
  }

  return Q.when(companySearch.findByText(userInput))
  .then(function(companySearchResults) {
    // ----------------
    // Pick out Company of interest from search results
    // ( can we separate out this as function?)
    var exactMatch = companySearchResults.filter(function(eachCompany) {
      return eachCompany.name.toLowerCase() === userInput.toLowerCase();
    });

    if (!companySearchResults.length) {
      console.log('Nothing found in initial Company search');
      queryResult.type = 'nothing-found';
      // returning an empty object as Posts for the next step in chain
      return Q.when({});
    }
    else if (exactMatch && exactMatch.length) {
      company = exactMatch[0];
      console.log('Found an exact match from Companies search');
    }
    else {
      company = companySearchResults[0];
      console.log("Going with first result from Companies search");
    };
    // ----------------

    console.log('About to attach other companies list');
    company = attachOtherCompanies(company, companySearchResults, userInput);

    console.log('Other companies attached, about to query Posts of Company');
    return postSearch.findByCompany(company)
  })
  .then(function(posts) {
    console.log('Posts of Company returned in action handler');
    queryResult.type = 'standard';
    company.posts = posts;
    queryResult.data = company;
    // console.log('Result of API queries: ' + JSON.stringify(queryResult));
    return queryResult;
  });
}

function structureGenericResponse(queryResult) {
  var genericResponse = {
    userInput: queryResult.userInput,
    data: {
      name: queryResult.data.name || '' ,
      contactMethods: {
        phone: '',
        email: '',
        twitter: '',
        web: '',
        chat: '',
        facebook: ''
      },
      posts: [],
      otherCompanies: queryResult.data.otherCompanies
    },
    type: queryResult.type || '',
    context: queryResult.context || ''
  }
// Extract contact methods:
  genericResponse.data.contactMethods = utilities.extractContactMethods(queryResult.data);
// Extract Posts info
  var posts = queryResult.data.posts;
  if (posts && posts.length) {
    genericResponse.data.posts = posts.map((post) => {
      return {
        title: post.title || '',
        urlId: post.urlId || '',
      };
    })
  };
  return genericResponse;
}

// Should this exist in another module?
function attachOtherCompanies(company, companySearchResults, userInput) {
    var companyNames = companySearchResults.map((eachCompany) => {
      return eachCompany.name;
    });
    console.log("List of company names: " + JSON.stringify(companyNames));
    company.otherCompanies = companyNames.filter((name) => {
      return name.toLowerCase() !== userInput.toLowerCase();
    });
    return company;
};

// takes Company object, puts associated info into an result object
// should this exist in another module?
function extractContactMethods(queryResultData) {
  var contactInfo = {
    phone: '',
    email: '',
    twitter: '',
    web: '',
    chat: '',
    facebook: ''
  };
  var company = queryResultData;
  contactInfo.phone = company.callback.phone || '';

  let emailContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "email";
    });
  contactInfo.email = (emailContactMethods && emailContactMethods.length) ? emailContactMethods[0].target : '';

  let twitterContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "twitter";
    });
  contactInfo.twitter = (twitterContactMethods && twitterContactMethods.length) ? twitterContactMethods[0].target : '';

  let webContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "web";
    });
  contactInfo.web = (webContactMethods && webContactMethods.length) ? webContactMethods[0].target : '';

  let chatContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "chat";
    });
  contactInfo.chat = (chatContactMethods && chatContactMethods.length) ? chatContactMethods[0].target : '';

  let facebookContactMethods = company.contactMethods.filter(function (method) {
        return method.type === "facebook";
    });
  contactInfo.facebook = (facebookContactMethods && facebookContactMethods.length) ? facebookContactMethods[0].target : '';

  console.log("Extracted contact info from company: " + JSON.stringify(contactInfo));
  return contactInfo;
}

module.exports = {
  processRequest: processRequest
};
<|endoftext|>


<commit_before>/* global module:false */
module.exports = function(grunt) {

	// Project configuration
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		meta: {
			banner:
				'/*!\n' +
				' * reveal.js <%= pkg.version %> (<%= grunt.template.today("yyyy-mm-dd, HH:MM") %>)\n' +
				' * http://lab.hakim.se/reveal-js\n' +
				' * MIT licensed\n' +
				' *\n' +
				' * Copyright (C) 2013 Hakim El Hattab, http://hakim.se\n' +
				' */'
		},

		// Tests will be added soon
		qunit: {
			files: [ 'test/**/*.html' ]
		},

		uglify: {
			options: {
				banner: '<%= meta.banner %>\n'
			},
			build: {
				src: 'js/reveal.js',
				dest: 'js/reveal.min.js'
			}
		},

		cssmin: {
			compress: {
				files: {
					'css/reveal.min.css': [ 'css/reveal.css' ]
				}
			}
		},

		sass: {
			main: {
				files: {
					'css/theme/default.css': 'css/theme/source/default.scss',
					'css/theme/beige.css': 'css/theme/source/beige.scss',
					'css/theme/night.css': 'css/theme/source/night.scss',
					'css/theme/serif.css': 'css/theme/source/serif.scss',
					'css/theme/simple.css': 'css/theme/source/simple.scss',
					'css/theme/sky.css': 'css/theme/source/sky.scss',
					'css/theme/moon.css': 'css/theme/source/moon.scss',
					'css/theme/solarized.css': 'css/theme/source/solarized.scss'
				}
			}
		},

		jshint: {
			options: {
				curly: false,
				eqeqeq: true,
				immed: true,
				latedef: true,
				newcap: true,
				noarg: true,
				sub: true,
				undef: true,
				eqnull: true,
				browser: true,
				expr: true,
				globals: {
					head: false,
					module: false,
					console: false
				}
			},
			files: [ 'Gruntfile.js', 'js/reveal.js' ]
		},

		watch: {
			main: {
				files: [ 'Gruntfile.js', 'js/reveal.js', 'css/reveal.css' ],
				tasks: 'default'
			},
			theme: {
				files: [ 'css/theme/source/*.scss', 'css/theme/template/*.scss' ],
				tasks: 'themes'
			}
		}

	});

	// Dependencies
	grunt.loadNpmTasks( 'grunt-contrib-jshint' );
	grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
	grunt.loadNpmTasks( 'grunt-contrib-uglify' );
	grunt.loadNpmTasks( 'grunt-contrib-watch' );
	grunt.loadNpmTasks( 'grunt-contrib-sass' );

	// Default task
	grunt.registerTask( 'default', [ 'jshint', 'cssmin', 'uglify' ] );

	// Theme task
	grunt.registerTask( 'themes', [ 'sass' ] );

};
<commit_msg>Closure. Removed a bunch of cruft<commit_after>(function () {
  'use strict';
  var deepmerge = require('deepmerge');
  var matchdep = require('matchdep');

  module.exports = function (grunt) {

    grunt.initConfig({
      // Development Server
      connect: {
        server: {
          options: {
            port: 8808,
            base: '.'
          }
        }
      },

      // Watch Task
      watch: {
        options: {
          livereload: 8088
        },
        html: {
          files: '**/*.html'
        },
        // sass: {
        //   files: 'sass/**/*.scss',
        //   tasks: ['compass:dev'],
        //   options: {
        //     livereload: false
        //   }
        // },
        css: {
          files: 'css/**/*.css'
        },
        js: {
          files: 'js/**/*.js'
        },
        files: {
          files: [
            'images/**/*',
            'videos/**/*'
          ]
        }
      },

      // Compass
      // compass: {
      //   options: {
      //     sassDir: 'sass',

      //   }
      // }
    });

    //////////////////////////////
    // Grunt Task Loads
    //////////////////////////////
    matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    //////////////////////////////
    // Server Task
    //////////////////////////////
    grunt.registerTask('server', 'Runs a server to dev from', function() {
      grunt.task.run(['connect', 'watch']);
    });
  }
})();<|endoftext|>