<commit_before>var key = require('key');
var arrow = key.code.arrow;
var util = require('../util');
var rangeUtil = require('../range-util');
var ctrlOrCmd = require('../ctrl-or-cmd');

module.exports = function(_grid) {
    var grid = _grid;

    var model = {
        focus: {
            row: 0,
            col: 0
        }
    };

    model.otherSelections = [];

    var focusClass = grid.cellClasses.create(0, 0, 'focus');
    grid.cellClasses.add(focusClass);

    model.focusDecorator = grid.decorators.create(0, 0, 1, 1);
    var focusDefaultRender = model.focusDecorator.render;
    model.focusDecorator.render = function() {
        var div = focusDefaultRender();
        div.setAttribute('class', 'grid-focus-decorator');
        return div;
    };
    grid.decorators.add(model.focusDecorator);

    model.setFocus = function setFocus(row, col, dontClearSelection) {
        row = grid.data.row.clamp(row);
        col = grid.data.col.clamp(col);
        var changed = row !== model.focus.row || col !== model.focus.col;
        model.focus.row = row;
        model.focus.col = col;
        focusClass.top = row;
        focusClass.left = col;
        model.focusDecorator.top = row;
        model.focusDecorator.left = col;
        grid.cellScrollModel.scrollIntoView(row, col);
        if (!dontClearSelection) {
            clearOtherSelections();
        }
        setSelectionToFocus();
        if (changed) {
            grid.eventLoop.fire('grid-focus-change');
        }
    };

    function seekNextEdge(newIndex, startedDefined, isForwardEdge, isBackwardEdge, goForward) {

        var isEdgeToSeek;
        if (isForwardEdge(newIndex) || !startedDefined) {
            isEdgeToSeek = isBackwardEdge;
        } else {
            isEdgeToSeek = isForwardEdge;
        }

        while (goForward(newIndex) !== undefined && !isEdgeToSeek(newIndex = goForward(newIndex))) /*eslint-disable no-empty*/ {
            // empty
        } /*eslint-enable no-empty*/

        return newIndex;
    }

    function navFrom(row, col, e) {
        // if nothing changes great we'll stay where we are
        var newRow = row;
        var newCol = col;
        var isSeek = ctrlOrCmd(e);
        var isLeftwardEdge, isRightwardEdge, isUpwardEdge, isDownwardEdge, cellHasValue, startedDefined;
        if (isSeek) {
            cellHasValue = function(r, c) {
                if (r === undefined || c === undefined) {
                    return false;
                }

                return !!grid.dataModel.get(r, c).formatted;
            };
            isLeftwardEdge = function(c) {
                return cellHasValue(newRow, c) && !cellHasValue(newRow, grid.data.left(c));
            };
            isRightwardEdge = function(c) {
                return cellHasValue(newRow, c) && !cellHasValue(newRow, grid.data.right(c));
            };
            isUpwardEdge = function(r) {
                return cellHasValue(r, newCol) && !cellHasValue(grid.data.up(r), newCol);
            };
            isDownwardEdge = function(r) {
                return cellHasValue(r, newCol) && !cellHasValue(grid.data.down(r), newCol);
            };
            startedDefined = cellHasValue(newRow, newCol);
        }
        switch (e.which) {
            case arrow.down.code:
                if (isSeek) {
                    newRow = seekNextEdge(newRow, startedDefined, isDownwardEdge, isUpwardEdge, grid.data.down);
                } else {
                    newRow = grid.data.down(newRow);
                }
                break;
            case arrow.up.code:
                if (isSeek) {
                    newRow = seekNextEdge(newRow, startedDefined, isUpwardEdge, isDownwardEdge, grid.data.up);
                } else {
                    newRow = grid.data.up(newRow);
                }
                break;
            case arrow.right.code:
                if (isSeek) {
                    newCol = seekNextEdge(newCol, startedDefined, isRightwardEdge, isLeftwardEdge, grid.data.right);
                } else {
                    newCol = grid.data.right(newCol);
                }
                break;
            case arrow.left.code:
                if (isSeek) {
                    newCol = seekNextEdge(newCol, startedDefined, isLeftwardEdge, isRightwardEdge, grid.data.left);
                } else {
                    newCol = grid.data.left(newCol);
                }
                break;
        }
        if (newRow === undefined) {
            newRow = row;
        }
        if (newCol === undefined) {
            newCol = col;
        }
        return {
            row: newRow,
            col: newCol
        };
    }

    model._navFrom = navFrom;

    grid.eventLoop.bind('keydown', function(e) {
        if (!key.is(arrow, e.which) || !grid.focused) {
            return;
        }
        // focus logic

        if (!e.shiftKey) {
            var newFocus = navFrom(model.focus.row, model.focus.col, e);
            model.setFocus(newFocus.row, newFocus.col, e);
        } else {
            // selection logic
            var newSelection;
            // stand in for if it's cleared
            if (model.selection.top === -1) {
                newSelection = {
                    top: model.focus.row,
                    left: model.focus.col,
                    height: 1,
                    width: 1
                };
            } else {
                newSelection = {
                    top: model.selection.top,
                    left: model.selection.left,
                    height: model.selection.height,
                    width: model.selection.width
                };
            }
            var navFromRow;
            var navFromCol;
            if (model.focus.row === newSelection.top) {
                navFromRow = newSelection.top + newSelection.height - 1;
            } else {
                navFromRow = newSelection.top;
            }

            if (model.focus.col === newSelection.left) {
                navFromCol = newSelection.left + newSelection.width - 1;
            } else {
                navFromCol = newSelection.left;
            }
            var newRowCol = navFrom(navFromRow, navFromCol, e);
            setSelectionFromPoints(model.focus.row, model.focus.col, newRowCol.row, newRowCol.col);
            grid.cellScrollModel.scrollIntoView(newRowCol.row, newRowCol.col);
        }
    });

    function isNavableMouseEvent(e) {
        var target = e.target;
        // if there's no target let it through because that only happens in unit tests,
        // or if it happened in real world it wouldn't have a valid row or col and so wouldn't do anything anyway
        return !target || grid.eventIsOnCells(e);
    }

    grid.eventLoop.bind('mousedown', function(e) {
        if (!isNavableMouseEvent(e)) {
            return;
        }
        // assume the event has been annotated by the cell mouse model interceptor
        var row = e.row;
        var col = e.col;

        var ctrlOrCmdPressed = ctrlOrCmd(e);

        if (e.shiftKey) {
            var fromRow = model.focus.row;
            var fromCol = model.focus.col;
            var toRow = row;
            var toCol = col;
            if (row < 0) {
                fromRow = 0;
                toRow = Infinity;
            }
            if (col < 0) {
                fromCol = 0;
                toCol = Infinity;
            }
            setSelectionFromPoints(fromRow, fromCol, toRow, toCol, ctrlOrCmdPressed);
        } else {
            if (ctrlOrCmdPressed) {
                addSelection(model.selection);
            }

            var focusRow = row;
            if (focusRow < 0) {
                focusRow = grid.view.row.toData(grid.rowModel.numHeaders());
            }
            var focusCol = col;
            if (focusCol < 0) {
                focusCol = grid.view.col.toData(grid.colModel.numHeaders());
            }
            model.setFocus(focusRow, focusCol, ctrlOrCmdPressed);

            if (row < 0 && col < 0) {
                setSelectionFromPoints(0, 0, Infinity, Infinity, ctrlOrCmdPressed);
            } else if (row < 0) {
                setSelectionFromPoints(0, col, Infinity, col, ctrlOrCmdPressed);
            } else if (col < 0) {
                setSelectionFromPoints(row, 0, row, Infinity, ctrlOrCmdPressed);
            }
        }
    });

    function addSelection(range) {
        model.otherSelections.push(createAndAddSelectionDecorator(range.top, range.left, range.height, range.width));
    }

    model._rowSelectionClasses = [];
    model._colSelectionClasses = [];
    // row col selection
    function handleRowColSelectionChange(rowOrCol) {
        var decoratorsField = ('_' + rowOrCol + 'SelectionClasses');
        model[decoratorsField].forEach(function(selectionDecorator) {
            grid.cellClasses.remove(selectionDecorator);
        });
        model[decoratorsField] = [];

        grid[rowOrCol + 'Model'].getSelected().forEach(function(index) {
            var virtualIndex = grid[rowOrCol + 'Model'].toVirtual(index);
            var top = rowOrCol === 'row' ? virtualIndex : 0;
            var left = rowOrCol === 'col' ? virtualIndex : 0;
            var decorator = grid.cellClasses.create(top, left, 'selected', 1, 1, 'virtual');
            grid.cellClasses.add(decorator);
            model[decoratorsField].push(decorator);
        });
    }

    grid.eventLoop.bind('grid-row-selection-change', function() {
        handleRowColSelectionChange('row');
    });

    grid.eventLoop.bind('grid-col-selection-change', function() {
        handleRowColSelectionChange('col');
    });

    function createAndAddSelectionDecorator() {
        var selection = grid.decorators.create.apply(this, arguments);
        var defaultRender = selection.render;
        selection.render = function() {
            var div = defaultRender();
            div.setAttribute('class', 'grid-selection');
            return div;
        };
        grid.decorators.add(selection);
        return selection;
    }

    var selection = createAndAddSelectionDecorator();

    function syncSelectionToHeaders() {
        grid.colModel.clearSelected(true);
        grid.rowModel.clearSelected(true);
        model.getAllSelections().forEach(function(selection) {
            if (selection) {
                maybeSelectHeaderFromSelection(selection);
            }
        });
    }

    model.getAllSelections = function() {
        var selections = [];
        if (model.selection) {
            selections.push(model.selection);
        }
        return selections.concat(model.otherSelections);
    };

    function maybeSelectHeaderFromSelection(range, deselect) {
        var indexes;
        if (range.height === Infinity) {
            indexes = grid.data.col.indexes({
                from: range.left,
                length: range.width
            });
            if (deselect) {
                grid.colModel.deselect(indexes);
            } else {
                grid.colModel.select(indexes);
            }
        }
        if (range.width === Infinity) {
            indexes = grid.data.row.indexes({
                from: range.top,
                length: range.height
            });
            if (deselect) {
                grid.rowModel.deselect(indexes);
            } else {
                grid.rowModel.select(indexes);
            }
        }
    }

    model.setSelection = function setSelection(newSelection) {
        var height = newSelection.height;
        var width = newSelection.width;
        if (height === 1 && width === 1 && !model.otherSelections.length) {
            height = -1;
            width = -1;
        }
        selection.top = newSelection.top;
        selection.left = newSelection.left;
        selection.height = height;
        selection.width = width;
        // select the columns to match
        syncSelectionToHeaders();
    };

    function setSelectionToFocus() {
        model.setSelection({
            top: model.focus.row,
            left: model.focus.col,
            height: 1,
            width: 1
        });
    }

    function clearOtherSelections() {
        grid.decorators.remove(model.otherSelections);
        model.otherSelections = [];
        syncSelectionToHeaders();
    }

    function setSelectionFromPoints(fromRow, fromCol, toRow, toCol, dontClearOthers) {
        if (!dontClearOthers) {
            clearOtherSelections();
        }
        toRow = util.clamp(toRow, 0, Infinity);
        toCol = util.clamp(toCol, 0, Infinity);
        var newSelection = rangeUtil.createFromPoints(fromRow, fromCol, toRow, toCol);
        model.setSelection(newSelection);
    }

    selection._onDragStart = function(e) {
        if (!isNavableMouseEvent(e)) {
            return;
        }
        if (e.enableAutoScroll) {
            e.enableAutoScroll();
        }
        var fromRow = model.focus.row;
        var fromCol = model.focus.col;
        var startCol = e.col;
        var startRow = e.row;
        var unbindDrag = grid.eventLoop.bind('grid-cell-drag', function(e) {
            var toRow = e.row;
            var toCol = e.col;

            var fixedRows = grid.rowModel.numFixed(true);
            if (startRow < fixedRows && toRow > fixedRows) {
                startRow = toRow = grid.rowModel.numFixed();
                grid.cellScrollModel.scrollTo(0, grid.cellScrollModel.col);
            }
            var fixedCols = grid.colModel.numFixed(true);
            if (startCol < fixedCols && toCol > fixedCols) {
                startCol = toCol = grid.colModel.numFixed();
                grid.cellScrollModel.scrollTo(grid.cellScrollModel.row, 0);
            }

            if (selection.left === 0 && selection.width === Infinity) {
                toCol = Infinity;
            }
            if (selection.top === 0 && selection.height === Infinity) {
                toRow = Infinity;
            }

            // pass true to prevent clearing, if it were to be cleared the mousedown handles that
            setSelectionFromPoints(fromRow, fromCol, toRow, toCol, true);
        });
        var unbindDragEnd = grid.eventLoop.bind('grid-drag-end', function() {
            unbindDrag();
            unbindDragEnd();
        });
    };

    grid.eventLoop.bind('grid-drag-start', selection._onDragStart);
    setSelectionToFocus();
    model._selectionDecorator = selection;

    Object.defineProperty(model, 'selection', {
        get: function() {
            if (selection.height === -1) { // cleared selection default to focus
                return {
                    top: model.focus.row,
                    left: model.focus.col,
                    height: 1,
                    width: 1
                };
            }
            return selection;
        }
    });

    model.getAllSelectedRanges = function() {
        var selectionRange = grid.navigationModel.selection;
        // valid selection range cannot go to -1
        if (selectionRange.top === -1) {
            selectionRange = {
                top: grid.navigationModel.focus.row,
                left: grid.navigationModel.focus.col,
                width: 1,
                height: 1
            };
        }
        return [selectionRange].concat(model.otherSelections);
    };

    function clearSelectionFromModelChange(e) {
        if (e.action === 'size') { // don't clear for resize but all other changes for now will clear selection
            return;
        }
        setSelectionToFocus();
        clearOtherSelections();

    }

    grid.eventLoop.bind('grid-col-change', clearSelectionFromModelChange);
    grid.eventLoop.bind('grid-row-change', clearSelectionFromModelChange);
    return model;
};
<commit_msg>don't clear or select from right clicks<commit_after>var key = require('key');
var arrow = key.code.arrow;
var util = require('../util');
var rangeUtil = require('../range-util');
var ctrlOrCmd = require('../ctrl-or-cmd');

