<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 inherits = require('util').inherits;
var states = require('./states');
var EventEmitter = require('./lib/event_emitter');
var StateMachine = require('./state_machine');
var errors = require('./errors');

// Each circuit uses the circuits collection as the "nextHandler" for
// "shouldRequest" to consult.  Peers use this hook to weight peers both by
// healthy and other factors, but the circuit only needs to know about health
// before forwarding.

function AlwaysShouldRequestHandler() { }

AlwaysShouldRequestHandler.prototype.shouldRequest = function shouldRequest() {
    return true;
};

var alwaysShouldRequestHandler = new AlwaysShouldRequestHandler();

function CircuitStateChange(circuit, oldState, state) {
    var self = this;
    self.circuit = circuit;
    self.oldState = oldState;
    self.state = state;
}

//  circuit = circuits                        : Circuits
//      .circuitsByServiceName[serviceName]   : ServiceCircuits
//      .circuitsByCallerName[callerName]     : EndpointCircuits
//      .circuitsByEndpointName[endpointName]

function EndpointCircuits(root) {
    var self = this;
    self.root = root;
    self.circuitsByEndpointName = {};
}

EndpointCircuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuit = self.circuitsByEndpointName['$' + endpointName];
    if (!circuit) {
        circuit = new Circuit(callerName, serviceName, endpointName);
        circuit.shouldRequestOptions = self.root.shouldRequestOptions;
        var stateOptions = self.root.stateOptions;
        circuit.stateOptions = new states.StateOptions(circuit, {
            nextHandler: stateOptions.nextHandler,
            timers: stateOptions.timers,
            random: stateOptions.random,
            period: stateOptions.period,
            maxErrorRate: stateOptions.maxErrorRate,
            minRequests: stateOptions.minRequests,
            probation: stateOptions.probation
        });
        circuit.stateChangedEvent.on(function circuitStateChanged(states) {
            self.root.emitCircuitStateChange(circuit, states);
        });
        circuit.setState(states.HealthyState);
        self.circuitsByEndpointName['$' + endpointName] = circuit;
    }
    return circuit;
};

EndpointCircuits.prototype.collectCircuitTuples = function collectCircuitTuples(tuples) {
    var self = this;
    var endpointNames = Object.keys(self.circuitsByEndpointName);
    for (var index = 0; index < endpointNames.length; index++) {
        var endpointName = endpointNames[index];
        var circuit = self.circuitsByEndpointName[endpointName];
        tuples.push([circuit.callerName, circuit.serviceName, circuit.endpointName]);
    }
};

function ServiceCircuits(root) {
    var self = this;
    self.root = root;
    self.circuitsByCallerName = {};
}

ServiceCircuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuits = self.circuitsByCallerName['$' + callerName];
    if (!circuits) {
        circuits = new EndpointCircuits(self.root);
        self.circuitsByCallerName['$' + callerName] = circuits;
    }
    return circuits.getCircuit(callerName, serviceName, endpointName);
};

ServiceCircuits.prototype.collectCircuitTuples = function collectCircuitTuples(tuples) {
    var self = this;
    var callerNames = Object.keys(self.circuitsByCallerName);
    for (var index = 0; index < callerNames.length; index++) {
        var callerName = callerNames[index];
        var circuit = self.circuitsByCallerName[callerName];
        circuit.collectCircuitTuples(tuples);
    }
};

function Circuits(options) {
    var self = this;
    EventEmitter.call(self);
    self.circuitStateChangeEvent = self.defineEvent('circuitStateChange');
    self.circuitsByServiceName = {};
    self.stateOptions = {
        nextHandler: alwaysShouldRequestHandler,
        timers: options.timers,
        random: options.random,
        period: options.period,
        maxErrorRate: options.maxErrorRate,
        minRequests: options.minRequests,
        probation: options.probation
    };
    self.shouldRequestOptions = {};
    self.egressNodes = options.egressNodes;
}

inherits(Circuits, EventEmitter);

Circuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuits = self.circuitsByServiceName['$' + serviceName];
    if (!circuits) {
        circuits = new ServiceCircuits(self);
        self.circuitsByServiceName['$' + serviceName] = circuits;
    }
    return circuits.getCircuit(callerName, serviceName, endpointName);
};

Circuits.prototype.getCircuitTuples = function getCircuitTuples() {
    var self = this;
    var tuples = [];
    var serviceNames = Object.keys(self.circuitsByServiceName);
    for (var index = 0; index < serviceNames.length; index++) {
        var serviceName = serviceNames[index];
        self.circuitsByServiceName[serviceName].collectCircuitTuples(tuples);
    }
    return tuples;
};

Circuits.prototype.handleRequest = function handleRequest(req, buildRes, nextHandler) {
    var self = this;
    // Default the caller name.
    // All callers that fail to specifiy a cn share a circuit for each sn:en
    // and fail together.
    var callerName = req.headers.cn || 'no-cn';
    var serviceName = req.serviceName;
    if (!serviceName) {
        return buildRes().sendError('BadRequest', 'All requests must have a service name');
    }
    return req.withArg1(function withArg1() {
        var circuit = self.getCircuit(callerName, serviceName, String(req.arg1));
        return circuit.handleRequest(req, buildRes, nextHandler);
    });
};

// Called upon membership change to collect services that the corresponding
// exit node is no longer responsible for.
Circuits.prototype.updateServices = function updateServices() {
    var self = this;
    var serviceNames = Object.keys(self.circuitsByServiceName);
    for (var index = 0; index < serviceNames.length; index++) {
        var serviceName = serviceNames[index];
        if (!self.egressNodes.isExitFor(serviceName)) {
            delete self.circuitsByServiceName[serviceName];
        }
    }
};

Circuits.prototype.emitCircuitStateChange = function (circuit, states) {
    var self = this;
    self.circuitStateChangeEvent.emit(
        self.root,
        new CircuitStateChange(circuit, states[0], states[1])
    );
};

function Circuit(callerName, serviceName, endpointName) {
    var self = this;
    EventEmitter.call(self);
    StateMachine.call(self);
    self.stateChangedEvent = self.defineEvent('stateChanged');
    self.callerName = callerName || 'no-cn';
    self.serviceName = serviceName;
    self.endpointName = endpointName;
    self.shouldRequestOptions = null;
    self.stateOptions = null;
}

inherits(Circuit, EventEmitter);

Circuit.prototype.setState = StateMachine.prototype.setState;

Circuit.prototype.handleRequest = function handleRequest(req, buildRes, nextHandler) {
    var self = this;
    if (self.state.shouldRequest(req, self.shouldRequestOptions)) {
        return self.monitorRequest(req, buildRes, nextHandler);
    } else {
        return buildRes().sendError('Declined', 'Service is not healthy');
    }
};

Circuit.prototype.monitorRequest = function monitorRequest(req, buildRes, nextHandler) {
    var self = this;

    self.state.onRequest(req);

    req.errorEvent.on(onError);

    function monitorBuildRes(options) {
        var res = buildRes(options);
        self.monitorResponse(res);
        return res;
    }

    function onError(err) {
        self.state.onRequestError(err);
    }

    return nextHandler.handleRequest(req, monitorBuildRes);
};

Circuit.prototype.monitorResponse = function monitorResponse(res) {
    var self = this;

    res.errorEvent.on(onError);
    res.finishEvent.on(onFinish);

    function onError(err) {
        self.state.onRequestError(err);
    }

    function onFinish() {
        // TODO distingiush res.ok?
        // note that incoming requests do not have responseEvent and clear out
        // their response upon finish.
        if (errors.isUnhealthy(res.codeString)) {
            self.state.onRequestUnhealthy();
        } else {
            self.state.onRequestHealthy();
        }
    }
};

module.exports = Circuits;
<commit_msg>Circuits: simplify state options construction<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 inherits = require('util').inherits;
var states = require('./states');
var EventEmitter = require('./lib/event_emitter');
var StateMachine = require('./state_machine');
var errors = require('./errors');

// Each circuit uses the circuits collection as the "nextHandler" for
// "shouldRequest" to consult.  Peers use this hook to weight peers both by
// healthy and other factors, but the circuit only needs to know about health
// before forwarding.

function AlwaysShouldRequestHandler() { }

AlwaysShouldRequestHandler.prototype.shouldRequest = function shouldRequest() {
    return true;
};

var alwaysShouldRequestHandler = new AlwaysShouldRequestHandler();

function CircuitStateChange(circuit, oldState, state) {
    var self = this;
    self.circuit = circuit;
    self.oldState = oldState;
    self.state = state;
}

//  circuit = circuits                        : Circuits
//      .circuitsByServiceName[serviceName]   : ServiceCircuits
//      .circuitsByCallerName[callerName]     : EndpointCircuits
//      .circuitsByEndpointName[endpointName]

function EndpointCircuits(root) {
    var self = this;
    self.root = root;
    self.circuitsByEndpointName = {};
}

EndpointCircuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuit = self.circuitsByEndpointName['$' + endpointName];
    if (!circuit) {
        circuit = new Circuit(callerName, serviceName, endpointName);
        circuit.shouldRequestOptions = self.root.shouldRequestOptions;
        circuit.stateOptions = new states.StateOptions(circuit, self.root.stateOptions);
        circuit.stateChangedEvent.on(function circuitStateChanged(states) {
            self.root.emitCircuitStateChange(circuit, states);
        });
        circuit.setState(states.HealthyState);
        self.circuitsByEndpointName['$' + endpointName] = circuit;
    }
    return circuit;
};