module.exports = function(_grid) {
    var grid = _grid;

    var model = {
        focus: {
            row: 0,
            col: 0
        }
    };

    model.otherSelections = [];

    var focusClass = grid.cellClasses.create(0, 0, 'focus');
    grid.cellClasses.add(focusClass);

    model.focusDecorator = grid.decorators.create(0, 0, 1, 1);
    var focusDefaultRender = model.focusDecorator.render;
    model.focusDecorator.render = function() {
        var div = focusDefaultRender();
        div.setAttribute('class', 'grid-focus-decorator');
        return div;
    };
    grid.decorators.add(model.focusDecorator);

    model.setFocus = function setFocus(row, col, dontClearSelection) {
        row = grid.data.row.clamp(row);
        col = grid.data.col.clamp(col);
        var changed = row !== model.focus.row || col !== model.focus.col;
        model.focus.row = row;
        model.focus.col = col;
        focusClass.top = row;
        focusClass.left = col;
        model.focusDecorator.top = row;
        model.focusDecorator.left = col;
        grid.cellScrollModel.scrollIntoView(row, col);
        if (!dontClearSelection) {
            clearOtherSelections();
        }
        setSelectionToFocus();
        if (changed) {
            grid.eventLoop.fire('grid-focus-change');
        }
    };

    function seekNextEdge(newIndex, startedDefined, isForwardEdge, isBackwardEdge, goForward) {

        var isEdgeToSeek;
        if (isForwardEdge(newIndex) || !startedDefined) {
            isEdgeToSeek = isBackwardEdge;
        } else {
            isEdgeToSeek = isForwardEdge;
        }

        while (goForward(newIndex) !== undefined && !isEdgeToSeek(newIndex = goForward(newIndex))) /*eslint-disable no-empty*/ {
            // empty
        } /*eslint-enable no-empty*/

        return newIndex;
    }

    function navFrom(row, col, e) {
        // if nothing changes great we'll stay where we are
        var newRow = row;
        var newCol = col;
        var isSeek = ctrlOrCmd(e);
        var isLeftwardEdge, isRightwardEdge, isUpwardEdge, isDownwardEdge, cellHasValue, startedDefined;
        if (isSeek) {
            cellHasValue = function(r, c) {
                if (r === undefined || c === undefined) {
                    return false;
                }

                return !!grid.dataModel.get(r, c).formatted;
            };
            isLeftwardEdge = function(c) {
                return cellHasValue(newRow, c) && !cellHasValue(newRow, grid.data.left(c));
            };
            isRightwardEdge = function(c) {
                return cellHasValue(newRow, c) && !cellHasValue(newRow, grid.data.right(c));
            };
            isUpwardEdge = function(r) {
                return cellHasValue(r, newCol) && !cellHasValue(grid.data.up(r), newCol);
            };
            isDownwardEdge = function(r) {
                return cellHasValue(r, newCol) && !cellHasValue(grid.data.down(r), newCol);
            };
            startedDefined = cellHasValue(newRow, newCol);
        }
        switch (e.which) {
            case arrow.down.code:
                if (isSeek) {
                    newRow = seekNextEdge(newRow, startedDefined, isDownwardEdge, isUpwardEdge, grid.data.down);
                } else {
                    newRow = grid.data.down(newRow);
                }
                break;
            case arrow.up.code:
                if (isSeek) {
                    newRow = seekNextEdge(newRow, startedDefined, isUpwardEdge, isDownwardEdge, grid.data.up);
                } else {
                    newRow = grid.data.up(newRow);
                }
                break;
            case arrow.right.code:
                if (isSeek) {
                    newCol = seekNextEdge(newCol, startedDefined, isRightwardEdge, isLeftwardEdge, grid.data.right);
                } else {
                    newCol = grid.data.right(newCol);
                }
                break;
            case arrow.left.code:
                if (isSeek) {
                    newCol = seekNextEdge(newCol, startedDefined, isLeftwardEdge, isRightwardEdge, grid.data.left);
                } else {
                    newCol = grid.data.left(newCol);
                }
                break;
        }
        if (newRow === undefined) {
            newRow = row;
        }
        if (newCol === undefined) {
            newCol = col;
        }
        return {
            row: newRow,
            col: newCol
        };
    }

    model._navFrom = navFrom;

    grid.eventLoop.bind('keydown', function(e) {
        if (!key.is(arrow, e.which) || !grid.focused) {
            return;
        }
        // focus logic

        if (!e.shiftKey) {
            var newFocus = navFrom(model.focus.row, model.focus.col, e);
            model.setFocus(newFocus.row, newFocus.col, e);
        } else {
            // selection logic
            var newSelection;
            // stand in for if it's cleared
            if (model.selection.top === -1) {
                newSelection = {
                    top: model.focus.row,
                    left: model.focus.col,
                    height: 1,
                    width: 1
                };
            } else {
                newSelection = {
                    top: model.selection.top,
                    left: model.selection.left,
                    height: model.selection.height,
                    width: model.selection.width
                };
            }
            var navFromRow;
            var navFromCol;
            if (model.focus.row === newSelection.top) {
                navFromRow = newSelection.top + newSelection.height - 1;
            } else {
                navFromRow = newSelection.top;
            }

            if (model.focus.col === newSelection.left) {
                navFromCol = newSelection.left + newSelection.width - 1;
            } else {
                navFromCol = newSelection.left;
            }
            var newRowCol = navFrom(navFromRow, navFromCol, e);
            setSelectionFromPoints(model.focus.row, model.focus.col, newRowCol.row, newRowCol.col);
            grid.cellScrollModel.scrollIntoView(newRowCol.row, newRowCol.col);
        }
    });

    function isNavableMouseEvent(e) {
        var target = e.target;
        // if there's no target let it through because that only happens in unit tests,
        // or if it happened in real world it wouldn't have a valid row or col and so wouldn't do anything anyway
        return !target || grid.eventIsOnCells(e) && e.button !== 2;
    }

    grid.eventLoop.bind('mousedown', function(e) {
        if (!isNavableMouseEvent(e)) {
            return;
        }
        // assume the event has been annotated by the cell mouse model interceptor
        var row = e.row;
        var col = e.col;

        var ctrlOrCmdPressed = ctrlOrCmd(e);

        if (e.shiftKey) {
            var fromRow = model.focus.row;
            var fromCol = model.focus.col;
            var toRow = row;
            var toCol = col;
            if (row < 0) {
                fromRow = 0;
                toRow = Infinity;
            }
            if (col < 0) {
                fromCol = 0;
                toCol = Infinity;
            }
            setSelectionFromPoints(fromRow, fromCol, toRow, toCol, ctrlOrCmdPressed);
        } else {
            if (ctrlOrCmdPressed) {
                addSelection(model.selection);
            }

            var focusRow = row;
            if (focusRow < 0) {
                focusRow = grid.view.row.toData(grid.rowModel.numHeaders());
            }
            var focusCol = col;
            if (focusCol < 0) {
                focusCol = grid.view.col.toData(grid.colModel.numHeaders());
            }
            model.setFocus(focusRow, focusCol, ctrlOrCmdPressed);

            if (row < 0 && col < 0) {
                setSelectionFromPoints(0, 0, Infinity, Infinity, ctrlOrCmdPressed);
            } else if (row < 0) {
                setSelectionFromPoints(0, col, Infinity, col, ctrlOrCmdPressed);
            } else if (col < 0) {
                setSelectionFromPoints(row, 0, row, Infinity, ctrlOrCmdPressed);
            }
        }
    });

    function addSelection(range) {
        model.otherSelections.push(createAndAddSelectionDecorator(range.top, range.left, range.height, range.width));
    }

    model._rowSelectionClasses = [];
    model._colSelectionClasses = [];
    // row col selection
    function handleRowColSelectionChange(rowOrCol) {
        var decoratorsField = ('_' + rowOrCol + 'SelectionClasses');
        model[decoratorsField].forEach(function(selectionDecorator) {
            grid.cellClasses.remove(selectionDecorator);
        });
        model[decoratorsField] = [];

        grid[rowOrCol + 'Model'].getSelected().forEach(function(index) {
            var virtualIndex = grid[rowOrCol + 'Model'].toVirtual(index);
            var top = rowOrCol === 'row' ? virtualIndex : 0;
            var left = rowOrCol === 'col' ? virtualIndex : 0;
            var decorator = grid.cellClasses.create(top, left, 'selected', 1, 1, 'virtual');
            grid.cellClasses.add(decorator);
            model[decoratorsField].push(decorator);
        });
    }

    grid.eventLoop.bind('grid-row-selection-change', function() {
        handleRowColSelectionChange('row');
    });

    grid.eventLoop.bind('grid-col-selection-change', function() {
        handleRowColSelectionChange('col');
    });

    function createAndAddSelectionDecorator() {
        var selection = grid.decorators.create.apply(this, arguments);
        var defaultRender = selection.render;
        selection.render = function() {
            var div = defaultRender();
            div.setAttribute('class', 'grid-selection');
            return div;
        };
        grid.decorators.add(selection);
        return selection;
    }

    var selection = createAndAddSelectionDecorator();

    function syncSelectionToHeaders() {
        grid.colModel.clearSelected(true);
        grid.rowModel.clearSelected(true);
        model.getAllSelections().forEach(function(selection) {
            if (selection) {
                maybeSelectHeaderFromSelection(selection);
            }
        });
    }

    model.getAllSelections = function() {
        var selections = [];
        if (model.selection) {
            selections.push(model.selection);
        }
        return selections.concat(model.otherSelections);
    };

    function maybeSelectHeaderFromSelection(range, deselect) {
        var indexes;
        if (range.height === Infinity) {
            indexes = grid.data.col.indexes({
                from: range.left,
                length: range.width
            });
            if (deselect) {
                grid.colModel.deselect(indexes);
            } else {
                grid.colModel.select(indexes);
            }
        }
        if (range.width === Infinity) {
            indexes = grid.data.row.indexes({
                from: range.top,
                length: range.height
            });
            if (deselect) {
                grid.rowModel.deselect(indexes);
            } else {
                grid.rowModel.select(indexes);
            }
        }
    }

    model.setSelection = function setSelection(newSelection) {
        var height = newSelection.height;
        var width = newSelection.width;
        if (height === 1 && width === 1 && !model.otherSelections.length) {
            height = -1;
            width = -1;
        }
        selection.top = newSelection.top;
        selection.left = newSelection.left;
        selection.height = height;
        selection.width = width;
        // select the columns to match
        syncSelectionToHeaders();
    };

    function setSelectionToFocus() {
        model.setSelection({
            top: model.focus.row,
            left: model.focus.col,
            height: 1,
            width: 1
        });
    }

    function clearOtherSelections() {
        grid.decorators.remove(model.otherSelections);
        model.otherSelections = [];
        syncSelectionToHeaders();
    }

    function setSelectionFromPoints(fromRow, fromCol, toRow, toCol, dontClearOthers) {
        if (!dontClearOthers) {
            clearOtherSelections();
        }
        toRow = util.clamp(toRow, 0, Infinity);
        toCol = util.clamp(toCol, 0, Infinity);
        var newSelection = rangeUtil.createFromPoints(fromRow, fromCol, toRow, toCol);
        model.setSelection(newSelection);
    }

    selection._onDragStart = function(e) {
        if (!isNavableMouseEvent(e)) {
            return;
        }
        if (e.enableAutoScroll) {
            e.enableAutoScroll();
        }
        var fromRow = model.focus.row;
        var fromCol = model.focus.col;
        var startCol = e.col;
        var startRow = e.row;
        var unbindDrag = grid.eventLoop.bind('grid-cell-drag', function(e) {
            var toRow = e.row;
            var toCol = e.col;

            var fixedRows = grid.rowModel.numFixed(true);
            if (startRow < fixedRows && toRow > fixedRows) {
                startRow = toRow = grid.rowModel.numFixed();
                grid.cellScrollModel.scrollTo(0, grid.cellScrollModel.col);
            }
            var fixedCols = grid.colModel.numFixed(true);
            if (startCol < fixedCols && toCol > fixedCols) {
                startCol = toCol = grid.colModel.numFixed();
                grid.cellScrollModel.scrollTo(grid.cellScrollModel.row, 0);
            }

            if (selection.left === 0 && selection.width === Infinity) {
                toCol = Infinity;
            }
            if (selection.top === 0 && selection.height === Infinity) {
                toRow = Infinity;
            }

            // pass true to prevent clearing, if it were to be cleared the mousedown handles that
            setSelectionFromPoints(fromRow, fromCol, toRow, toCol, true);
        });
        var unbindDragEnd = grid.eventLoop.bind('grid-drag-end', function() {
            unbindDrag();
            unbindDragEnd();
        });
    };

    grid.eventLoop.bind('grid-drag-start', selection._onDragStart);
    setSelectionToFocus();
    model._selectionDecorator = selection;

    Object.defineProperty(model, 'selection', {
        get: function() {
            if (selection.height === -1) { // cleared selection default to focus
                return {
                    top: model.focus.row,
                    left: model.focus.col,
                    height: 1,
                    width: 1
                };
            }
            return selection;
        }
    });

    model.getAllSelectedRanges = function() {
        var selectionRange = grid.navigationModel.selection;
        // valid selection range cannot go to -1
        if (selectionRange.top === -1) {
            selectionRange = {
                top: grid.navigationModel.focus.row,
                left: grid.navigationModel.focus.col,
                width: 1,
                height: 1
            };
        }
        return [selectionRange].concat(model.otherSelections);
    };

    function clearSelectionFromModelChange(e) {
        if (e.action === 'size') { // don't clear for resize but all other changes for now will clear selection
            return;
        }
        setSelectionToFocus();
        clearOtherSelections();

    }

    grid.eventLoop.bind('grid-col-change', clearSelectionFromModelChange);
    grid.eventLoop.bind('grid-row-change', clearSelectionFromModelChange);
    return model;
};<|endoftext|>


<commit_before>/**
 *
 * waveform
 *
 * @param {type} $
 * @returns {waveform_L7.waveformAnonym$2}
 */
define([
    'jquery'

], function (
    $
) {

    'use strict';

    var getWaveDataFromServer = function getWaveDataFromServerFunction(trackId, peaksAmount, callback) {

        var request = $.ajax({
            url: '/getwavedata?trackId=' + trackId + '&peaksAmount=' + peaksAmount,
            type: 'GET',
            dataType: 'json'
        });

        request.done(function(data) {

            if (typeof data !== 'undefined' && data.peaks !== undefined) {

                callback(false, data.peaks);

            } else {

                if (typeof data === 'undefined' || data.error === undefined) {

                    callback('undefined response from server');

                } else {

                    callback(data.error);

                }

            }

        });

        request.fail(function(jqXHR, textStatus) {

            callback(textStatus);

        });

    };

    var drawWave = function drawWaveFunction(data, $element, options) {

        console.log(data);
        console.log($element);
        console.log(options);

        var canvasContext = getCanvasContext($element);
        var peaksLength = data.length;
        var canvasHeight = options.waveHeight * 2;
        var canvasWidth = (peaksLength * options.peakWidth) + ((peaksLength - 1) * options.spaceWidth);
        var peakColor = options.peakColorHex;

        $element.attr('height', canvasHeight);
        $element.attr('width', canvasWidth);

        canvasContext.fillStyle = '#ffff00';
        canvasContext.fillRect(0, 0, canvasWidth, canvasHeight);

        var i;

        canvasContext.lineWidth = options.peakWidth;

        var heightPercentage = options.waveHeight / 100;

        for (i = 0; i < peaksLength; i++) {

            var peakHeightInPercent = data[i];

            var peakBottom = ((i + 1) * options.peakWidth) + (i * options.spaceWidth);
            var peakHeight = options.waveHeight - (heightPercentage * peakHeightInPercent);

            canvasContext.beginPath();
            canvasContext.moveTo(peakBottom, options.waveHeight);
            canvasContext.lineTo(peakBottom, peakHeight);
            canvasContext.stroke();

        }

    };

    var audioContext;

    var getAudioContext = function getAudioContextFunction() {

        var AudioContext = window.AudioContext || window.webkitAudioContext;

        audioContext = new AudioContext();

    };

    var getCanvasContext = function getCanvasContextFunction($element) {

        var canvasContext = $element[0].getContext('2d');

        return canvasContext;

    };

    var initialize = function initializeFunction() {

        getAudioContext();

    };

    return {
        init: initialize,
        draw: drawWave,
        getDataFromServer: getWaveDataFromServer
    };

});<commit_msg>find click position<commit_after>/**
 *
 * waveform
 *
 * @param {type} $
 * @returns {waveform_L7.waveformAnonym$2}
 */