EndpointCircuits.prototype.collectCircuitTuples = function collectCircuitTuples(tuples) {
    var self = this;
    var endpointNames = Object.keys(self.circuitsByEndpointName);
    for (var index = 0; index < endpointNames.length; index++) {
        var endpointName = endpointNames[index];
        var circuit = self.circuitsByEndpointName[endpointName];
        tuples.push([circuit.callerName, circuit.serviceName, circuit.endpointName]);
    }
};

function ServiceCircuits(root) {
    var self = this;
    self.root = root;
    self.circuitsByCallerName = {};
}

ServiceCircuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuits = self.circuitsByCallerName['$' + callerName];
    if (!circuits) {
        circuits = new EndpointCircuits(self.root);
        self.circuitsByCallerName['$' + callerName] = circuits;
    }
    return circuits.getCircuit(callerName, serviceName, endpointName);
};

ServiceCircuits.prototype.collectCircuitTuples = function collectCircuitTuples(tuples) {
    var self = this;
    var callerNames = Object.keys(self.circuitsByCallerName);
    for (var index = 0; index < callerNames.length; index++) {
        var callerName = callerNames[index];
        var circuit = self.circuitsByCallerName[callerName];
        circuit.collectCircuitTuples(tuples);
    }
};

function Circuits(options) {
    var self = this;
    EventEmitter.call(self);
    self.circuitStateChangeEvent = self.defineEvent('circuitStateChange');
    self.circuitsByServiceName = {};

    self.stateOptions = new states.StateOptions(null, {
        timers: options.timers,
        random: options.random,
        nextHandler: alwaysShouldRequestHandler,
        period: options.period,
        maxErrorRate: options.maxErrorRate,
        minRequests: options.minRequests,
        probation: options.probation
    });
    self.shouldRequestOptions = {};
    self.egressNodes = options.egressNodes;
}

inherits(Circuits, EventEmitter);

Circuits.prototype.getCircuit = function getCircuit(callerName, serviceName, endpointName) {
    var self = this;
    var circuits = self.circuitsByServiceName['$' + serviceName];
    if (!circuits) {
        circuits = new ServiceCircuits(self);
        self.circuitsByServiceName['$' + serviceName] = circuits;
    }
    return circuits.getCircuit(callerName, serviceName, endpointName);
};

Circuits.prototype.getCircuitTuples = function getCircuitTuples() {
    var self = this;
    var tuples = [];
    var serviceNames = Object.keys(self.circuitsByServiceName);
    for (var index = 0; index < serviceNames.length; index++) {
        var serviceName = serviceNames[index];
        self.circuitsByServiceName[serviceName].collectCircuitTuples(tuples);
    }
    return tuples;
};

Circuits.prototype.handleRequest = function handleRequest(req, buildRes, nextHandler) {
    var self = this;
    // Default the caller name.
    // All callers that fail to specifiy a cn share a circuit for each sn:en
    // and fail together.
    var callerName = req.headers.cn || 'no-cn';
    var serviceName = req.serviceName;
    if (!serviceName) {
        return buildRes().sendError('BadRequest', 'All requests must have a service name');
    }
    return req.withArg1(function withArg1() {
        var circuit = self.getCircuit(callerName, serviceName, String(req.arg1));
        return circuit.handleRequest(req, buildRes, nextHandler);
    });
};

// Called upon membership change to collect services that the corresponding
// exit node is no longer responsible for.
Circuits.prototype.updateServices = function updateServices() {
    var self = this;
    var serviceNames = Object.keys(self.circuitsByServiceName);
    for (var index = 0; index < serviceNames.length; index++) {
        var serviceName = serviceNames[index];
        if (!self.egressNodes.isExitFor(serviceName)) {
            delete self.circuitsByServiceName[serviceName];
        }
    }
};

Circuits.prototype.emitCircuitStateChange = function (circuit, states) {
    var self = this;
    self.circuitStateChangeEvent.emit(
        self.root,
        new CircuitStateChange(circuit, states[0], states[1])
    );
};

function Circuit(callerName, serviceName, endpointName) {
    var self = this;
    EventEmitter.call(self);
    StateMachine.call(self);
    self.stateChangedEvent = self.defineEvent('stateChanged');
    self.callerName = callerName || 'no-cn';
    self.serviceName = serviceName;
    self.endpointName = endpointName;
    self.shouldRequestOptions = null;
    self.stateOptions = null;
}

inherits(Circuit, EventEmitter);

Circuit.prototype.setState = StateMachine.prototype.setState;

Circuit.prototype.handleRequest = function handleRequest(req, buildRes, nextHandler) {
    var self = this;
    if (self.state.shouldRequest(req, self.shouldRequestOptions)) {
        return self.monitorRequest(req, buildRes, nextHandler);
    } else {
        return buildRes().sendError('Declined', 'Service is not healthy');
    }
};

Circuit.prototype.monitorRequest = function monitorRequest(req, buildRes, nextHandler) {
    var self = this;

    self.state.onRequest(req);

    req.errorEvent.on(onError);

    function monitorBuildRes(options) {
        var res = buildRes(options);
        self.monitorResponse(res);
        return res;
    }

    function onError(err) {
        self.state.onRequestError(err);
    }

    return nextHandler.handleRequest(req, monitorBuildRes);
};

Circuit.prototype.monitorResponse = function monitorResponse(res) {
    var self = this;

    res.errorEvent.on(onError);
    res.finishEvent.on(onFinish);

    function onError(err) {
        self.state.onRequestError(err);
    }

    function onFinish() {
        // TODO distingiush res.ok?
        // note that incoming requests do not have responseEvent and clear out
        // their response upon finish.
        if (errors.isUnhealthy(res.codeString)) {
            self.state.onRequestUnhealthy();
        } else {
            self.state.onRequestHealthy();
        }
    }
};

module.exports = Circuits;
<|endoftext|>


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

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';

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

import Util from '../_vendors/Util';

class ColGroup extends Component {

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

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    getColStyle = column => {

        const result = {};

        if (column.width != null) {
            result.width = column.width;
        }
        if (column.minWidth != null) {
            result.minWidth = column.minWidth;
        }

        return isEmpty(result) ? null : result;

    };

    render() {

        const {columns} = this.props;

        return columns ?
            <colgroup>
                {
                    columns.map(({column, span}, index) => column ?
                        <col key={index}
                             style={this.getColStyle(column)}
                             span={span && span > 1 ? span : null}/>
                        :
                        null
                    )
                }
            </colgroup>
            :
            null;

    }
}