define([
    'jquery'

], function (
    $
) {

    'use strict';

    var getWaveDataFromServer = function getWaveDataFromServerFunction(trackId, peaksAmount, callback) {

        var request = $.ajax({
            url: '/getwavedata?trackId=' + trackId + '&peaksAmount=' + peaksAmount,
            type: 'GET',
            dataType: 'json'
        });

        request.done(function(data) {

            if (typeof data !== 'undefined' && data.peaks !== undefined) {

                callback(false, data.peaks);

            } else {

                if (typeof data === 'undefined' || data.error === undefined) {

                    callback('undefined response from server');

                } else {

                    callback(data.error);

                }

            }

        });

        request.fail(function(jqXHR, textStatus) {

            callback(textStatus);

        });

    };

    var drawWave = function drawWaveFunction(data, $element, options) {

        console.log(data);
        console.log($element);
        console.log(options);

        var canvasContext = getCanvasContext($element);
        var peaksLength = data.length;
        var canvasHeight = options.waveHeight * 2;
        var canvasWidth = (peaksLength * options.peakWidth) + ((peaksLength - 1) * options.spaceWidth);
        var peakColor = options.peakColorHex;

        $element.attr('height', canvasHeight);
        $element.attr('width', canvasWidth);

        canvasContext.fillStyle = '#ffff00';
        canvasContext.fillRect(0, 0, canvasWidth, canvasHeight);

        var i;

        canvasContext.lineWidth = options.peakWidth;

        var heightPercentage = options.waveHeight / 100;

        for (i = 0; i < peaksLength; i++) {

            var peakHeightInPercent = data[i];

            var peakBottom = ((i + 1) * options.peakWidth) + (i * options.spaceWidth);
            var peakHeight = options.waveHeight - (heightPercentage * peakHeightInPercent);

            canvasContext.beginPath();
            canvasContext.moveTo(peakBottom, options.waveHeight);
            canvasContext.lineTo(peakBottom, peakHeight);
            canvasContext.stroke();

        }

        addClickListener($element);

    };

    var addClickListener = function addClickListenerFunction($element) {

        $element.on('click', function(event) {

            getMousePosition($element, event);

        });

    };

    var getMousePosition = function getMousePositionFunction($element, event) {

        var boundingClientRectangle = $element[0].getBoundingClientRect();

        var position = event.clientX - boundingClientRectangle.left;

        console.log(position);

    };

    var audioContext;

    var getAudioContext = function getAudioContextFunction() {

        var AudioContext = window.AudioContext || window.webkitAudioContext;

        audioContext = new AudioContext();

    };

    var getCanvasContext = function getCanvasContextFunction($element) {

        var canvasContext = $element[0].getContext('2d');

        return canvasContext;

    };

    var initialize = function initializeFunction() {

        getAudioContext();

    };

    return {
        init: initialize,
        draw: drawWave,
        getDataFromServer: getWaveDataFromServer
    };

});<|endoftext|>


<commit_before><commit_msg>forgot to build again, sigh<commit_after><|endoftext|>


<commit_before>/* eslint-disable */
import { useStrict } from "mobx";
import ProjectStore from "../../stores/domain/ProjectStore";
import Suite from "../../models/Suite";
import TestCase from "../../models/TestCase";

useStrict(true);

describe("Suite model", () => {
  it("new suite should be named 'Utitled Suite'", () => {
    expect((new Suite()).name).toBe("Untitled Suite");
  });
  it("Suites should have randomly generated identifiers", () => {
    expect((new Suite()).id).not.toBe((new Suite()).id);
  });
  it("should rename the suite", () => {
    const suite = new Suite();
    suite.setName("test");
    expect(suite.name).toBe("test");
  });
  it("should add a new Test Case", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    expect(suite.tests.length).toBe(0);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
  });
  it("should throw if no Test Case was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase()).toThrowError("Expected to receive TestCase instead received undefined");
  });
  it("should throw if a different type was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase(1)).toThrowError("Expected to receive TestCase instead received Number");
  });
  it("should remove a Test Case from the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(test);
    expect(suite.tests.length).toBe(0);
  });
  it("should do nothing if removed a non-existent test", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(new TestCase());
    expect(suite.tests.length).toBe(1);
  });
  it("should replace the tests in the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    store.createTestCase();
    store.createTestCase();
    store.createTestCase();
    expect(suite.tests.length).toBe(0);
    suite.replaceTestCases(store.tests);
    expect(suite.tests.length).toBe(3);
  });
  it("should load from JS", () => {
    const jsRep = {
      id: "1",
      name: "test suite",
      tests: []
    };
    const suite = Suite.fromJS(jsRep);
    expect(suite.id).toBe(jsRep.id);
    expect(suite.name).toBe(jsRep.name);
    expect(suite instanceof Suite).toBeTruthy();
  });
  it("should load tests from JS", () => {
    const jsRep = {
      id: "1",
      name: "test suite",
      tests: [
        {
          id: "2",
          name: "first test"
        },
        {
          id: "3",
          name: "second test"
        }
      ]
    };
    const suite = Suite.fromJS(jsRep);
    expect(suite.tests.length).toBe(2);
    expect(suite.tests[0] instanceof TestCase).toBeTruthy();
  });
});
<commit_msg>load tests as well<commit_after>/* eslint-disable */
import { useStrict } from "mobx";
import ProjectStore from "../../stores/domain/ProjectStore";
import Suite from "../../models/Suite";
import TestCase from "../../models/TestCase";

useStrict(true);

describe("Suite model", () => {
  it("new suite should be named 'Utitled Suite'", () => {
    expect((new Suite()).name).toBe("Untitled Suite");
  });
  it("Suites should have randomly generated identifiers", () => {
    expect((new Suite()).id).not.toBe((new Suite()).id);
  });
  it("should rename the suite", () => {
    const suite = new Suite();
    suite.setName("test");
    expect(suite.name).toBe("test");
  });
  it("should add a new Test Case", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    expect(suite.tests.length).toBe(0);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
  });
  it("should throw if no Test Case was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase()).toThrowError("Expected to receive TestCase instead received undefined");
  });
  it("should throw if a different type was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase(1)).toThrowError("Expected to receive TestCase instead received Number");
  });
  it("should remove a Test Case from the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(test);
    expect(suite.tests.length).toBe(0);
  });
  it("should do nothing if removed a non-existent test", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(new TestCase());
    expect(suite.tests.length).toBe(1);
  });
  it("should replace the tests in the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    store.createTestCase();
    store.createTestCase();
    store.createTestCase();
    expect(suite.tests.length).toBe(0);
    suite.replaceTestCases(store.tests);
    expect(suite.tests.length).toBe(3);
  });
  it("should load from JS", () => {
    const jsRep = {
      id: "1",
      name: "test suite",
      tests: []
    };
    const suite = Suite.fromJS(jsRep);
    expect(suite.id).toBe(jsRep.id);
    expect(suite.name).toBe(jsRep.name);
    expect(suite instanceof Suite).toBeTruthy();
  });
  it("should load tests from JS", () => {
    const projectTests = [
      {
        id: "2",
        name: "first test",
        commands: []
      },
      {
        id: "3",
        name: "second test",
        commands: []
      }
    ];
    const jsRep = {
      id: "1",
      name: "test suite",
      tests: ["2", "3"]
    };
    const suite = Suite.fromJS(jsRep, projectTests);
    expect(suite.tests.length).toBe(2);
    expect(suite.tests[0] instanceof TestCase).toBeTruthy();
  });
});
<|endoftext|>


<commit_before>'use strict'
/**
 * Dependencies
 */
const cwd = process.cwd()
const path = require('path')
const firebase = require('firebase')
const BaseHandler = require(path.join(cwd, 'handlers', 'BaseHandler'))
const Player = require(path.join(cwd, 'models', 'Player'))
const Game = require(path.join(cwd, 'models', 'Game'))
const Secret = require(path.join(cwd, 'models', 'Secret'))

/**
 * Scope
 */
const scope = 'KillHandler'

/**
 * KillHandler
 */
class KillHandler extends BaseHandler {

  static handle (event) {
    let handler = new KillHandler(event)

    Promise
      .resolve({handler})
      .then(handler.verify)
      .then(handler.kill)
      .then(handler.done)
  }