ColGroup.propTypes = {

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

        /**
         * fixed position of column ( true / 'left' / 'right' )
         */
        fixed: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(Util.enumerateValue(HorizontalAlign))]),

        /**
         * width of column
         */
        width: PropTypes.number,

        /**
         * minimum width of column
         */
        minWidth: PropTypes.number,

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

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

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

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

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

        /**
         * column span of table header
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

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

        /**
         * column span of table body
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

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

        /**
         * column span of table foot
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

    })).isRequired

};

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

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';

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

import Util from '../_vendors/Util';

class ColGroup extends Component {

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

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    getColStyle = column => {

        const result = {};

        if (column.width != null) {
            result.width = column.width;
        }
        if (column.minWidth != null) {
            result.minWidth = column.minWidth;
        }

        return isEmpty(result) ? null : result;

    };

    render() {

        const {columns} = this.props;

        return columns ?
            <colgroup>
                {
                    columns.map(({column, span}, index) => column ?
                        <col key={index}
                             style={this.getColStyle(column)}
                             span={span && span > 1 ? span : null}/>
                        :
                        null
                    )
                }
            </colgroup>
            :
            null;

    }
}

ColGroup.propTypes = {

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

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

        /**
         * width of column
         */
        width: PropTypes.number,

        /**
         * minimum width of column
         */
        minWidth: PropTypes.number,

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

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

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

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

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

        /**
         * column span of table header
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

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

        /**
         * column span of table body
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

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

        /**
         * column span of table foot
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

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

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

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

    })).isRequired

};

export default ColGroup;
<|endoftext|>


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

import React, {Component} from 'react';
import {findDOMNode} from 'react-dom';
import PropTypes from 'prop-types';
import _ from 'lodash';

import Paper from '../Paper';
import Theme from '../Theme';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import PopupCalculation from '../_vendors/PopupCalculation';

import Position from '../_statics/Position';

export default class MenuBody extends Component {

    static Position = Position;
    static Theme = Theme;
    static propTypes = {

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

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

        /**
         * This is the DOM element that will be used to set the position of the popover.
         */
        triggerEl: PropTypes.object,

        /**
         * If true,the popover is visible.
         */
        visible: PropTypes.bool,

        /**
         * If true,the popover will have a triangle on the top of the DOM element.
         */
        hasTriangle: PropTypes.bool,

        triangle: PropTypes.element,

        /**
         * The popover theme.Can be primary,highlight,success,warning,error.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The popover alignment.The value can be Menu.Position.LEFT or Menu.Position.RIGHT.
         */
        position: PropTypes.oneOf(Util.enumerateValue(Position)),

        /**
         * If true, menu will have animation effects.
         */
        isAnimated: PropTypes.bool,

        shouldPreventContainerScroll: PropTypes.bool,

        /**
         * The depth of Paper component.
         */
        depth: PropTypes.number,

        isTriggerPositionFixed: PropTypes.bool,

        /**
         * The function of menu render.
         */
        onRender: PropTypes.func,

        /**
         * Callback function fired when the popover is requested to be closed.
         */
        onRequestClose: PropTypes.func,

        /**
         * Callback function fired when wrapper wheeled.
         */
        onWheel: PropTypes.func

    };
    static defaultProps = {

        className: '',
        style: null,
        theme: Theme.DEFAULT,

        triggerEl: null,
        visible: false,
        hasTriangle: true,
        triangle:

,
        position: Position.BOTTOM_LEFT,
        isAnimated: true,
        depth: 6,
        shouldPreventContainerScroll: true,
        isTriggerPositionFixed: false

    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.hasMounted = false;
        this.prepareCloseTimeout = null;
        this.requestCloseTimeout = null;

        this.state = {
            visible: false
        };

        this.triggerMouseEnterHandler = ::this.triggerMouseEnterHandler;
        this.triggerMouseLeaveHandler = ::this.triggerMouseLeaveHandler;
        this.resizeHandler = ::this.resizeHandler;
        this.debounceResizeHandle = _.debounce(::this.debounceResizeHandle, 150);
        this.initializeAnimation = ::this.initializeAnimation;
        this.animate = ::this.animate;

    }

    triggerMouseEnterHandler() {
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
    }

    triggerMouseLeaveHandler() {
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
        this.prepareCloseTimeout = setTimeout(() => {
            this.setState({
                visible: false
            }, () => {
                this.requestCloseTimeout && clearTimeout(this.requestCloseTimeout);
                this.requestCloseTimeout = setTimeout(() => {
                    const {onRequestClose} = this.props;
                    this.hasMounted && onRequestClose && onRequestClose();
                }, 250);
            });
        }, 100);
    }

    resizeHandler() {
        this.debounceResizeHandle();
    }

    debounceResizeHandle() {
        this.forceUpdate();
    }

    initializeAnimation(callback) {
        setTimeout(() => {
            this.hasMounted && callback();
        }, 0);
    }

    animate() {
        this.setState({
            visible: true
        });
    }

    componentDidMount() {

        this.hasMounted = true;
        this.menuEl = findDOMNode(this.refs.menu);

        Event.addEvent(this.props.triggerEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.addEvent(this.props.triggerEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.addEvent(this.menuEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.addEvent(this.menuEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.addEvent(window, 'resize', this.resizeHandler);

    }

    componentWillAppear(callback) {
        this.initializeAnimation(callback);
    }

    componentDidAppear() {
        this.animate();
    }

    componentDidUpdate() {
        const {onRender} = this.props,
            {visible} = this.state;
        visible && onRender && onRender(this.menuEl, this.props.triggerEl);
    }

    componentWillUnmount() {

        this.hasMounted = false;
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
        this.requestCloseTimeout && clearTimeout(this.requestCloseTimeout);

        Event.removeEvent(this.props.triggerEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.removeEvent(this.props.triggerEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.removeEvent(this.menuEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.removeEvent(this.menuEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.removeEvent(window, 'resize', this.resizeHandler);

    }

    render() {

        const {

                children,

                className, style, theme, hasTriangle, triangle, position, isAnimated,
                triggerEl, isTriggerPositionFixed,

                // not passing down these props
                visible: v, shouldPreventContainerScroll, onRender, onRequestClose,

                ...restProps

            } = this.props,
            {visible} = this.state,

            menuClassName = (visible ? '' : ' hidden') + (hasTriangle ? ' menu-has-triangle' : '')
                + (theme ? ` theme-${theme}` : '') + (position ? ` menu-position-${position}` : '')
                + (isAnimated ? ' menu-animated' : '') + (className ? ' ' + className : ''),
            menuStyle = {
                ...PopupCalculation.getStyle(triggerEl, this.menuEl, position, isTriggerPositionFixed),
                ...style
            };

        return (
            <Paper {...restProps}
                   ref="menu"
                   className={'menu' + menuClassName}
                   style={menuStyle}
                   onWheel={e => {
                       Event.wheelHandler(e, this.props);
                   }}>

                {
                    hasTriangle ?

                            {triangle}

                        :
                        null
                }

 {
                         Event.wheelHandler(e, this.props);
                     }}>
                    {children}

            </Paper>
        );

    }
};<commit_msg>update MenuBody<commit_after>/**
 * @file MenuBody component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import {findDOMNode} from 'react-dom';
import PropTypes from 'prop-types';
import _ from 'lodash';

import Paper from '../Paper';
import Theme from '../Theme';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import PopupCalculation from '../_vendors/PopupCalculation';

import Position from '../_statics/Position';

class MenuBody extends Component {

    static Position = Position;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.hasMounted = false;
        this.prepareCloseTimeout = null;
        this.requestCloseTimeout = null;

        this.state = {
            visible: false
        };

        this.triggerMouseEnterHandler = ::this.triggerMouseEnterHandler;
        this.triggerMouseLeaveHandler = ::this.triggerMouseLeaveHandler;
        this.resizeHandler = ::this.resizeHandler;
        this.debounceResizeHandle = _.debounce(::this.debounceResizeHandle, 150);
        this.initializeAnimation = ::this.initializeAnimation;
        this.animate = ::this.animate;

    }

    triggerMouseEnterHandler() {
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
    }

    triggerMouseLeaveHandler() {
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
        this.prepareCloseTimeout = setTimeout(() => {
            this.setState({
                visible: false
            }, () => {
                this.requestCloseTimeout && clearTimeout(this.requestCloseTimeout);
                this.requestCloseTimeout = setTimeout(() => {
                    const {onRequestClose} = this.props;
                    this.hasMounted && onRequestClose && onRequestClose();
                }, 250);
            });
        }, 100);
    }

    resizeHandler() {
        this.debounceResizeHandle();
    }

    debounceResizeHandle() {
        this.forceUpdate();
    }

    initializeAnimation(callback) {
        setTimeout(() => {
            this.hasMounted && callback();
        }, 0);
    }

    animate() {
        this.setState({
            visible: true
        });
    }

    componentDidMount() {

        this.hasMounted = true;
        this.menuEl = findDOMNode(this.refs.menu);

        Event.addEvent(this.props.triggerEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.addEvent(this.props.triggerEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.addEvent(this.menuEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.addEvent(this.menuEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.addEvent(window, 'resize', this.resizeHandler);

    }

    componentWillAppear(callback) {
        this.initializeAnimation(callback);
    }

    componentDidAppear() {
        this.animate();
    }

    componentDidUpdate() {
        const {onRender} = this.props,
            {visible} = this.state;
        visible && onRender && onRender(this.menuEl, this.props.triggerEl);
    }

    componentWillUnmount() {

        this.hasMounted = false;
        this.prepareCloseTimeout && clearTimeout(this.prepareCloseTimeout);
        this.requestCloseTimeout && clearTimeout(this.requestCloseTimeout);

        Event.removeEvent(this.props.triggerEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.removeEvent(this.props.triggerEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.removeEvent(this.menuEl, 'mouseenter', this.triggerMouseEnterHandler);
        Event.removeEvent(this.menuEl, 'mouseleave', this.triggerMouseLeaveHandler);
        Event.removeEvent(window, 'resize', this.resizeHandler);

    }

    render() {

        const {

                children,

                className, style, theme, hasTriangle, triangle, position, isAnimated,
                triggerEl, isTriggerPositionFixed,

                // not passing down these props
                visible: v, shouldPreventContainerScroll, onRender, onRequestClose,

                ...restProps

            } = this.props,
            {visible} = this.state,

            menuClassName = (visible ? '' : ' hidden') + (hasTriangle ? ' menu-has-triangle' : '')
                + (theme ? ` theme-${theme}` : '') + (position ? ` menu-position-${position}` : '')
                + (isAnimated ? ' menu-animated' : '') + (className ? ' ' + className : ''),
            menuStyle = {
                ...PopupCalculation.getStyle(triggerEl, this.menuEl, position, isTriggerPositionFixed),
                ...style
            };

        return (
            <Paper {...restProps}
                   ref="menu"
                   className={'menu' + menuClassName}
                   style={menuStyle}
                   onWheel={e => {
                       Event.wheelHandler(e, this.props);
                   }}>

                {
                    hasTriangle ?

                            {triangle}

                        :
                        null
                }

 {
                         Event.wheelHandler(e, this.props);
                     }}>
                    {children}

            </Paper>
        );

    }
};

MenuBody.propTypes = {

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

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

    /**
     * This is the DOM element that will be used to set the position of the popover.
     */
    triggerEl: PropTypes.object,

    /**
     * If true,the popover is visible.
     */
    visible: PropTypes.bool,

    /**
     * If true,the popover will have a triangle on the top of the DOM element.
     */
    hasTriangle: PropTypes.bool,

    triangle: PropTypes.element,

    /**
     * The popover theme.Can be primary,highlight,success,warning,error.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The popover alignment.The value can be Menu.Position.LEFT or Menu.Position.RIGHT.
     */
    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * If true, menu will have animation effects.
     */
    isAnimated: PropTypes.bool,

    shouldPreventContainerScroll: PropTypes.bool,

    /**
     * The depth of Paper component.
     */
    depth: PropTypes.number,

    isTriggerPositionFixed: PropTypes.bool,

    /**
     * The function of menu render.
     */
    onRender: PropTypes.func,

    /**
     * Callback function fired when the popover is requested to be closed.
     */
    onRequestClose: PropTypes.func,

    /**
     * Callback function fired when wrapper wheeled.
     */
    onWheel: PropTypes.func

};

MenuBody.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    triggerEl: null,
    visible: false,
    hasTriangle: true,
    triangle:

,
    position: Position.BOTTOM_LEFT,
    isAnimated: true,
    depth: 6,
    shouldPreventContainerScroll: true,
    isTriggerPositionFixed: false

};

export default MenuBody;<|endoftext|>


<commit_before>angular.module('BaseClass', [])
    .factory('BaseClass', function () {

        'use strict';

        var findObjectOfProperty = function (start, propName) {
            while (true) {
                if (!start) {
                    throw Error('Could not find property "' + propName + '"');
                }

                if (start.hasOwnProperty(propName)) {
                    return start;
                }

                start = Object.getPrototypeOf(start);
            }
        };

        // BaseClass constructor
        var BaseClass = function (attributes) {
            if (!angular.isObject(attributes)) {
                throw Error('arguments provided to constructor must be a key/value pair object!');
            }

            angular.extend(this, attributes);
        };

        BaseClass.extend = function (properties) {

            var Class = this,
                SubClass;

            if (angular.isObject(properties) && properties.hasOwnProperty('constructor')) {
                SubClass = properties.constructor;
            } else {
                SubClass = function () {
                    return Class.apply(this, arguments);
                }
            }

            SubClass.extend = Class.extend;

            // Creates new Object based on Class prototype.
            SubClass.prototype = Object.create(Class.prototype, {
                constructor: { // Sets correct constructor on a SubClass prototype.
                    writable: true,
                    value: SubClass
                },
                _super: { // In case we need to access Class prototype from within a SubClass prototype.
                    value: function (method, args) {
                        var __super, previousSuper, start, superObject, returnValue;

                        __super = '__super__' + method;

                        previousSuper = this[__super];

                        start = Object.getPrototypeOf(
                            previousSuper ? previousSuper : findObjectOfProperty(this, method) // where is the current method?
                        );

                        superObject = findObjectOfProperty(start, method);

                        this[__super] = superObject;

                        returnValue = superObject[method].apply(this, args);

                        if (previousSuper) {
                            this[__super] = previousSuper;
                        } else {
                            delete this[__super];
                        }

                        return returnValue;
                    }
                }
            });

            angular.extend(SubClass.prototype, properties); // Extends SubClass prototype with supplied properties.

            if (Array.isArray(properties.mixins)) { // Add any mixin methods to SubClass prototype.

                properties.mixins.forEach(function (mixin) {
                    for (var prop in mixin) {
                        if (angular.isFunction(mixin[prop]) && angular.isUndefined(SubClass.prototype[prop])) {
                            SubClass.prototype[prop] = mixin[prop];
                        }
                    }
                });
            }

            return SubClass;
        };

        return BaseClass;
    });
<commit_msg>Removed some empty lines<commit_after>angular.module('BaseClass', [])
    .factory('BaseClass', function () {
        'use strict';

        var findObjectOfProperty = function (start, propName) {
            while (true) {
                if (!start) {
                    throw Error('Could not find property "' + propName + '"');
                }

                if (start.hasOwnProperty(propName)) {
                    return start;
                }

                start = Object.getPrototypeOf(start);
            }
        };

        // BaseClass constructor
        var BaseClass = function (attributes) {
            if (!angular.isObject(attributes)) {
                throw Error('arguments provided to constructor must be a key/value pair object!');
            }

            angular.extend(this, attributes);
        };

        BaseClass.extend = function (properties) {
            var Class = this,
                SubClass;

            if (angular.isObject(properties) && properties.hasOwnProperty('constructor')) {
                SubClass = properties.constructor;
            } else {
                SubClass = function () {
                    return Class.apply(this, arguments);
                }
            }

            SubClass.extend = Class.extend;

            // Creates new Object based on Class prototype.
            SubClass.prototype = Object.create(Class.prototype, {
                constructor: { // Sets correct constructor on a SubClass prototype.
                    writable: true,
                    value: SubClass
                },
                _super: { // In case we need to access Class prototype from within a SubClass prototype.
                    value: function (method, args) {
                        var __super, previousSuper, start, superObject, returnValue;

                        __super = '__super__' + method;

                        previousSuper = this[__super];

                        start = Object.getPrototypeOf(
                            previousSuper ? previousSuper : findObjectOfProperty(this, method) // where is the current method?
                        );

                        superObject = findObjectOfProperty(start, method);

                        this[__super] = superObject;

                        returnValue = superObject[method].apply(this, args);

                        if (previousSuper) {
                            this[__super] = previousSuper;
                        } else {
                            delete this[__super];
                        }

                        return returnValue;
                    }
                }
            });

            angular.extend(SubClass.prototype, properties); // Extends SubClass prototype with supplied properties.

            if (Array.isArray(properties.mixins)) { // Add any mixin methods to SubClass prototype.
                properties.mixins.forEach(function (mixin) {
                    for (var prop in mixin) {
                        if (angular.isFunction(mixin[prop]) && angular.isUndefined(SubClass.prototype[prop])) {
                            SubClass.prototype[prop] = mixin[prop];
                        }
                    }
                });
            }

            return SubClass;
        };

        return BaseClass;
    });
<|endoftext|>


<commit_before>/**
 * @ngdoc object
 * @name anol.layer.Feature
 *
 * @param {Object} options AnOl Layer options
 * @param {Object} options.olLayer Options for ol.layer.Vector
 * @param {Object} options.olLayer.source Options for ol.source.Vector
 *
 * @description
 * Inherits from {@link anol.layer.Layer anol.layer.Layer}.
 */
 anol.layer.Feature = function(_options) {
    if(_options === false) {
        anol.layer.Layer.call(this, _options);
        return;
    }
    var self = this;
    var defaults = {};
    var options = $.extend({}, defaults, _options );

    this.hasStyleFunction = angular.isFunction(options.olLayer.style);

    this.style = options.style;
    this.minResolution = (options.style || {}).minResolution;
    this.maxResolution = (options.style || {}).maxResolution;
    this.hasPropertyLabel = (options.style || {}).propertyLabel !== undefined;

    this.externalGraphicPrefix = options.externalGraphicPrefix;
    this.hasPropertyLabel = false;

    this.isVector = true;
    this.loaded = true;
    this.saveable = options.saveable || false;
    this.editable = options.editable || false;

    anol.layer.Layer.call(this, options);
};
anol.layer.Feature.prototype = new anol.layer.Layer(false);
$.extend(anol.layer.Feature.prototype, {
    CLASS_NAME: 'anol.layer.Feature',
    OL_LAYER_CLASS: ol.layer.Vector,
    OL_SOURCE_CLASS: ol.source.Vector,
    DEFAULT_FONT_FACE: 'Helvetica',
    DEFAULT_FONT_SIZE: '10px',
    DEFAULT_FONT_WEIGHT: 'normal',
    setOlLayer: function(olLayer) {
        var self = this;
        // if the layer has an own style function we don't create an style object
        if(!this.hasStyleFunction) {
            var defaultStyle = angular.isFunction(olLayer.getStyle()) ? olLayer.getStyle()()[0] : olLayer.getStyle();

            if(this.style !== undefined) {
                var createImageStyleFunction = this.style.externalGraphic !== undefined ? this.createIconStyle : this.createCircleStyle;

                this.defaultStyle = new ol.style.Style({
                    image: createImageStyleFunction.call(this, this.style, defaultStyle.getImage()),
                    fill: this.createFillStyle(this.style, defaultStyle.getFill()),
                    stroke: this.createStrokeStyle(this.style, defaultStyle.getStroke()),
                    text: this.createTextStyle(this.style, defaultStyle.getText())
                });
            } else {
                this.defaultStyle = defaultStyle;
            }

            olLayer.setStyle(function(feature, resolution) {
                return [self.createStyle(feature, resolution)];
            });
        }

        anol.layer.Layer.prototype.setOlLayer.call(this, olLayer);
    },
    extent: function() {
        var extent = this.olLayer.getSource().getExtent();
        if(ol.extent.isEmpty(extent)) {
            return false;
        }
        return extent;
    },
    isCombinable: function(other) {
        var combinable = anol.layer.Layer.prototype.isCombinable.call(this, other);
        return false;
    },
    createStyle: function(feature, resolution) {
        var defaultStyle = angular.isFunction(this.defaultStyle) ?
            this.defaultStyle(feature, resolution)[0] : this.defaultStyle;
        if(feature === undefined) {
            return defaultStyle;
        }
        var geometryType = feature.getGeometry().getType();
        var featureStyle = feature.get('style') || {};
        if(
            angular.equals(featureStyle, {}) &&
            !this.hasPropertyLabel &&
            this.minResolution === undefined &&
            this.maxResolution === undefined
        ) {
            return defaultStyle;
        }

        var minResolution = featureStyle.minResolution || this.minResolution;
        if(angular.isString(minResolution)) {
            minResolution = parseFloat(minResolution);
        }
        var maxResolution = featureStyle.maxResolution || this.maxResolution;
        if(angular.isString(maxResolution)) {
            maxResolution = parseFloat((maxResolution));
        }
        if(
            (angular.isDefined(minResolution) && minResolution > resolution) ||
            (angular.isDefined(maxResolution) && maxResolution < resolution)
        ) {
            return new ol.style.Style();
        }

        var styleOptions = {};
        if(geometryType === 'Point') {
            styleOptions.image = this.createImageStyle(featureStyle, defaultStyle.getImage());
        } else {
            // line features ignores fill style
            styleOptions.fill = this.createFillStyle(featureStyle, defaultStyle.getFill());
            styleOptions.stroke = this.createStrokeStyle(featureStyle, defaultStyle.getStroke());
        }
        styleOptions.text = this.createTextStyle(featureStyle, defaultStyle.getText(), feature);
        return new ol.style.Style(styleOptions);
    },
    createImageStyle: function(style, defaultImageStyle) {
        var radius = style.radius;
        var externalGraphic = style.externalGraphic;

        var isCircle = radius !== undefined;
        var isIcon = externalGraphic !== undefined;
        var isDefaultCircle = defaultImageStyle instanceof ol.style.Circle;
        var isDefaultIcon = defaultImageStyle instanceof ol.style.Icon;

        if (isIcon || (!isCircle && isDefaultIcon)) {
            return this.createIconStyle(style, defaultImageStyle);
        } else if(isCircle || (!isIcon && isDefaultCircle)) {
            return this.createCircleStyle(style, defaultImageStyle);
        }
        return defaultImageStyle;
    },
    createCircleStyle: function(style, defaultCircleStyle) {
        var defaultStrokeStyle = new ol.style.Stroke();
        var defaultFillStyle = new ol.style.Fill();
        var radius;
        if(defaultCircleStyle instanceof ol.style.Circle) {
            defaultStrokeStyle = defaultCircleStyle.getStroke();
            defaultFillStyle = defaultCircleStyle.getFill();
            radius = defaultCircleStyle.getRadius();
        }

        var _radius = style.radius;
        if(_radius !== undefined) {
            radius = parseFloat(_radius);
        }
        return new ol.style.Circle({
            radius: radius,
            stroke: this.createStrokeStyle(style, defaultStrokeStyle),
            fill: this.createFillStyle(style, defaultFillStyle)
        });
    },
    createIconStyle: function(style, defaultIconStyle) {
        var styleOptions = {};

        if(defaultIconStyle instanceof ol.style.Icon) {
            styleOptions.src = defaultIconStyle.getSrc();
            styleOptions.rotation = defaultIconStyle.getRotation();
            styleOptions.scale = defaultIconStyle.getScale();
            styleOptions.size = defaultIconStyle.getSize();
            styleOptions.imgSize = defaultIconStyle.getSize();
        }

        if(style.externalGraphic !== undefined) {
            if(this.externalGraphicPrefix !== undefined) {
                styleOptions.src = this.externalGraphicPrefix + style.externalGraphic;
            } else {
                styleOptions.src = style.externalGraphic;
            }

        }

        if(style.graphicRotation !== undefined) {
            styleOptions.rotation = parseFloat(style.graphicRotation);
        }

        if(style.graphicWidth !== undefined && style.graphicHeight !== undefined) {
            styleOptions.size = [
                parseInt(style.graphicWidth),
                parseInt(style.graphicHeight)
            ];
            styleOptions.imgSize = [
                parseInt(style.graphicWidth),
                parseInt(style.graphicHeight)
            ];
        }

        if(style.graphicColor !== undefined) {
            styleOptions.color = style.graphicColor;
        }

        var anchor = [0.5, 0.5];
        if(style.graphicXAnchor !== undefined) {
            anchor[0] = parseInt(style.graphicXAnchor);
            styleOptions.anchorXUnits = 'pixel';
        }
        if(style.graphicYAnchor !== undefined) {
            anchor[1] = parseInt(style.graphicYAnchor);
            styleOptions.anchorYUnits = 'pixel';
        }
        styleOptions.anchor = anchor;

        if(style.graphicScale !== undefined) {
            styleOptions.scale = parseFloat(style.graphicScale);
        }

        return new ol.style.Icon(styleOptions);
    },
    createFillStyle: function(style, defaultFillStyle) {
        var color = ol.color.asArray(defaultFillStyle.getColor()).slice();
        var fillColor = style.fillColor;
        if (fillColor !== undefined) {
            fillColor = ol.color.asArray(fillColor);
            color[0] = fillColor[0];
            color[1] = fillColor[1];
            color[2] = fillColor[2];
        }
        var fillOpacity = style.fillOpacity;
        if(fillOpacity !== undefined) {
            color[3] = parseFloat(fillOpacity);
        }
        return new ol.style.Fill({
            color: color
        });
    },
    createStrokeStyle: function(style, defaultStrokeStyle) {
        var color = ol.color.asArray(defaultStrokeStyle.getColor()).slice();
        var strokeWidth = defaultStrokeStyle.getWidth();
        var strokeDashstyle = defaultStrokeStyle.getLineDash();

        var strokeColor = style.strokeColor;
        if(strokeColor !== undefined) {
            strokeColor = ol.color.asArray(strokeColor);
            color[0] = strokeColor[0];
            color[1] = strokeColor[1];
            color[2] = strokeColor[2];
        }
        var strokeOpacity = style.strokeOpacity;
        if(strokeOpacity !== undefined) {
            color[3] = parseFloat(strokeOpacity);
        }
        var _strokeWidth = style.strokeWidth;
        if(_strokeWidth !== undefined) {
            strokeWidth = parseFloat(_strokeWidth);
        }
        var _strokeDashstyle = style.strokeDashstyle;
        if(_strokeDashstyle !== undefined) {
            strokeDashstyle = this.createDashStyle(strokeWidth, _strokeDashstyle);
        }

        return new ol.style.Stroke({
            color: color,
            width: strokeWidth,
            lineDash: strokeDashstyle,
            lineJoin: 'round'
        });
    },
    // Taken from OpenLayers 2.13.1
    // see https://github.com/openlayers/openlayers/blob/release-2.13.1/lib/OpenLayers/Renderer/SVG.js#L391
    createDashStyle: function(strokeWidth, strokeDashstyle) {
        var w = strokeWidth;
        var str = strokeDashstyle;
        switch (str) {
            case 'dot':
                return [1, 4 * w];
            case 'dash':
                return [4 * w, 4 * w];
            case 'dashdot':
                return [4 * w, 4 * w, 1, 4 * w];
            case 'longdash':
                return [8 * w, 4 * w];
            case 'longdashdot':
                return [8 * w, 4 * w, 1, 4 * w];
            // also matches 'solid'
            default:
                return undefined;
          }
    },
    // return function for labelKey from feature if feature is undefined
    // used for default layer style
    getLabel: function(feature, labelKey) {
        if(feature === undefined) {
            return function(_feature) {
                if(_feature === undefined) {
                    return '';
                }
                return _feature.get(labelKey);
            };
        }
        return feature.get(labelKey);
    },
    createTextStyle: function(style, defaultTextStyle, feature) {
        var fontWeight = this.DEFAULT_FONT_WEIGHT;
        var fontFace = this.DEFAULT_FONT_FACE;
        var fontSize = this.DEFAULT_FONT_SIZE;
        var defaultText;
        var defaultTextFillStyle;

        // atm defaultTextStyle is null
        if(defaultTextStyle !== null) {
            var splittedFont = defaultTextStyle.getFont().split(' ');
            fontWeight = splittedFont[0];
            fontSize = splittedFont[1];
            fontFace = splittedFont[2];
            defaultTextFillStyle = defaultTextStyle.getFill();
            defaultText = defaultTextStyle.getText();
            if(angular.isFunction(defaultText) && feature !== undefined) {
                defaultText = defaultText.call(this, feature);
            }
        }
        var styleOptions = {};
        if(style.text !== undefined) {
            styleOptions.text = style.text;
        } else if(style.propertyLabel !== undefined) {
            styleOptions.text = this.getLabel(feature, style.propertyLabel);
        } else if(defaultText !== undefined) {
            styleOptions.text = defaultText;
        }
        if(styleOptions.text === undefined && feature !== undefined) {
            return;
        }
        if(style.fontWeight !== undefined) {
            fontWeight = style.fontWeight;
        }
        if(style.fontSize !== undefined) {
            fontSize = style.fontSize;
        }
        if(style.fontFace !== undefined) {
            fontFace = style.fontFace;
        }
        styleOptions.font = [fontWeight, fontSize, fontFace].join(' ');

        var fontColor = [];
        if(defaultTextFillStyle !== undefined && defaultTextFillStyle !== null) {
            var defaultFontColor = defaultTextFillStyle.getColor();
            if(defaultFontColor !== undefined) {
                fontColor = ol.color.asArray(defaultFontColor).slice();
            }
        }
        if(style.fontColor !== undefined) {
            var _fontColor = ol.color.asArray(style.fontColor).slice();
            if(_fontColor !== undefined) {
                fontColor[0] = _fontColor[0];
                fontColor[1] = _fontColor[1];
                fontColor[2] = _fontColor[2];
                fontColor[3] = _fontColor[3] || fontColor[3] || 1;
            }
        }
        if(fontColor !== undefined && fontColor.length === 4) {
            styleOptions.fill = new ol.style.Fill({
                color: fontColor
            });
        }
        if(Object.keys(styleOptions).length > 0) {
            return new ol.style.Text(styleOptions);
        }
        return undefined;
    }
    // TODO add getProperties method including handling of hidden properties like style
    // TODO add hasProperty method
});
<commit_msg>Removed unneeded method overwrite<commit_after>/**
 * @ngdoc object
 * @name anol.layer.Feature
 *
 * @param {Object} options AnOl Layer options
 * @param {Object} options.olLayer Options for ol.layer.Vector
 * @param {Object} options.olLayer.source Options for ol.source.Vector
 *
 * @description
 * Inherits from {@link anol.layer.Layer anol.layer.Layer}.
 */
 anol.layer.Feature = function(_options) {
    if(_options === false) {
        anol.layer.Layer.call(this, _options);
        return;
    }
    var self = this;
    var defaults = {};
    var options = $.extend({}, defaults, _options );

    this.hasStyleFunction = angular.isFunction(options.olLayer.style);

    this.style = options.style;
    this.minResolution = (options.style || {}).minResolution;
    this.maxResolution = (options.style || {}).maxResolution;
    this.hasPropertyLabel = (options.style || {}).propertyLabel !== undefined;

    this.externalGraphicPrefix = options.externalGraphicPrefix;
    this.hasPropertyLabel = false;

    this.isVector = true;
    this.loaded = true;
    this.saveable = options.saveable || false;
    this.editable = options.editable || false;

    anol.layer.Layer.call(this, options);
};
anol.layer.Feature.prototype = new anol.layer.Layer(false);
$.extend(anol.layer.Feature.prototype, {
    CLASS_NAME: 'anol.layer.Feature',
    OL_LAYER_CLASS: ol.layer.Vector,
    OL_SOURCE_CLASS: ol.source.Vector,
    DEFAULT_FONT_FACE: 'Helvetica',
    DEFAULT_FONT_SIZE: '10px',
    DEFAULT_FONT_WEIGHT: 'normal',
    setOlLayer: function(olLayer) {
        var self = this;
        // if the layer has an own style function we don't create an style object
        if(!this.hasStyleFunction) {
            var defaultStyle = angular.isFunction(olLayer.getStyle()) ? olLayer.getStyle()()[0] : olLayer.getStyle();

            if(this.style !== undefined) {
                var createImageStyleFunction = this.style.externalGraphic !== undefined ? this.createIconStyle : this.createCircleStyle;

                this.defaultStyle = new ol.style.Style({
                    image: createImageStyleFunction.call(this, this.style, defaultStyle.getImage()),
                    fill: this.createFillStyle(this.style, defaultStyle.getFill()),
                    stroke: this.createStrokeStyle(this.style, defaultStyle.getStroke()),
                    text: this.createTextStyle(this.style, defaultStyle.getText())
                });
            } else {
                this.defaultStyle = defaultStyle;
            }

            olLayer.setStyle(function(feature, resolution) {
                return [self.createStyle(feature, resolution)];
            });
        }

        anol.layer.Layer.prototype.setOlLayer.call(this, olLayer);
    },
    extent: function() {
        var extent = this.olLayer.getSource().getExtent();
        if(ol.extent.isEmpty(extent)) {
            return false;
        }
        return extent;
    },
    createStyle: function(feature, resolution) {
        var defaultStyle = angular.isFunction(this.defaultStyle) ?
            this.defaultStyle(feature, resolution)[0] : this.defaultStyle;
        if(feature === undefined) {
            return defaultStyle;
        }
        var geometryType = feature.getGeometry().getType();
        var featureStyle = feature.get('style') || {};
        if(
            angular.equals(featureStyle, {}) &&
            !this.hasPropertyLabel &&
            this.minResolution === undefined &&
            this.maxResolution === undefined
        ) {
            return defaultStyle;
        }

        var minResolution = featureStyle.minResolution || this.minResolution;
        if(angular.isString(minResolution)) {
            minResolution = parseFloat(minResolution);
        }
        var maxResolution = featureStyle.maxResolution || this.maxResolution;
        if(angular.isString(maxResolution)) {
            maxResolution = parseFloat((maxResolution));
        }
        if(
            (angular.isDefined(minResolution) && minResolution > resolution) ||
            (angular.isDefined(maxResolution) && maxResolution < resolution)
        ) {
            return new ol.style.Style();
        }

        var styleOptions = {};
        if(geometryType === 'Point') {
            styleOptions.image = this.createImageStyle(featureStyle, defaultStyle.getImage());
        } else {
            // line features ignores fill style
            styleOptions.fill = this.createFillStyle(featureStyle, defaultStyle.getFill());
            styleOptions.stroke = this.createStrokeStyle(featureStyle, defaultStyle.getStroke());
        }
        styleOptions.text = this.createTextStyle(featureStyle, defaultStyle.getText(), feature);
        return new ol.style.Style(styleOptions);
    },
    createImageStyle: function(style, defaultImageStyle) {
        var radius = style.radius;
        var externalGraphic = style.externalGraphic;

        var isCircle = radius !== undefined;
        var isIcon = externalGraphic !== undefined;
        var isDefaultCircle = defaultImageStyle instanceof ol.style.Circle;
        var isDefaultIcon = defaultImageStyle instanceof ol.style.Icon;

        if (isIcon || (!isCircle && isDefaultIcon)) {
            return this.createIconStyle(style, defaultImageStyle);
        } else if(isCircle || (!isIcon && isDefaultCircle)) {
            return this.createCircleStyle(style, defaultImageStyle);
        }
        return defaultImageStyle;
    },
    createCircleStyle: function(style, defaultCircleStyle) {
        var defaultStrokeStyle = new ol.style.Stroke();
        var defaultFillStyle = new ol.style.Fill();
        var radius;
        if(defaultCircleStyle instanceof ol.style.Circle) {
            defaultStrokeStyle = defaultCircleStyle.getStroke();
            defaultFillStyle = defaultCircleStyle.getFill();
            radius = defaultCircleStyle.getRadius();
        }

        var _radius = style.radius;
        if(_radius !== undefined) {
            radius = parseFloat(_radius);
        }
        return new ol.style.Circle({
            radius: radius,
            stroke: this.createStrokeStyle(style, defaultStrokeStyle),
            fill: this.createFillStyle(style, defaultFillStyle)
        });
    },
    createIconStyle: function(style, defaultIconStyle) {
        var styleOptions = {};

        if(defaultIconStyle instanceof ol.style.Icon) {
            styleOptions.src = defaultIconStyle.getSrc();
            styleOptions.rotation = defaultIconStyle.getRotation();
            styleOptions.scale = defaultIconStyle.getScale();
            styleOptions.size = defaultIconStyle.getSize();
            styleOptions.imgSize = defaultIconStyle.getSize();
        }

        if(style.externalGraphic !== undefined) {
            if(this.externalGraphicPrefix !== undefined) {
                styleOptions.src = this.externalGraphicPrefix + style.externalGraphic;
            } else {
                styleOptions.src = style.externalGraphic;
            }

        }

        if(style.graphicRotation !== undefined) {
            styleOptions.rotation = parseFloat(style.graphicRotation);
        }

        if(style.graphicWidth !== undefined && style.graphicHeight !== undefined) {
            styleOptions.size = [
                parseInt(style.graphicWidth),
                parseInt(style.graphicHeight)
            ];
            styleOptions.imgSize = [
                parseInt(style.graphicWidth),
                parseInt(style.graphicHeight)
            ];
        }

        if(style.graphicColor !== undefined) {
            styleOptions.color = style.graphicColor;
        }

        var anchor = [0.5, 0.5];
        if(style.graphicXAnchor !== undefined) {
            anchor[0] = parseInt(style.graphicXAnchor);
            styleOptions.anchorXUnits = 'pixel';
        }
        if(style.graphicYAnchor !== undefined) {
            anchor[1] = parseInt(style.graphicYAnchor);
            styleOptions.anchorYUnits = 'pixel';
        }
        styleOptions.anchor = anchor;

        if(style.graphicScale !== undefined) {
            styleOptions.scale = parseFloat(style.graphicScale);
        }

        return new ol.style.Icon(styleOptions);
    },
    createFillStyle: function(style, defaultFillStyle) {
        var color = ol.color.asArray(defaultFillStyle.getColor()).slice();
        var fillColor = style.fillColor;
        if (fillColor !== undefined) {
            fillColor = ol.color.asArray(fillColor);
            color[0] = fillColor[0];
            color[1] = fillColor[1];
            color[2] = fillColor[2];
        }
        var fillOpacity = style.fillOpacity;
        if(fillOpacity !== undefined) {
            color[3] = parseFloat(fillOpacity);
        }
        return new ol.style.Fill({
            color: color
        });
    },
    createStrokeStyle: function(style, defaultStrokeStyle) {
        var color = ol.color.asArray(defaultStrokeStyle.getColor()).slice();
        var strokeWidth = defaultStrokeStyle.getWidth();
        var strokeDashstyle = defaultStrokeStyle.getLineDash();

        var strokeColor = style.strokeColor;
        if(strokeColor !== undefined) {
            strokeColor = ol.color.asArray(strokeColor);
            color[0] = strokeColor[0];
            color[1] = strokeColor[1];
            color[2] = strokeColor[2];
        }
        var strokeOpacity = style.strokeOpacity;
        if(strokeOpacity !== undefined) {
            color[3] = parseFloat(strokeOpacity);
        }
        var _strokeWidth = style.strokeWidth;
        if(_strokeWidth !== undefined) {
            strokeWidth = parseFloat(_strokeWidth);
        }
        var _strokeDashstyle = style.strokeDashstyle;
        if(_strokeDashstyle !== undefined) {
            strokeDashstyle = this.createDashStyle(strokeWidth, _strokeDashstyle);
        }

        return new ol.style.Stroke({
            color: color,
            width: strokeWidth,
            lineDash: strokeDashstyle,
            lineJoin: 'round'
        });
    },
    // Taken from OpenLayers 2.13.1
    // see https://github.com/openlayers/openlayers/blob/release-2.13.1/lib/OpenLayers/Renderer/SVG.js#L391
    createDashStyle: function(strokeWidth, strokeDashstyle) {
        var w = strokeWidth;
        var str = strokeDashstyle;
        switch (str) {
            case 'dot':
                return [1, 4 * w];
            case 'dash':
                return [4 * w, 4 * w];
            case 'dashdot':
                return [4 * w, 4 * w, 1, 4 * w];
            case 'longdash':
                return [8 * w, 4 * w];
            case 'longdashdot':
                return [8 * w, 4 * w, 1, 4 * w];
            // also matches 'solid'
            default:
                return undefined;
          }
    },
    // return function for labelKey from feature if feature is undefined
    // used for default layer style
    getLabel: function(feature, labelKey) {
        if(feature === undefined) {
            return function(_feature) {
                if(_feature === undefined) {
                    return '';
                }
                return _feature.get(labelKey);
            };
        }
        return feature.get(labelKey);
    },
    createTextStyle: function(style, defaultTextStyle, feature) {
        var fontWeight = this.DEFAULT_FONT_WEIGHT;
        var fontFace = this.DEFAULT_FONT_FACE;
        var fontSize = this.DEFAULT_FONT_SIZE;
        var defaultText;
        var defaultTextFillStyle;

        // atm defaultTextStyle is null
        if(defaultTextStyle !== null) {
            var splittedFont = defaultTextStyle.getFont().split(' ');
            fontWeight = splittedFont[0];
            fontSize = splittedFont[1];
            fontFace = splittedFont[2];
            defaultTextFillStyle = defaultTextStyle.getFill();
            defaultText = defaultTextStyle.getText();
            if(angular.isFunction(defaultText) && feature !== undefined) {
                defaultText = defaultText.call(this, feature);
            }
        }
        var styleOptions = {};
        if(style.text !== undefined) {
            styleOptions.text = style.text;
        } else if(style.propertyLabel !== undefined) {
            styleOptions.text = this.getLabel(feature, style.propertyLabel);
        } else if(defaultText !== undefined) {
            styleOptions.text = defaultText;
        }
        if(styleOptions.text === undefined && feature !== undefined) {
            return;
        }
        if(style.fontWeight !== undefined) {
            fontWeight = style.fontWeight;
        }
        if(style.fontSize !== undefined) {
            fontSize = style.fontSize;
        }
        if(style.fontFace !== undefined) {
            fontFace = style.fontFace;
        }
        styleOptions.font = [fontWeight, fontSize, fontFace].join(' ');

        var fontColor = [];
        if(defaultTextFillStyle !== undefined && defaultTextFillStyle !== null) {
            var defaultFontColor = defaultTextFillStyle.getColor();
            if(defaultFontColor !== undefined) {
                fontColor = ol.color.asArray(defaultFontColor).slice();
            }
        }
        if(style.fontColor !== undefined) {
            var _fontColor = ol.color.asArray(style.fontColor).slice();
            if(_fontColor !== undefined) {
                fontColor[0] = _fontColor[0];
                fontColor[1] = _fontColor[1];
                fontColor[2] = _fontColor[2];
                fontColor[3] = _fontColor[3] || fontColor[3] || 1;
            }
        }
        if(fontColor !== undefined && fontColor.length === 4) {
            styleOptions.fill = new ol.style.Fill({
                color: fontColor
            });
        }
        if(Object.keys(styleOptions).length > 0) {
            return new ol.style.Text(styleOptions);
        }
        return undefined;
    }
    // TODO add getProperties method including handling of hidden properties like style
    // TODO add hasProperty method
});
<|endoftext|>


<commit_before>import {
  getArg,
  getArgs,
  getEnvironmentVariables,
  getEnvironmentVariable,
  getRemainingVariables,
  getRemainingOptions,
  flattenOptions,
} from '../args';

describe('args test', () => {
  test('it should return correct arg', () => {
    process.argv = ['node', '-e', 'MONGO_URL=mongodb://127.0.0.1:27017', '--deps', 'imagemagick'];
    const arg = getArg('deps');
    expect(arg).toBe('imagemagick');
  });

  test('it should return all default args', () => {
    process.argv = ['node', '-e', 'MONGO_URL=mongodb://127.0.0.1:27017', '--deps', 'imagemagick'];
    const args = getArgs();
    expect(args).toEqual({
      $0: '-e',
      _: ['node'],
      help: false,
      version: false,
      deps: 'imagemagick',
      e: 'MONGO_URL=mongodb://127.0.0.1:27017',
    });
  });

  test('it should return all args when passed an argv', () => {
    const args = getArgs([
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '--deps',
      'imagemagick',
      '--public',
    ]);
    expect(args).toEqual({
      $0: '-e',
      _: ['node'],
      help: false,
      version: false,
      deps: 'imagemagick',
      e: 'MONGO_URL=mongodb://127.0.0.1:27017',
      public: true,
    });
  });

  test('it should return correct number of environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariables();
    expect(environmentVariables.length).toBe(2);
  });

  test('it should return all environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariables();
    expect(environmentVariables).toEqual([
      { name: 'MONGO_URL', value: 'mongodb://127.0.0.1:27017' },
      { name: 'ROOT_URL', value: 'http://localhost:3000' },
    ]);
  });

  test('it should return a environment variable by name', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariable('ROOT_URL');
    expect(environmentVariables).toBe('http://localhost:3000');
  });

  test('it should return all custom environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
    ];
    const remainingVariables = getRemainingVariables();
    expect(remainingVariables).toEqual([['-e', 'MY_SPECIAL_VAR=cats'], ['-e', 'SECRET=litter']]);
  });

  test('it should return all custom options', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
      '--public',
      '--alias',
      'abc.com',
    ];
    const remainingOptions = getRemainingOptions();
    expect(remainingOptions).toEqual([['--public'], ['--alias', 'abc.com']]);
  });

  test('it should correctly flatten options', () => {
    const flattenedOptions = flattenOptions([
      '--public',
      ['-e', 'MONGO_URL=mongodb://127.0.0.1:27017'],
      ['--alias', 'abc.com'],
    ]);
    expect(flattenedOptions).toEqual([
      '--public',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '--alias',
      'abc.com',
    ]);
  });

  test('it should ignore certain flags', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
      '--nosplit',
    ];
    const remainingVariables = getRemainingVariables();
    expect(remainingVariables).toEqual([['-e', 'MY_SPECIAL_VAR=cats'], ['-e', 'SECRET=litter']]);
  });
});
<commit_msg>Del extra \n<commit_after>import {
  getArg,
  getArgs,
  getEnvironmentVariables,
  getEnvironmentVariable,
  getRemainingVariables,
  getRemainingOptions,
  flattenOptions,
} from '../args';

describe('args test', () => {
  test('it should return correct arg', () => {
    process.argv = ['node', '-e', 'MONGO_URL=mongodb://127.0.0.1:27017', '--deps', 'imagemagick'];
    const arg = getArg('deps');
    expect(arg).toBe('imagemagick');
  });

  test('it should return all default args', () => {
    process.argv = ['node', '-e', 'MONGO_URL=mongodb://127.0.0.1:27017', '--deps', 'imagemagick'];
    const args = getArgs();
    expect(args).toEqual({
      $0: '-e',
      _: ['node'],
      help: false,
      version: false,
      deps: 'imagemagick',
      e: 'MONGO_URL=mongodb://127.0.0.1:27017',
    });
  });

  test('it should return all args when passed an argv', () => {
    const args = getArgs([
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '--deps',
      'imagemagick',
      '--public',
    ]);
    expect(args).toEqual({
      $0: '-e',
      _: ['node'],
      help: false,
      version: false,
      deps: 'imagemagick',
      e: 'MONGO_URL=mongodb://127.0.0.1:27017',
      public: true,
    });
  });

  test('it should return correct number of environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariables();
    expect(environmentVariables.length).toBe(2);
  });

  test('it should return all environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariables();
    expect(environmentVariables).toEqual([
      { name: 'MONGO_URL', value: 'mongodb://127.0.0.1:27017' },
      { name: 'ROOT_URL', value: 'http://localhost:3000' },
    ]);
  });

  test('it should return a environment variable by name', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '--deps',
      'abc',
    ];
    const environmentVariables = getEnvironmentVariable('ROOT_URL');
    expect(environmentVariables).toBe('http://localhost:3000');
  });

  test('it should return all custom environment variables', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
    ];
    const remainingVariables = getRemainingVariables();
    expect(remainingVariables).toEqual([['-e', 'MY_SPECIAL_VAR=cats'], ['-e', 'SECRET=litter']]);
  });

  test('it should return all custom options', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
      '--public',
      '--alias',
      'abc.com',
    ];
    const remainingOptions = getRemainingOptions();
    expect(remainingOptions).toEqual([['--public'], ['--alias', 'abc.com']]);
  });

  test('it should correctly flatten options', () => {
    const flattenedOptions = flattenOptions([
      '--public',
      ['-e', 'MONGO_URL=mongodb://127.0.0.1:27017'],
      ['--alias', 'abc.com'],
    ]);
    expect(flattenedOptions).toEqual([
      '--public',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '--alias',
      'abc.com',
    ]);
  });

  test('it should ignore certain flags', () => {
    process.argv = [
      'node',
      '-e',
      'MONGO_URL=mongodb://127.0.0.1:27017',
      '-e',
      'ROOT_URL=http://localhost:3000',
      '-e',
      'MY_SPECIAL_VAR=cats',
      '-e',
      'SECRET=litter',
      '--deps',
      'abc',
      '--nosplit',
    ];
    const remainingVariables = getRemainingVariables();
    expect(remainingVariables).toEqual([['-e', 'MY_SPECIAL_VAR=cats'], ['-e', 'SECRET=litter']]);
  });
});
<|endoftext|>