  verify (opts) {
    let {handler} = opts

    if (!handler.event || !handler.event.game) {
      return handler.error({
        scope,
        message: 'kill event must have game field'
      })
    }

    if (!handler.event || !handler.event.subject) {
      return handler.error({
        scope,
        message: 'kill event must have subject field'
      })
    }

    if (!handler.event || !handler.event.secret) {
      return handler.error({
        scope,
        message: 'kill event must have secret field'
      })
    }

    return new Promise((resolve, reject) => {
      let game = Game.get(handler.event.game)
      let killer = Player.get(handler.event.game, handler.event.subject)
      let secret = Secret.get(handler.event.secret)
      let target

      Promise.all([
        game.loaded,
        killer.loaded,
        secret.loaded
      ]).then(() => {
        if (!killer || !killer.val) {
          reject(handler.error({
            scope,
            message: `${handler.event.subject} (killer) is an invalid player`
          }))
        }

        if (killer.val.game_state !== 'zombie' && killer.val.game_state !== 'original-zombie') {
          reject(handler.error({
            scope,
            message: `${handler.event.subject} (killer) needs to be a zombie to tag a human`
          }))
        }

        if (!game || game.val.status !== 'started') {
          reject(handler.error({
            scope,
            message: `${handler.event.game} needs to have started to register a kill`
          }))
        }

        if (!secret || !secret.val) {
          reject(handler.error({
            scope,
            message: `${handler.event.secret} is an invalid secret`
          }))
        }

      }).then(() => {
        target = Player.get(handler.event.game, secret.val)
        return target.loaded
      }).then(() => {
        if (!target || !target.val) {
          reject(handler.error({
            scope,
            message: `${secret.val} (target) is an invalid player`
          }))
        }

        if (target.val.game_state !== 'human') {
          reject(handler.error({
            scope,
            message: `${secret.val} (target) needs to be human to be tagged`
          }))
        }

        resolve({
          handler,
          game,
          subject: killer,
          target
        })

      })
    })
  }

  kill (opts) {
    let {handler, game, subject, target} = opts

    return new Promise((resolve, reject) => {
      Promise.all([
        target.killedBy(subject),
        subject.kill(target)
      ]).then(() => {
        resolve(opts)
      })
    })
  }

}

/**
 * Exports
 */
module.exports = KillHandler<commit_msg>feat(KillHandler): better error handling<commit_after>'use strict'
/**
 * Dependencies
 */
const cwd = process.cwd()
const path = require('path')
const firebase = require('firebase')
const BaseHandler = require(path.join(cwd, 'handlers', 'BaseHandler'))
const Player = require(path.join(cwd, 'models', 'Player'))
const Game = require(path.join(cwd, 'models', 'Game'))
const Secret = require(path.join(cwd, 'models', 'Secret'))

/**
 * Scope
 */
const scope = 'KillHandler'

/**
 * KillHandler
 */
class KillHandler extends BaseHandler {

  static handle (event) {
    let handler = new KillHandler(event)

    Promise
      .resolve({handler})
      .then(handler.verify)
      .then(handler.kill)
      .then(handler.done)
  }

  verify (opts) {
    let {handler} = opts

    if (!handler.event || !handler.event.game) {
      return handler.error({
        scope,
        message: 'kill event must have game field'
      })
    }

    if (!handler.event || !handler.event.subject) {
      return handler.error({
        scope,
        message: 'kill event must have subject field'
      })
    }

    if (!handler.event || !handler.event.secret) {
      return handler.error({
        scope,
        message: 'kill event must have secret field'
      })
    }

    return new Promise((resolve, reject) => {
      let game = Game.get(handler.event.game)
      let killer = Player.get(handler.event.game, handler.event.subject)
      let secret = Secret.get(handler.event.secret)
      let target

      Promise.all([
        game.loaded,
        killer.loaded,
        secret.loaded
      ]).then(() => {
        if (!killer || !killer.val) {
          reject(handler.error({
            scope,
            message: `${handler.event.subject} (killer) is an invalid player`
          }))
        }

        if (killer.val.game_state !== 'zombie' && killer.val.game_state !== 'original-zombie') {
          reject(handler.error({
            scope,
            message: `${handler.event.subject} (killer) needs to be a zombie to tag a human`
          }))
        }

        if (!game || game.val.status !== 'started') {
          reject(handler.error({
            scope,
            message: `${handler.event.game} needs to have started to register a kill`
          }))
        }

        if (!secret || !secret.val) {
          reject(handler.error({
            scope,
            message: `${handler.event.secret} is an invalid secret`
          }))
        }

      }).then(() => {
        target = Player.get(handler.event.game, secret.val)
        return target.loaded
      }).then(() => {
        if (!target || !target.val) {
          reject(handler.error({
            scope,
            message: `${secret.val} (target) is an invalid player`
          }))
        }

        if (target.val.game_state !== 'human') {
          reject(handler.error({
            scope,
            message: `${secret.val} (target) needs to be human to be tagged`
          }))
        }

        resolve({
          handler,
          game,
          subject: killer,
          target
        })

      })
    })
  }

  kill (opts) {
    let {handler, game, subject, target} = opts

    return new Promise((resolve, reject) => {
      Promise.all([
        target.killedBy(subject),
        subject.kill(target)
      ]).then(() => {
        resolve(opts)
      }).catch((err) => {
        reject(handler.error({
          scope,
          message: err.message || err
        }))
      })
    })
  }

}

/**
 * Exports
 */
module.exports = KillHandler<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import '!style-loader!css-loader!./DashboardDetail.css'

import IconClose from '@material-ui/icons/ArrowForwardIos'
import IconWidget from '@material-ui/icons/Apps'
import IconDetail from '@material-ui/icons/VerticalSplitOutlined'
import IconList from '@material-ui/icons/ViewHeadlineOutlined'
import Link from 'views/components/Link'

import useTheme from 'DataSource/useTheme'
import selectn from 'selectn'
import Typography from '@material-ui/core/Typography'
/**
 * @summary DashboardDetailPresentation
 * @version 1.0.1
 * @component
 *
 * @param {object} props
 * @param {function} props.onClose
 * @param {function} props.onOpen
 * @param {node} props.childrenSelectedDetail
 * @param {node} props.childrenSelectedSidebar
 * @param {node} props.childrenUnselected
 * @param {string} props.selectedId
 *
 * @returns {node} jsx markup
 */
function DashboardDetailPresentation({
  childrenSelectedDetail,
  childrenSelectedSidebar,
  childrenUnselected,
  onClose,
  onOpen,
  selectedId,
}) {
  const { theme } = useTheme()
  const workshopDark = selectn(['palette', 'primary', 'dark'], theme)
  return (
    <div className={`DashboardDetail ${selectedId ? 'DashboardDetail--Selected' : 'DashboardDetail--nothingSelected'}`}>
      {/* DashboardDetail__header
      ------------------------------------------ */}

        <Link href="/dashboard" className="DashboardDetail__headerLink">

            <IconWidget fontSize="large" />{' '}

          <Typography variant="h5" component="span">
            Back to Dashboard
          </Typography>
        </Link>

        {selectedId && (
          <button className="DashboardDetail__headerButton" onClick={onClose}>

              <IconList fontSize="large" />

            <Typography variant="h5" component="span">
              Show full list view
            </Typography>
          </button>
        )}
        {selectedId === undefined && (
          <button className="DashboardDetail__headerButton" onClick={onOpen}>

              <IconDetail fontSize="large" />

            <Typography variant="h5" component="span">
              Show detail view
            </Typography>
          </button>
        )}

      {/* Full list view (no item selected)
      ------------------------------------------ */}
      {selectedId === undefined && childrenUnselected}

      {/* Detail view (item is selected)
      ------------------------------------------ */}
      {selectedId && (
        <>
          {/* Sidebar
          ------------------------------------------ */}

{childrenSelectedSidebar}

          {/* Selected item details/admin
          ------------------------------------------ */}

            <button className="DashboardDetail__selectedItemClose" onClick={onClose}>
              <IconClose className="DashboardDetail__selectedItemCloseIcon" fontSize="small" />
            </button>
            {childrenSelectedDetail}

        </>
      )}

  )
}
// PROPTYPES
const { func, node, string } = PropTypes
DashboardDetailPresentation.propTypes = {
  childrenSelectedDetail: node,
  childrenSelectedSidebar: node,
  childrenUnselected: node,
  onClose: func,
  onOpen: func,
  selectedId: string,
}

export default DashboardDetailPresentation
<commit_msg>FW-1837 Dropped buttons (#479)<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import '!style-loader!css-loader!./DashboardDetail.css'

import IconClose from '@material-ui/icons/ArrowForwardIos'
import IconWidget from '@material-ui/icons/Apps'
import Link from 'views/components/Link'

import useTheme from 'DataSource/useTheme'
import selectn from 'selectn'
import Typography from '@material-ui/core/Typography'
/**
 * @summary DashboardDetailPresentation
 * @version 1.0.1
 * @component
 *
 * @param {object} props
 * @param {function} props.onClose
 * @param {function} props.onOpen
 * @param {node} props.childrenSelectedDetail
 * @param {node} props.childrenSelectedSidebar
 * @param {node} props.childrenUnselected
 * @param {string} props.selectedId
 *
 * @returns {node} jsx markup
 */
function DashboardDetailPresentation({
  childrenSelectedDetail,
  childrenSelectedSidebar,
  childrenUnselected,
  onClose,
  selectedId,
}) {
  const { theme } = useTheme()
  const workshopDark = selectn(['palette', 'primary', 'dark'], theme)
  return (
    <div className={`DashboardDetail ${selectedId ? 'DashboardDetail--Selected' : 'DashboardDetail--nothingSelected'}`}>
      {/* DashboardDetail__header
      ------------------------------------------ */}

        <Link href="/dashboard" className="DashboardDetail__headerLink">

            <IconWidget fontSize="large" />{' '}

          <Typography variant="h5" component="span">
            Back to Dashboard
          </Typography>
        </Link>

      {/* Full list view (no item selected)
      ------------------------------------------ */}
      {selectedId === undefined && childrenUnselected}

      {/* Detail view (item is selected)
      ------------------------------------------ */}
      {selectedId && (
        <>
          {/* Sidebar
          ------------------------------------------ */}

{childrenSelectedSidebar}

          {/* Selected item details/admin
          ------------------------------------------ */}

            <button className="DashboardDetail__selectedItemClose" onClick={onClose}>
              <IconClose className="DashboardDetail__selectedItemCloseIcon" fontSize="small" />
            </button>
            {childrenSelectedDetail}

        </>
      )}

  )
}
// PROPTYPES
const { func, node, string } = PropTypes
DashboardDetailPresentation.propTypes = {
  childrenSelectedDetail: node,
  childrenSelectedSidebar: node,
  childrenUnselected: node,
  onClose: func,
  onOpen: func,
  selectedId: string,
}

export default DashboardDetailPresentation
<|endoftext|>


<commit_before>var GitHubApi = require("github")
  , config = require("config")

var apiOptions = {
  protocol: config.github.api.protocol,
  host: config.github.api.host,
  version: config.github.api.version,
  pathPrefix: config.github.api.pathPrefix,
  timeout: 5000
}

/**
 * Create an authenticated instance of the GitHub API accessor.
 *
 * @param {String} authToken OAuth access token
 * - If a user-specific token is not supplied, uses the master OAuth token
 */
module.exports.getInstance = function (authToken) {
  var instance = new GitHubApi(apiOptions)
  instance.authenticate({
    type: "oauth",
    token: authToken ? authToken : config.github.token
  })
  return instance
}
<commit_msg>allow to override github port in config<commit_after>var GitHubApi = require("github")
  , config = require("config")

var apiOptions = {
  protocol: config.github.api.protocol,
  host: config.github.api.host,
  port: config.github.api.port,
  version: config.github.api.version,
  pathPrefix: config.github.api.pathPrefix,
  timeout: 5000
}

/**
 * Create an authenticated instance of the GitHub API accessor.
 *
 * @param {String} authToken OAuth access token
 * - If a user-specific token is not supplied, uses the master OAuth token
 */
module.exports.getInstance = function (authToken) {
  var instance = new GitHubApi(apiOptions)
  instance.authenticate({
    type: "oauth",
    token: authToken ? authToken : config.github.token
  })
  return instance
}
<|endoftext|>


<commit_before>(function() {
    /* Tools to be called from gulp when building a standard app */

    "use strict";
    var gulp = require('gulp');
    var fs = require("fs");
    var path = require("path");

    var browserify = require("browserify");
    var es6ify = require("es6ify");
    var stringify = require('stringify');

    var remapify = require("remapify");
    var filterTransform = require("filter-transform");
    var uglify = require('gulp-uglify');
    var buffer = require('vinyl-buffer');
    var source = require('vinyl-source-stream');
    var extend = require("extend");

    var stripify = require("stripify");

    var chokidar = require('chokidar');

    var async = require("async");

    var tools = module.exports;
    var cwd = process.cwd();

    var sassPath = process.platform === "win32" ? "sass.bat" : "sass";

    var options = {
        globals: {
            angular: "angular",
            jquery: "$"
        },
        serverapp: {

        },
        sourceFolder: "./src",
        libFolder: "./lib",
        cssEntryPoint: "./css/index.scss",
        moduleMappings: {},
        customBrowserifyTransforms: [],
        additionalWatchPaths: [],
        buildfolder: "./build",
        cssVariations: {
            "ie": '$browserType: "ie";'
        },
        imageFolders: ["./src/images"]
    };

    tools.init = function(opt) {
        extend(options, opt);
        options.moduleMappings.chondric = path.resolve(__dirname, "../es6");

    };

    tools.test = function() {
        console.log("Test function");
    };

    tools.buildVariation = function(variation, env, watch, destFolder, onBuildComplete) {
        console.log(options);
        var debugMode = env != "prod"; //true;
        if (options.debug !== undefined) debugMode = options.debug;
        if (options[env] && options[env].debug !== undefined) debugMode = options[env].debug;
        console.log("Debug: " + debugMode);
        console.log("building " + variation + " for " + env);
        var buildfolder = path.resolve(cwd, options.buildfolder);
        if (!fs.existsSync(buildfolder)) fs.mkdirSync(buildfolder);
        var tempFolder = path.resolve(buildfolder, "temp");
        if (!fs.existsSync(tempFolder)) fs.mkdirSync(tempFolder);
        var envFolder = path.resolve(buildfolder, env);
        if (!fs.existsSync(envFolder)) fs.mkdirSync(envFolder);
        var varFolder = path.resolve(buildfolder, env, variation);
        if (!fs.existsSync(varFolder)) fs.mkdirSync(varFolder);

        if (destFolder) varFolder = path.resolve(cwd, destFolder);

        var hostSettings = {};
        extend(hostSettings, options.hostSettings);
        extend(hostSettings, options[env]);
        fs.writeFileSync(path.resolve(tempFolder, "hostsettings.js"), "module.exports=" + JSON.stringify(hostSettings), "utf-8");

        var moduleMappings = [{
            src: 'hostsettings.js',
            expose: 'build',
            cwd: tempFolder
        }];
        for (var k in options.moduleMappings) {
            moduleMappings.push({
                src: './**/*.html',
                expose: k,
                cwd: options.moduleMappings[k],
            });
            moduleMappings.push({
                src: './**/*.js',
                expose: k,
                cwd: options.moduleMappings[k],
            });
        }

        console.log(moduleMappings);

        var sourceFolder = path.resolve(cwd, options.sourceFolder);
        var libFolder = path.resolve(cwd, options.libFolder);

        es6ify.traceurOverrides = {
            annotations: true,
            types: true,
            memberVariables: true
        };

        var filteredEs6ify = filterTransform(
            function(file) {
                // browserify needs transforms to be global, and compiling es5 modules
                // breaks stuff, so only compile the bits we know are es6
                if (file.indexOf("node_modules") >= 0) {
                    // files under node_modules are only compiled as es6 if they are included in
                    // moduleMappings - i.e. if chondric was loaded with npm install rather than npm link
                    for (var i = 0; i < moduleMappings.length; i++) {
                        var pn = moduleMappings[i].cwd;
                        if (file.indexOf(pn) === 0 && file.lastIndexOf("node_modules") < pn.length) {
                            return path.extname(file) === '.js';
                        }
                    }
                    return false;
                }
                return path.extname(file) === '.js';

            },
            es6ify
        );

        var globalShim = filterTransform(
            function(file) {
                return path.extname(file) === ".js";
            },
            require('browserify-global-shim').configure(options.globals)
        );

        function buildClientJs(onComplete) {
            var jsBuildError = null;

            var b = browserify({
                    debug: debugMode,
                    extensions: [".txt", ".html"],
                    //paths: [path.resolve(__dirname,"../es6")]
                })
                .add(es6ify.runtime, {
                    entry: true
                })
                .plugin(remapify, moduleMappings)
                .transform(stringify({
                    extensions: ['.txt', '.html'],
                    minify: true
                }), {
                    global: true
                });

            for (var i = 0; i < options.customBrowserifyTransforms.length; i++) {
                b = b.transform(options.customBrowserifyTransforms[i]());
            }

            b = b.transform(filteredEs6ify, {
                global: true
            });

            b = b.transform(globalShim, {
                global: true
            });

            if (!debugMode) {
                // remove console.log calls
                b = b.transform({
                    global: true
                }, stripify);
            }
            if (debugMode && options.browserTests) {
                // inject tests
                b.require(require.resolve(path.resolve(cwd, options.browserTests)), {
                    expose: "test",
                    entry: true
                });
            }
            b.require(require.resolve(path.resolve(sourceFolder, variation + ".js")), {
                entry: true
            });

            function reportError(title, msg, source, detail) {
                var errorReporter = fs.readFileSync(path.resolve(__dirname, "./reporterror.js"), "utf-8");

                errorReporter = errorReporter.replace("\"[TITLE]\"", JSON.stringify(title || "Error"));
                errorReporter = errorReporter.replace("\"[MESSAGE]\"", JSON.stringify(msg || "Something went wrong"));
                errorReporter = errorReporter.replace("\"[SOURCE]\"", JSON.stringify(source || ""));
                errorReporter = errorReporter.replace("\"[DETAIL]\"", JSON.stringify(detail || ""));
                return errorReporter;
            }

            b = b.bundle()
                .once('error', function(err) {
                    console.log("Browserify error");
                    console.log(err.message);
                    var msg = err.message;
                    var source = "";
                    var detail = "";

                    var m = /(.*):(\d+):(\d+): (.*)/.exec(msg);
                    if (m && m.length >= 5) {
                        msg = m[4];
                        var fn = m[1];
                        var errorLine = parseInt(m[2]);
                        source = m[1] + ":" + m[2] + ":" + m[3];
                        detail = "";

                        var sc = fs.readFileSync(fn, "utf-8").split("\n");
                        for (var i = errorLine - 4; i < errorLine + 3; i++) {
                            var l = sc[i];
                            if (l === undefined) continue;
                            detail += l + "\n";
                        }

                    }

                    jsBuildError = {
                        message: msg,
                        source: source,
                        detail: detail
                    };
                    var errorReporter = reportError("BuildError", msg, source, detail);
                    fs.writeFileSync(path.resolve(varFolder, "app.js"), errorReporter);
                    if (onComplete) onComplete(jsBuildError);
                    this.emit("end");
                });
            b.on('error', function(err) {
                // Ignore any errors after the first so onComplete is only called once
            });
            b.on("end", function() {
                if (!jsBuildError) {
                    console.log("Done browserify");
                    if (onComplete) onComplete();
                }
            });

            var appFile = path.resolve(varFolder, "app.js");
            var appFileTemp = path.resolve(varFolder, "app (building).js");
            var appFileEs3 = path.resolve(varFolder, "app-es3.js");

            // For use with <script>$.getScript(window.atob ? "app.js" : "app-es3.js");</script>
            fs.writeFileSync(appFileEs3, reportError("App error", "This app is designed for use in modern browsers."));

            if (debugMode) {
                fs.writeFileSync(appFile, reportError("Build Incomplete", "Browserify build in progress - try again in a few seconds."));

                b.on("end", function() {
                    if (!jsBuildError && fs.existsSync(appFileTemp)) {
                        if (fs.existsSync(appFile)) fs.unlinkSync(appFile);
                        fs.renameSync(appFileTemp, appFile);
                    }
                });

                b = b.pipe(fs.createWriteStream(appFileTemp));
            } else {
                b = b
                    .pipe(source('app.js')) // gives streaming vinyl file object
                    .pipe(buffer()) // <----- convert from streaming to buffered vinyl file object
                    .pipe(uglify({
                        mangle: true,
                        compress: false
                    }))
                    .pipe(gulp.dest(varFolder));
            }

        }

        function copyHtml() {
            gulp.src(sourceFolder + '/*.html')
                .pipe(gulp.dest(varFolder));
        }

        function copyLib() {
            gulp.src(libFolder + '/*.js')
                .pipe(gulp.dest(varFolder + "/lib"));
        }

        function copyImages() {
            var flatten = require('gulp-flatten');
            console.log("Copying images");
            var globs = [];
            for (var i = 0; i < options.imageFolders.length; i++) {
                var imgf = options.imageFolders[i];
                globs.push(imgf + "/**");
            }

            console.log(globs);
            gulp.src(globs)
                .pipe(flatten())
                .pipe(gulp.dest(varFolder + "/images"));

        }

        //        function copyImages() {
        //            gulp.src(__dirname + '/apphtml/images/**/*')
        //                .pipe(gulp.dest(options.buildfolder + "/" + env + "/" + variation + "/images"))
        //                .on("end", function() {
        //                    gulp.src(process.cwd() + "/images/**/*")
        //                        .pipe(gulp.dest(options.buildfolder + "/" + env + "/" + variation + "/images"));
        //                });
        //        }

        function buildCssFile(inputFile, outputFile, fileBuilt) {
            var params = (debugMode ? ["--style", "nested"] : ["--style", "compressed"])
                .concat(["-I", ".", inputFile, varFolder + "/" + outputFile]);
            // using spawn because libsass sourcemaps are buggy

            var spawn = require("child_process").spawn;
            var p = spawn(sassPath, params, {
                cwd: cwd
            });
            p.stdout.on('data', function(data) {
                console.log("" + data);
            });

            p.stderr.on('data', function(data) {
                console.log("" + data);
            });
            p.on("close", function(code) {
                console.log("Done sass build of " + inputFile + " with code " + code);
                if (fileBuilt) fileBuilt(code === 0 ? null : ("SASS Error " + code));
            });

        }

        function buildCss(onCssBuilt) {
            var cssEntryPoint = path.resolve(cwd, options.cssEntryPoint);

            buildCssFile(cssEntryPoint, "app.css", function(err) {
                if (err) return onCssBuilt && onCssBuilt();

                var variations = [];
                for (var k in options.cssVariations) {
                    variations.push({
                        key: k,
                        settings: options.cssVariations[k]
                    });
                }

                async.eachSeries(variations, function(v, next) {
                    var iesrc = v.settings + '\n@import "' + (path.relative(tempFolder, cssEntryPoint).replace(/\\/ig, "/")) + '";';
                    var ieCssFile = path.resolve(tempFolder, "index-" + v.key + ".scss");
                    fs.writeFileSync(ieCssFile, iesrc);
                    buildCssFile(ieCssFile, "app-" + v.key + ".css", next);
                }, onCssBuilt);

            });

        }

        buildClientJs(function(err) {
            if (err) return onBuildComplete && onBuildComplete(err);
            buildCss(function(err) {
                if (err) return onBuildComplete && onBuildComplete(err);
                copyHtml();
                copyImages();
                copyLib();
                if (options.afterBrowserify) options.afterBrowserify(varFolder, env, variation);
                console.log("Build completed successfully");
                return onBuildComplete && onBuildComplete(err);
            });
        });

        if (watch) {

            var paths = [
                    path.resolve(__dirname, "../es6"),
                    sourceFolder
                ]
                .concat(options.additionalWatchPaths);

            // watch the css folder if it isn't already watched as part of the source folder
            var cssFolder = path.dirname(path.resolve(cwd, options.cssEntryPoint));
            if (cssFolder.indexOf(sourceFolder) !== 0) paths.push(cssFolder);

            // watch image folders
            for (var i = 0; i < options.imageFolders.length; i++) {
                var imgf = options.imageFolders[i];
                if (imgf.indexOf(sourceFolder) !== 0) paths.push(imgf);
            }

            // watch tests
            if (options.browserTests) {
                paths.push(path.dirname(path.resolve(options.browserTests)));
            }

            var watcher = chokidar.watch(paths, {
                ignored: /[\/\\]\./,
                persistent: true,
                ignoreInitial: true
            });

            watcher.on("all", function(type, file) {
                console.log(type + " event for " + file);
                var ext = path.extname(file);
                if (ext == ".scss") {
                    console.log("CSS needs rebuild");
                    buildCss();
                } else if (ext == ".js" || ext == ".html") {
                    console.log("Browserify package needs rebuild");
                    buildClientJs(function(err) {
                        if (!err && options.afterBrowserify) options.afterBrowserify(varFolder, env, variation);
                    });
                } else if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif") {
                    console.log("Updating images");
                    copyImages();

                }
                // if the changed file is .js or .html, need to run browserify
                // copy html only copies a single file, so maybe just include that in the browserify process

                // src/images just needs to be copied if anything changes, and it can't contain anything used by browserify

            });

        }
    };

    tools.buildTask = function() {
        var args = process.argv.slice(3);
        if (args.length != 2 || args[0].indexOf("--") !== 0 || args[1].indexOf("--") !== 0) {
            console.log("Invalid arguments for build task");
            console.log("Usage: gulp build --web --dev");
            return;
        }
        var variation = args[0].substr(2);
        var env = args[1].substr(2);

        tools.buildVariation(variation, env);
    };

})();
<commit_msg>add d3 to global shims<commit_after>(function() {
    /* Tools to be called from gulp when building a standard app */

    "use strict";
    var gulp = require('gulp');
    var fs = require("fs");
    var path = require("path");

    var browserify = require("browserify");
    var es6ify = require("es6ify");
    var stringify = require('stringify');

    var remapify = require("remapify");
    var filterTransform = require("filter-transform");
    var uglify = require('gulp-uglify');
    var buffer = require('vinyl-buffer');
    var source = require('vinyl-source-stream');
    var extend = require("extend");

    var stripify = require("stripify");

    var chokidar = require('chokidar');

    var async = require("async");

    var tools = module.exports;
    var cwd = process.cwd();

    var sassPath = process.platform === "win32" ? "sass.bat" : "sass";

    var options = {
        globals: {
            angular: "angular",
            jquery: "$",
            d3: "d3"
        },
        serverapp: {

        },
        sourceFolder: "./src",
        libFolder: "./lib",
        cssEntryPoint: "./css/index.scss",
        moduleMappings: {},
        customBrowserifyTransforms: [],
        additionalWatchPaths: [],
        buildfolder: "./build",
        cssVariations: {
            "ie": '$browserType: "ie";'
        },
        imageFolders: ["./src/images"]
    };

    tools.init = function(opt) {
        extend(options, opt);
        options.moduleMappings.chondric = path.resolve(__dirname, "../es6");

    };

    tools.test = function() {
        console.log("Test function");
    };

    tools.buildVariation = function(variation, env, watch, destFolder, onBuildComplete) {
        console.log(options);
        var debugMode = env != "prod"; //true;
        if (options.debug !== undefined) debugMode = options.debug;
        if (options[env] && options[env].debug !== undefined) debugMode = options[env].debug;
        console.log("Debug: " + debugMode);
        console.log("building " + variation + " for " + env);
        var buildfolder = path.resolve(cwd, options.buildfolder);
        if (!fs.existsSync(buildfolder)) fs.mkdirSync(buildfolder);
        var tempFolder = path.resolve(buildfolder, "temp");
        if (!fs.existsSync(tempFolder)) fs.mkdirSync(tempFolder);
        var envFolder = path.resolve(buildfolder, env);
        if (!fs.existsSync(envFolder)) fs.mkdirSync(envFolder);
        var varFolder = path.resolve(buildfolder, env, variation);
        if (!fs.existsSync(varFolder)) fs.mkdirSync(varFolder);

        if (destFolder) varFolder = path.resolve(cwd, destFolder);

        var hostSettings = {};
        extend(hostSettings, options.hostSettings);
        extend(hostSettings, options[env]);
        fs.writeFileSync(path.resolve(tempFolder, "hostsettings.js"), "module.exports=" + JSON.stringify(hostSettings), "utf-8");

        var moduleMappings = [{
            src: 'hostsettings.js',
            expose: 'build',
            cwd: tempFolder
        }];
        for (var k in options.moduleMappings) {
            moduleMappings.push({
                src: './**/*.html',
                expose: k,
                cwd: options.moduleMappings[k],
            });
            moduleMappings.push({
                src: './**/*.js',
                expose: k,
                cwd: options.moduleMappings[k],
            });
        }

        console.log(moduleMappings);

        var sourceFolder = path.resolve(cwd, options.sourceFolder);
        var libFolder = path.resolve(cwd, options.libFolder);

        es6ify.traceurOverrides = {
            annotations: true,
            types: true,
            memberVariables: true
        };

        var filteredEs6ify = filterTransform(
            function(file) {
                // browserify needs transforms to be global, and compiling es5 modules
                // breaks stuff, so only compile the bits we know are es6
                if (file.indexOf("node_modules") >= 0) {
                    // files under node_modules are only compiled as es6 if they are included in
                    // moduleMappings - i.e. if chondric was loaded with npm install rather than npm link
                    for (var i = 0; i < moduleMappings.length; i++) {
                        var pn = moduleMappings[i].cwd;
                        if (file.indexOf(pn) === 0 && file.lastIndexOf("node_modules") < pn.length) {
                            return path.extname(file) === '.js';
                        }
                    }
                    return false;
                }
                return path.extname(file) === '.js';

            },
            es6ify
        );

        var globalShim = filterTransform(
            function(file) {
                return path.extname(file) === ".js";
            },
            require('browserify-global-shim').configure(options.globals)
        );

        function buildClientJs(onComplete) {
            var jsBuildError = null;

            var b = browserify({
                    debug: debugMode,
                    extensions: [".txt", ".html"],
                    //paths: [path.resolve(__dirname,"../es6")]
                })
                .add(es6ify.runtime, {
                    entry: true
                })
                .plugin(remapify, moduleMappings)
                .transform(stringify({
                    extensions: ['.txt', '.html'],
                    minify: true
                }), {
                    global: true
                });

            for (var i = 0; i < options.customBrowserifyTransforms.length; i++) {
                b = b.transform(options.customBrowserifyTransforms[i]());
            }

            b = b.transform(filteredEs6ify, {
                global: true
            });

            b = b.transform(globalShim, {
                global: true
            });

            if (!debugMode) {
                // remove console.log calls
                b = b.transform({
                    global: true
                }, stripify);
            }
            if (debugMode && options.browserTests) {
                // inject tests
                b.require(require.resolve(path.resolve(cwd, options.browserTests)), {
                    expose: "test",
                    entry: true
                });
            }
            b.require(require.resolve(path.resolve(sourceFolder, variation + ".js")), {
                entry: true
            });

            function reportError(title, msg, source, detail) {
                var errorReporter = fs.readFileSync(path.resolve(__dirname, "./reporterror.js"), "utf-8");

                errorReporter = errorReporter.replace("\"[TITLE]\"", JSON.stringify(title || "Error"));
                errorReporter = errorReporter.replace("\"[MESSAGE]\"", JSON.stringify(msg || "Something went wrong"));
                errorReporter = errorReporter.replace("\"[SOURCE]\"", JSON.stringify(source || ""));
                errorReporter = errorReporter.replace("\"[DETAIL]\"", JSON.stringify(detail || ""));
                return errorReporter;
            }

            b = b.bundle()
                .once('error', function(err) {
                    console.log("Browserify error");
                    console.log(err.message);
                    var msg = err.message;
                    var source = "";
                    var detail = "";

                    var m = /(.*):(\d+):(\d+): (.*)/.exec(msg);
                    if (m && m.length >= 5) {
                        msg = m[4];
                        var fn = m[1];
                        var errorLine = parseInt(m[2]);
                        source = m[1] + ":" + m[2] + ":" + m[3];
                        detail = "";

                        var sc = fs.readFileSync(fn, "utf-8").split("\n");
                        for (var i = errorLine - 4; i < errorLine + 3; i++) {
                            var l = sc[i];
                            if (l === undefined) continue;
                            detail += l + "\n";
                        }

                    }

                    jsBuildError = {
                        message: msg,
                        source: source,
                        detail: detail
                    };
                    var errorReporter = reportError("BuildError", msg, source, detail);
                    fs.writeFileSync(path.resolve(varFolder, "app.js"), errorReporter);
                    if (onComplete) onComplete(jsBuildError);
                    this.emit("end");
                });
            b.on('error', function(err) {
                // Ignore any errors after the first so onComplete is only called once
            });
            b.on("end", function() {
                if (!jsBuildError) {
                    console.log("Done browserify");
                    if (onComplete) onComplete();
                }
            });

            var appFile = path.resolve(varFolder, "app.js");
            var appFileTemp = path.resolve(varFolder, "app (building).js");
            var appFileEs3 = path.resolve(varFolder, "app-es3.js");

            // For use with <script>$.getScript(window.atob ? "app.js" : "app-es3.js");</script>
            fs.writeFileSync(appFileEs3, reportError("App error", "This app is designed for use in modern browsers."));

            if (debugMode) {
                fs.writeFileSync(appFile, reportError("Build Incomplete", "Browserify build in progress - try again in a few seconds."));

                b.on("end", function() {
                    if (!jsBuildError && fs.existsSync(appFileTemp)) {
                        if (fs.existsSync(appFile)) fs.unlinkSync(appFile);
                        fs.renameSync(appFileTemp, appFile);
                    }
                });

                b = b.pipe(fs.createWriteStream(appFileTemp));
            } else {
                b = b
                    .pipe(source('app.js')) // gives streaming vinyl file object
                    .pipe(buffer()) // <----- convert from streaming to buffered vinyl file object
                    .pipe(uglify({
                        mangle: true,
                        compress: false
                    }))
                    .pipe(gulp.dest(varFolder));
            }

        }

        function copyHtml() {
            gulp.src(sourceFolder + '/*.html')
                .pipe(gulp.dest(varFolder));
        }

        function copyLib() {
            gulp.src(libFolder + '/*.js')
                .pipe(gulp.dest(varFolder + "/lib"));
        }

        function copyImages() {
            var flatten = require('gulp-flatten');
            console.log("Copying images");
            var globs = [];
            for (var i = 0; i < options.imageFolders.length; i++) {
                var imgf = options.imageFolders[i];
                globs.push(imgf + "/**");
            }

            console.log(globs);
            gulp.src(globs)
                .pipe(flatten())
                .pipe(gulp.dest(varFolder + "/images"));

        }

        //        function copyImages() {
        //            gulp.src(__dirname + '/apphtml/images/**/*')
        //                .pipe(gulp.dest(options.buildfolder + "/" + env + "/" + variation + "/images"))
        //                .on("end", function() {
        //                    gulp.src(process.cwd() + "/images/**/*")
        //                        .pipe(gulp.dest(options.buildfolder + "/" + env + "/" + variation + "/images"));
        //                });
        //        }

        function buildCssFile(inputFile, outputFile, fileBuilt) {
            var params = (debugMode ? ["--style", "nested"] : ["--style", "compressed"])
                .concat(["-I", ".", inputFile, varFolder + "/" + outputFile]);
            // using spawn because libsass sourcemaps are buggy

            var spawn = require("child_process").spawn;
            var p = spawn(sassPath, params, {
                cwd: cwd
            });
            p.stdout.on('data', function(data) {
                console.log("" + data);
            });

            p.stderr.on('data', function(data) {
                console.log("" + data);
            });
            p.on("close", function(code) {
                console.log("Done sass build of " + inputFile + " with code " + code);
                if (fileBuilt) fileBuilt(code === 0 ? null : ("SASS Error " + code));
            });

        }

        function buildCss(onCssBuilt) {
            var cssEntryPoint = path.resolve(cwd, options.cssEntryPoint);

            buildCssFile(cssEntryPoint, "app.css", function(err) {
                if (err) return onCssBuilt && onCssBuilt();

                var variations = [];
                for (var k in options.cssVariations) {
                    variations.push({
                        key: k,
                        settings: options.cssVariations[k]
                    });
                }

                async.eachSeries(variations, function(v, next) {
                    var iesrc = v.settings + '\n@import "' + (path.relative(tempFolder, cssEntryPoint).replace(/\\/ig, "/")) + '";';
                    var ieCssFile = path.resolve(tempFolder, "index-" + v.key + ".scss");
                    fs.writeFileSync(ieCssFile, iesrc);
                    buildCssFile(ieCssFile, "app-" + v.key + ".css", next);
                }, onCssBuilt);

            });

        }

        buildClientJs(function(err) {
            if (err) return onBuildComplete && onBuildComplete(err);
            buildCss(function(err) {
                if (err) return onBuildComplete && onBuildComplete(err);
                copyHtml();
                copyImages();
                copyLib();
                if (options.afterBrowserify) options.afterBrowserify(varFolder, env, variation);
                console.log("Build completed successfully");
                return onBuildComplete && onBuildComplete(err);
            });
        });

        if (watch) {

            var paths = [
                    path.resolve(__dirname, "../es6"),
                    sourceFolder
                ]
                .concat(options.additionalWatchPaths);

            // watch the css folder if it isn't already watched as part of the source folder
            var cssFolder = path.dirname(path.resolve(cwd, options.cssEntryPoint));
            if (cssFolder.indexOf(sourceFolder) !== 0) paths.push(cssFolder);

            // watch image folders
            for (var i = 0; i < options.imageFolders.length; i++) {
                var imgf = options.imageFolders[i];
                if (imgf.indexOf(sourceFolder) !== 0) paths.push(imgf);
            }

            // watch tests
            if (options.browserTests) {
                paths.push(path.dirname(path.resolve(options.browserTests)));
            }

            var watcher = chokidar.watch(paths, {
                ignored: /[\/\\]\./,
                persistent: true,
                ignoreInitial: true
            });

            watcher.on("all", function(type, file) {
                console.log(type + " event for " + file);
                var ext = path.extname(file);
                if (ext == ".scss") {
                    console.log("CSS needs rebuild");
                    buildCss();
                } else if (ext == ".js" || ext == ".html") {
                    console.log("Browserify package needs rebuild");
                    buildClientJs(function(err) {
                        if (!err && options.afterBrowserify) options.afterBrowserify(varFolder, env, variation);
                    });
                } else if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif") {
                    console.log("Updating images");
                    copyImages();

                }
                // if the changed file is .js or .html, need to run browserify
                // copy html only copies a single file, so maybe just include that in the browserify process

                // src/images just needs to be copied if anything changes, and it can't contain anything used by browserify

            });

        }
    };

    tools.buildTask = function() {
        var args = process.argv.slice(3);
        if (args.length != 2 || args[0].indexOf("--") !== 0 || args[1].indexOf("--") !== 0) {
            console.log("Invalid arguments for build task");
            console.log("Usage: gulp build --web --dev");
            return;
        }
        var variation = args[0].substr(2);
        var env = args[1].substr(2);

        tools.buildVariation(variation, env);
    };

})();
<|endoftext|>