<commit_before>import request from 'common/src/superagent';
import {Services} from 'common/src/data/services';
import {flummoxCompatWrap} from 'common/src/redux-middlewares';
import {createAction} from 'redux-actions';
import Type from './clusters-types';
import {Provider, RequestConfig, saveRoute} from 'common/src/oauth-provider';

function fetchAllClusters(resourceId) {

  return request
          .get(`${Services.clusters.url}${Services.clusters.root}?lifecycle_status=ready`)
          .accept('json')
          .oauth(Provider, RequestConfig)
          .exec(saveRoute)
          .then(res => [resourceId, res.body]);
}

let fetchClustersAction = flummoxCompatWrap(createAction(Type.FETCH_CLUSTERS, fetchAllClusters));

export {
    fetchClustersAction as fetchAllClusters
};
<commit_msg>#281 implementation<commit_after>import request from 'common/src/superagent';
import {Services} from 'common/src/data/services';
import {flummoxCompatWrap} from 'common/src/redux-middlewares';
import {createAction} from 'redux-actions';
import Type from './clusters-types';
import {Provider, RequestConfig, saveRoute} from 'common/src/oauth-provider';

function fetchAllClusters(resourceId) {

  return request
          .get(`${Services.clusters.url}${Services.clusters.root}?lifecycle_status=ready&verbose=false`)
          .accept('json')
          .oauth(Provider, RequestConfig)
          .exec(saveRoute)
          .then(res => [resourceId, res.body]);
}

let fetchClustersAction = flummoxCompatWrap(createAction(Type.FETCH_CLUSTERS, fetchAllClusters));

export {
    fetchClustersAction as fetchAllClusters
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import isEmail from 'validator/lib/isEmail';
import {
  Button,
  ControlLabel,
  Form,
  FormControl,
  FormGroup
} from '@freecodecamp/react-bootstrap';
import { injectStripe } from 'react-stripe-elements';

import { apiLocation } from '../../../../config/env.json';
import Spacer from '../../../components/helpers/Spacer';
import StripeCardForm from './StripeCardForm';
import DonateCompletion from './DonateCompletion';
import { postJSON$ } from '../../../templates/Challenges/utils/ajax-stream.js';
import { userSelector, isSignedInSelector } from '../../../redux';

const propTypes = {
  email: PropTypes.string,
  isSignedIn: PropTypes.bool,
  stripe: PropTypes.shape({
    createToken: PropTypes.func.isRequired
  })
};
const initialState = {
  donationAmount: 500,
  donationState: {
    processing: false,
    success: false,
    error: ''
  }
};

const mapStateToProps = createSelector(
  userSelector,
  isSignedInSelector,
  ({ email }, isSignedIn) => ({ email, isSignedIn })
);

class DonateForm extends Component {
  constructor(...args) {
    super(...args);

    this.state = {
      ...initialState,
      email: null,
      isFormValid: false
    };

    this.getUserEmail = this.getUserEmail.bind(this);
    this.getValidationState = this.getValidationState.bind(this);
    this.handleEmailChange = this.handleEmailChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.postDonation = this.postDonation.bind(this);
    this.resetDonation = this.resetDonation.bind(this);
  }

  getUserEmail() {
    const { email: stateEmail } = this.state;
    const { email: propsEmail } = this.props;
    return stateEmail || propsEmail || '';
  }

  getValidationState(isFormValid) {
    this.setState(state => ({
      ...state,
      isFormValid
    }));
  }

  handleEmailChange(e) {
    const newValue = e.target.value;
    return this.setState(state => ({
      ...state,
      email: newValue
    }));
  }

  handleSubmit(e) {
    e.preventDefault();
    const email = this.getUserEmail();
    if (!email || !isEmail(email)) {
      return this.setState(state => ({
        ...state,
        donationState: {
          ...state.donationState,
          error:
            'We need a valid email address to which we can send your' +
            ' donation tax receipt.'
        }
      }));
    }
    return this.props.stripe.createToken({ email }).then(({ error, token }) => {
      if (error) {
        return this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            error:
              'Something went wrong processing your donation. Your card' +
              ' has not been charged.'
          }
        }));
      }
      return this.postDonation(token);
    });
  }

  postDonation(token) {
    const { donationAmount: amount } = this.state;
    const { isSignedIn } = this.props;
    this.setState(state => ({
      ...state,
      donationState: {
        ...state.donationState,
        processing: true
      }
    }));

    const chargeStripePath = isSignedIn
      ? `${apiLocation}/internal/donate/charge-stripe`
      : `${apiLocation}/unauthenticated/donate/charge-stripe`;
    return postJSON$(chargeStripePath, {
      token,
      amount
    }).subscribe(
      res =>
        this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            processing: false,
            success: true,
            error: res.error
          }
        })),
      err =>
        this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            processing: false,
            success: false,
            error: err.error
          }
        }))
    );
  }

  resetDonation() {
    return this.setState({ ...initialState });
  }

  renderCompletion(props) {
    return <DonateCompletion {...props} />;
  }

  renderDonateForm() {
    const { isFormValid } = this.state;
    return (

        <Form className='donation-form' onSubmit={this.handleSubmit}>
          <FormGroup className='donation-email-container'>
            <ControlLabel>
              Email (we'll send you a tax-deductible donation receipt):
            </ControlLabel>
            <FormControl
              onChange={this.handleEmailChange}
              placeholder='me@example.com'
              required={true}
              type='text'
              value={this.getUserEmail()}
            />
          </FormGroup>
          <StripeCardForm getValidationState={this.getValidationState} />
          <Button
            block={true}
            bsSize='lg'
            bsStyle='primary'
            disabled={!isFormValid}
            id='confirm-donation-btn'
            type='submit'
            >
            Confirm your donation of $5 / month
          </Button>
          <Spacer />
        </Form>

    );
  }

  render() {
    const {
      donationState: { processing, success, error }
    } = this.state;
    if (processing || success || error) {
      return this.renderCompletion({
        processing,
        success,
        error,
        reset: this.resetDonation
      });
    }
    return this.renderDonateForm();
  }
}

DonateForm.displayName = 'DonateForm';
DonateForm.propTypes = propTypes;

export default injectStripe(connect(mapStateToProps)(DonateForm));
<commit_msg>fix: Re-fix charge-stripe path<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import isEmail from 'validator/lib/isEmail';
import {
  Button,
  ControlLabel,
  Form,
  FormControl,
  FormGroup
} from '@freecodecamp/react-bootstrap';
import { injectStripe } from 'react-stripe-elements';

import { apiLocation } from '../../../../config/env.json';
import Spacer from '../../../components/helpers/Spacer';
import StripeCardForm from './StripeCardForm';
import DonateCompletion from './DonateCompletion';
import { postJSON$ } from '../../../templates/Challenges/utils/ajax-stream.js';
import { userSelector, isSignedInSelector } from '../../../redux';

const propTypes = {
  email: PropTypes.string,
  isSignedIn: PropTypes.bool,
  stripe: PropTypes.shape({
    createToken: PropTypes.func.isRequired
  })
};
const initialState = {
  donationAmount: 500,
  donationState: {
    processing: false,
    success: false,
    error: ''
  }
};

const mapStateToProps = createSelector(
  userSelector,
  isSignedInSelector,
  ({ email }, isSignedIn) => ({ email, isSignedIn })
);

class DonateForm extends Component {
  constructor(...args) {
    super(...args);

    this.state = {
      ...initialState,
      email: null,
      isFormValid: false
    };

    this.getUserEmail = this.getUserEmail.bind(this);
    this.getValidationState = this.getValidationState.bind(this);
    this.handleEmailChange = this.handleEmailChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.postDonation = this.postDonation.bind(this);
    this.resetDonation = this.resetDonation.bind(this);
  }

  getUserEmail() {
    const { email: stateEmail } = this.state;
    const { email: propsEmail } = this.props;
    return stateEmail || propsEmail || '';
  }

  getValidationState(isFormValid) {
    this.setState(state => ({
      ...state,
      isFormValid
    }));
  }

  handleEmailChange(e) {
    const newValue = e.target.value;
    return this.setState(state => ({
      ...state,
      email: newValue
    }));
  }

  handleSubmit(e) {
    e.preventDefault();
    const email = this.getUserEmail();
    if (!email || !isEmail(email)) {
      return this.setState(state => ({
        ...state,
        donationState: {
          ...state.donationState,
          error:
            'We need a valid email address to which we can send your' +
            ' donation tax receipt.'
        }
      }));
    }
    return this.props.stripe.createToken({ email }).then(({ error, token }) => {
      if (error) {
        return this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            error:
              'Something went wrong processing your donation. Your card' +
              ' has not been charged.'
          }
        }));
      }
      return this.postDonation(token);
    });
  }

  postDonation(token) {
    const { donationAmount: amount } = this.state;
    const { isSignedIn } = this.props;
    this.setState(state => ({
      ...state,
      donationState: {
        ...state.donationState,
        processing: true
      }
    }));

    const chargeStripePath = isSignedIn
      ? '/internal/donate/charge-stripe'
      : `${apiLocation}/unauthenticated/donate/charge-stripe`;
    return postJSON$(chargeStripePath, {
      token,
      amount
    }).subscribe(
      res =>
        this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            processing: false,
            success: true,
            error: res.error
          }
        })),
      err =>
        this.setState(state => ({
          ...state,
          donationState: {
            ...state.donationState,
            processing: false,
            success: false,
            error: err.error
          }
        }))
    );
  }

  resetDonation() {
    return this.setState({ ...initialState });
  }

  renderCompletion(props) {
    return <DonateCompletion {...props} />;
  }

  renderDonateForm() {
    const { isFormValid } = this.state;
    return (

        <Form className='donation-form' onSubmit={this.handleSubmit}>
          <FormGroup className='donation-email-container'>
            <ControlLabel>
              Email (we'll send you a tax-deductible donation receipt):
            </ControlLabel>
            <FormControl
              onChange={this.handleEmailChange}
              placeholder='me@example.com'
              required={true}
              type='text'
              value={this.getUserEmail()}
            />
          </FormGroup>
          <StripeCardForm getValidationState={this.getValidationState} />
          <Button
            block={true}
            bsSize='lg'
            bsStyle='primary'
            disabled={!isFormValid}
            id='confirm-donation-btn'
            type='submit'
            >
            Confirm your donation of $5 / month
          </Button>
          <Spacer />
        </Form>

    );
  }

  render() {
    const {
      donationState: { processing, success, error }
    } = this.state;
    if (processing || success || error) {
      return this.renderCompletion({
        processing,
        success,
        error,
        reset: this.resetDonation
      });
    }
    return this.renderDonateForm();
  }
}

DonateForm.displayName = 'DonateForm';
DonateForm.propTypes = propTypes;

export default injectStripe(connect(mapStateToProps)(DonateForm));
<|endoftext|>