<commit_before>/**
 * @fileoverview Tooltip component.
 * @author NHN Ent.
 *         FE Development Team <dl_javascript@nhnent.com>
 */

'use strict';

var TooltipBase = require('./tooltipBase'),
    chartConst = require('../const'),
    dom = require('../helpers/domHandler'),
    event = require('../helpers/eventListener'),
    templateMaker = require('../helpers/templateMaker'),
    tooltipTemplate = require('./tooltipTemplate');

var Tooltip = ne.util.defineClass(TooltipBase, /** @lends Tooltip.prototype */ {
    /**
     * Tooltip component.
     * @constructs Tooltip
     * @param {object} params parameters
     *      @param {array.<number>} params.values converted values
     *      @param {array} params.labels labels
     *      @param {array} params.legendLabels legend labels
     *      @param {object} params.bound axis bound
     *      @param {object} params.theme axis theme
     */
    init: function(params) {
        var optionTemplate;

        TooltipBase.call(this, params);

        optionTemplate = this.options.template || '';
        this.tplTooltip = optionTemplate ? templateMaker.template(optionTemplate) : tooltipTemplate.tplDefault;
    },

    /**
     * Render tooltip.
     * @param {{position: object}} bound tooltip bound
     * @returns {HTMLElement} tooltip element
     */
    render: function() {
        var el = TooltipBase.prototype.render.call(this);
        this.attachEvent(el);
        return el;
    },

    /**
     * To make tooltip data.
     * @returns {array.<object>} tooltip data
     */
    makeTooltipData: function() {
        var labels = this.labels,
            groupValues = this.values,
            legendLabels = this.legendLabels;

        return ne.util.map(groupValues, function(values, groupIndex) {
            return ne.util.map(values, function(value, index) {
                return {
                    category: labels ? labels[groupIndex] : '',
                    legend: legendLabels[index],
                    value: value
                };
            });
        });
    },

    /**
     * Fire custom event showAnimation.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @private
     */
    _fireShowAnimation: function(indexes) {
        this.fire('showAnimation', indexes);
    },

    /**
     * Fire custom event hideAnimation.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @private
     */
    _fireHideAnimation: function(indexes) {
        this.fire('hideAnimation', indexes);
    },

    /**
     * Set data indexes.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {{groupIndex: number, index:number}} indexes indexes
     * @private
     */
    _setIndexesCustomAttribute: function(elTooltip, indexes) {
        elTooltip.setAttribute('data-groupIndex', indexes.groupIndex);
        elTooltip.setAttribute('data-index', indexes.index);
    },

    /**
     * Get data indexes
     * @param {HTMLElement} elTooltip tooltip element
     * @returns {{groupIndex: number, index: number}} indexes
     * @private
     */
    _getIndexesCustomAttribute: function(elTooltip) {
        var groupIndex = elTooltip.getAttribute('data-groupIndex'),
            index = elTooltip.getAttribute('data-index'),
            indexes;
        if (groupIndex && index) {
            indexes = {
                groupIndex: parseInt(groupIndex, 10),
                index: parseInt(index, 10)
            };
        }
        return indexes;
    },

    /**
     * Set showed custom attribute.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {boolean} status whether showed or not
     * @private
     */
    _setShowedCustomAttribute: function(elTooltip, status) {
        elTooltip.setAttribute('data-showed', status);
    },

    /**
     * Whether showed tooltip or not.
     * @param {HTMLElement} elTooltip tooltip element
     * @returns {boolean} whether showed tooltip or not
     * @private
     */
    _isShowedTooltip: function(elTooltip) {
        return elTooltip.getAttribute('data-showed') === 'true';
    },

    /**
     * On mouseover event handler for tooltip area
     * @param {MouseEvent} e mouse event
     */
    onMouseover: function(e) {
        var elTarget = e.target || e.srcElement,
            indexes;

        if (!dom.hasClass(elTarget, chartConst.TOOLTIP_PREFIX)) {
            elTarget = dom.findParentByClass(elTarget, chartConst.TOOLTIP_PREFIX);
        }

        if (elTarget.id !== this._getTooltipId()) {
            return;
        }

        indexes = this._getIndexesCustomAttribute(elTarget);

        this._setShowedCustomAttribute(elTarget, true);

        this._fireShowAnimation(indexes);
    },

    onMousemove: function(e) {
        var elTarget = e.target || e.srcElement,
            indexes;

        if (!dom.hasClass(elTarget, chartConst.TOOLTIP_PREFIX)) {
            elTarget = dom.findParentByClass(elTarget, chartConst.TOOLTIP_PREFIX);
        }

        if (elTarget.id !== this._getTooltipId()) {
            return;
        }

        indexes = this._getIndexesCustomAttribute(elTarget);
        this.onShow({
            indexes: indexes,
            bound: {},
            eventPosition: {
                clientX: e.clientX,
                clientY: e.clientY
            }
        });
    },

    /**
     * On mouseout event handler for tooltip area
     * @param {MouseEvent} e mouse event
     */
    onMouseout: function(e) {
        var elTarget = e.target || e.srcElement;

        if (!dom.hasClass(elTarget, chartConst.TOOLTIP_PREFIX)) {
            elTarget = dom.findParentByClass(elTarget, chartConst.TOOLTIP_PREFIX);
        }

        if (elTarget.id !== this._getTooltipId()) {
            return;
        }

        this.hideTooltip(elTarget);
    },

    /**
     * To calculate tooltip position abount pie chart.
     * @param {object} params parameters
     *      @param {{left: number, top: number}} params.bound bound
     *      @param {{clientX: number, clientY: number}} params.eventPosition mouse position
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutPieChart: function(params) {
        params.bound.left = params.eventPosition.clientX - this.seriesPosition.left;
        params.bound.top = params.eventPosition.clientY - this.seriesPosition.top;
        return this._calculateTooltipPositionAboutNotBarChart(params);
    },

    /**
     * To calculate tooltip position about not bar chart.
     * @param {object} params parameters
     *      @param {{bound: object}} params.data graph information
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutNotBarChart: function(params) {
        var bound = params.bound,
            addPosition = params.addPosition,
            minusWidth = params.dimension.width - (bound.width || 0),
            lineGap = bound.width ? 0 : chartConst.TOOLTIP_GAP,
            positionOption = params.positionOption || '',
            tooltipHeight = params.dimension.height,
            result = {};
        result.left = bound.left + addPosition.left;
        result.top = bound.top - tooltipHeight + addPosition.top;

        if (positionOption.indexOf('left') > -1) {
            result.left -= minusWidth + lineGap;
        } else if (positionOption.indexOf('center') > -1) {
            result.left -= minusWidth / 2;
        } else {
            result.left += lineGap;
        }

        if (positionOption.indexOf('bottom') > -1) {
            result.top += tooltipHeight + lineGap;
        } else if (positionOption.indexOf('middle') > -1) {
            result.top += tooltipHeight / 2;
        } else {
            result.top -= chartConst.TOOLTIP_GAP;
        }
        return result;
    },

    /**
     * To calculate tooltip position about bar chart.
     * @param {object} params parameters
     *      @param {{bound: object}} params.data graph information
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutBarChart: function(params) {
        var bound = params.bound,
            addPosition = params.addPosition,
            minusHeight = params.dimension.height - (bound.height || 0),
            positionOption = params.positionOption || '',
            tooltipWidth = params.dimension.width,
            result = {};

        result.left = bound.left + bound.width + addPosition.left;
        result.top = bound.top + addPosition.top;

        // TODO : positionOptions을 객체로 만들어서 검사하도록 변경하기 ex) positionOption.left = true
        if (positionOption.indexOf('left') > -1) {
            result.left -= tooltipWidth;
        } else if (positionOption.indexOf('center') > -1) {
            result.left -= tooltipWidth / 2;
        } else {
            result.left += chartConst.TOOLTIP_GAP;
        }

        if (positionOption.indexOf('top') > -1) {
            result.top -= minusHeight;
        } else if (positionOption.indexOf('middle') > -1) {
            result.top -= minusHeight / 2;
        }

        return result;
    },

    /**
     * Calculate tooltip position.
     * @param {object} params parameters
     *      @param {{left: number, top: number, width: number, height: number}} params.bound graph bound
     *      @param {string} params.chartType chart type
     *      @param {boolean} params.allowNegativeTooltip whether allow negative tooltip or not
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPosition: function(params) {
        var result = {},
            sizeType, positionType, addPadding;

        if (params.eventPosition) {
            return this._calculateTooltipPositionAboutPieChart(params);
        }

        if (params.chartType === chartConst.CHART_TYPE_BAR) {
            result = this._calculateTooltipPositionAboutBarChart(params);
            sizeType = 'width';
            positionType = 'left';
            addPadding = 1;
        } else {
            result = this._calculateTooltipPositionAboutNotBarChart(params);
            sizeType = 'height';
            positionType = 'top';
            addPadding = -1;
        }

        if (params.allowNegativeTooltip) {
            result = this._moveToSymmetry(result, {
                bound: params.bound,
                indexes: params.indexes,
                dimension: params.dimension,
                sizeType: sizeType,
                positionType: positionType,
                addPadding: addPadding
            });
        }
        return result;
    },

    /**
     * Get value by indexes.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @returns {(string | number)} value
     * @private
     */
    _getValueByIndexes: function(indexes) {
        return this.values[indexes.groupIndex][indexes.index];
    },

    /**
     * Move to symmetry.
     * @param {{left: number, top: number}} position tooltip position
     * @param {object} params parameters
     *      @param {{left: number, top: number, width: number, height: number}} params.bound graph bound
     *      @param {string} params.id tooltip id
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.sizeType size type (width or height)
     *      @param {string} params.positionType position type (left or top)
     *      @param {number} params.addPadding add padding
     * @returns {{left: number, top: number}} moved position
     * @private
     */
    _moveToSymmetry: function(position, params) {
        var bound = params.bound,
            sizeType = params.sizeType,
            positionType = params.positionType,
            value = this._getValueByIndexes(params.indexes),
            center;

        if (value < 0) {
            center = bound[positionType] + (bound[sizeType] / 2) + (params.addPadding || 0);
            position[positionType] = position[positionType] - (position[positionType] - center) * 2 - params.dimension[sizeType];
        }

        return position;
    },

    /**
     * Get tooltip id.
     * @returns {string} tooltip id
     * @private
     */
    _getTooltipId: function() {
        if (!this.tooltipId) {
            this.tooltipId = chartConst.TOOLTIP_ID_PREFIX + '-' + (new Date()).getTime();
        }
        return this.tooltipId;
    },

    /**
     * To make tooltip html.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @returns {string} tooltip html
     * @private
     */
    _makeTooltipHtml: function(indexes) {
        var data = this.data[indexes.groupIndex][indexes.index];
        data.suffix = this.suffix;
        return this.tplTooltip(data);
    },

    _isChangedIndexes: function(prevIndexes, indexes) {
        return !!prevIndexes && (prevIndexes.groupIndex !== indexes.groupIndex || prevIndexes.index !== indexes.index);
    },

    /**
     * Show tooltip.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {{indexes: {groupIndex: number, index: number}, bound: object}} params tooltip data
     * @param {{left: number, top: number}} prevPosition prev position
     */
    showTooltip: function(elTooltip, params, prevPosition) {
        var indexes = params.indexes,
            curIndexes = this._getIndexesCustomAttribute(elTooltip),
            position;

        if (elTooltip.id === this._getTooltipId() && this._isChangedIndexes(curIndexes, indexes)) {
            this._fireHideAnimation(curIndexes);
        }

        elTooltip.id = this._getTooltipId();
        elTooltip.innerHTML = this._makeTooltipHtml(indexes);

        this._setIndexesCustomAttribute(elTooltip, indexes);
        this._setShowedCustomAttribute(elTooltip, true);

        dom.addClass(elTooltip, 'show');

        position = this._calculateTooltipPosition(ne.util.extend({
            dimension: this.getTooltipDimension(elTooltip),
            addPosition: ne.util.extend({
                left: 0,
                top: 0
            }, this.options.addPosition),
            positionOption: this.options.position || '',
            eventPosition: params.eventPosition
        }, params));

        this.moveToPosition(elTooltip, position, prevPosition);
        this._fireShowAnimation(indexes);
    },

    /**
     * Hide tooltip.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {function} callback callback
     */
    hideTooltip: function(elTooltip) {
        var that = this,
            indexes = this._getIndexesCustomAttribute(elTooltip);
        this._setShowedCustomAttribute(elTooltip, false);
        this._fireHideAnimation(indexes);

        if (this._isChangedIndexes(this.prevIndexes, indexes)) {
            delete this.prevIndexes;
        }

        setTimeout(function() {
            if (that._isShowedTooltip(elTooltip)) {
                return;
            }
            that.hideAnimation(elTooltip);

            that = null;
            indexes = null;
        }, chartConst.HIDE_DELAY);
    },

    /**
     * Attach event
     * @param {HTMLElement} el target element
     */
    attachEvent: function(el) {
        event.bindEvent('mouseover', el, ne.util.bind(this.onMouseover, this));
        event.bindEvent('mouseout', el, ne.util.bind(this.onMouseout, this));

        if (this.chartType === chartConst.CHART_TYPE_PIE) {
            event.bindEvent('mousemove', el, ne.util.bind(this.onMousemove, this));
        }
    }
});

ne.util.CustomEvents.mixin(Tooltip);

module.exports = Tooltip;
<commit_msg>Fix tooltip bug about pie chart.<commit_after>/**
 * @fileoverview Tooltip component.
 * @author NHN Ent.
 *         FE Development Team <dl_javascript@nhnent.com>
 */

'use strict';

var TooltipBase = require('./tooltipBase'),
    chartConst = require('../const'),
    dom = require('../helpers/domHandler'),
    event = require('../helpers/eventListener'),
    templateMaker = require('../helpers/templateMaker'),
    tooltipTemplate = require('./tooltipTemplate');

var Tooltip = ne.util.defineClass(TooltipBase, /** @lends Tooltip.prototype */ {
    /**
     * Tooltip component.
     * @constructs Tooltip
     * @param {object} params parameters
     *      @param {array.<number>} params.values converted values
     *      @param {array} params.labels labels
     *      @param {array} params.legendLabels legend labels
     *      @param {object} params.bound axis bound
     *      @param {object} params.theme axis theme
     */
    init: function(params) {
        var optionTemplate;

        TooltipBase.call(this, params);

        optionTemplate = this.options.template || '';
        this.tplTooltip = optionTemplate ? templateMaker.template(optionTemplate) : tooltipTemplate.tplDefault;
    },

    /**
     * Render tooltip.
     * @param {{position: object}} bound tooltip bound
     * @returns {HTMLElement} tooltip element
     */
    render: function() {
        var el = TooltipBase.prototype.render.call(this);
        this.attachEvent(el);
        return el;
    },

    /**
     * To make tooltip data.
     * @returns {array.<object>} tooltip data
     */
    makeTooltipData: function() {
        var labels = this.labels,
            groupValues = this.values,
            legendLabels = this.legendLabels;

        return ne.util.map(groupValues, function(values, groupIndex) {
            return ne.util.map(values, function(value, index) {
                return {
                    category: labels ? labels[groupIndex] : '',
                    legend: legendLabels[index],
                    value: value
                };
            });
        });
    },

    /**
     * Fire custom event showAnimation.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @private
     */
    _fireShowAnimation: function(indexes) {
        this.fire('showAnimation', indexes);
    },

    /**
     * Fire custom event hideAnimation.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @private
     */
    _fireHideAnimation: function(indexes) {
        this.fire('hideAnimation', indexes);
    },

    /**
     * Set data indexes.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {{groupIndex: number, index:number}} indexes indexes
     * @private
     */
    _setIndexesCustomAttribute: function(elTooltip, indexes) {
        elTooltip.setAttribute('data-groupIndex', indexes.groupIndex);
        elTooltip.setAttribute('data-index', indexes.index);
    },

    /**
     * Get data indexes
     * @param {HTMLElement} elTooltip tooltip element
     * @returns {{groupIndex: number, index: number}} indexes
     * @private
     */
    _getIndexesCustomAttribute: function(elTooltip) {
        var groupIndex = elTooltip.getAttribute('data-groupIndex'),
            index = elTooltip.getAttribute('data-index'),
            indexes;
        if (groupIndex && index) {
            indexes = {
                groupIndex: parseInt(groupIndex, 10),
                index: parseInt(index, 10)
            };
        }
        return indexes;
    },

    /**
     * Set showed custom attribute.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {boolean} status whether showed or not
     * @private
     */
    _setShowedCustomAttribute: function(elTooltip, status) {
        elTooltip.setAttribute('data-showed', status);
    },

    /**
     * Whether showed tooltip or not.
     * @param {HTMLElement} elTooltip tooltip element
     * @returns {boolean} whether showed tooltip or not
     * @private
     */
    _isShowedTooltip: function(elTooltip) {
        return elTooltip.getAttribute('data-showed') === 'true';
    },

    /**
     * On mouseover event handler for tooltip area
     * @param {MouseEvent} e mouse event
     */
    onMouseover: function(e) {
        var elTarget = e.target || e.srcElement,
            indexes;

        if (!dom.hasClass(elTarget, chartConst.TOOLTIP_PREFIX)) {
            elTarget = dom.findParentByClass(elTarget, chartConst.TOOLTIP_PREFIX);
        }

        if (elTarget.id !== this._getTooltipId()) {
            return;
        }

        indexes = this._getIndexesCustomAttribute(elTarget);

        this._setShowedCustomAttribute(elTarget, true);

        this._fireShowAnimation(indexes);
    },

    /**
     * On mouseout event handler for tooltip area
     * @param {MouseEvent} e mouse event
     */
    onMouseout: function(e) {
        var elTarget = e.target || e.srcElement;

        if (!dom.hasClass(elTarget, chartConst.TOOLTIP_PREFIX)) {
            elTarget = dom.findParentByClass(elTarget, chartConst.TOOLTIP_PREFIX);
        }

        if (elTarget.id !== this._getTooltipId()) {
            return;
        }

        this.hideTooltip(elTarget);
    },

    /**
     * To calculate tooltip position abount pie chart.
     * @param {object} params parameters
     *      @param {{left: number, top: number}} params.bound bound
     *      @param {{clientX: number, clientY: number}} params.eventPosition mouse position
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutPieChart: function(params) {
        params.bound.left = params.eventPosition.clientX - this.seriesPosition.left;
        params.bound.top = params.eventPosition.clientY - this.seriesPosition.top;
        return this._calculateTooltipPositionAboutNotBarChart(params);
    },

    /**
     * To calculate tooltip position about not bar chart.
     * @param {object} params parameters
     *      @param {{bound: object}} params.data graph information
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutNotBarChart: function(params) {
        var bound = params.bound,
            addPosition = params.addPosition,
            minusWidth = params.dimension.width - (bound.width || 0),
            lineGap = bound.width ? 0 : chartConst.TOOLTIP_GAP,
            positionOption = params.positionOption || '',
            tooltipHeight = params.dimension.height,
            result = {};
        result.left = bound.left + addPosition.left;
        result.top = bound.top - tooltipHeight + addPosition.top;

        if (positionOption.indexOf('left') > -1) {
            result.left -= minusWidth + lineGap;
        } else if (positionOption.indexOf('center') > -1) {
            result.left -= minusWidth / 2;
        } else {
            result.left += lineGap;
        }

        if (positionOption.indexOf('bottom') > -1) {
            result.top += tooltipHeight + lineGap;
        } else if (positionOption.indexOf('middle') > -1) {
            result.top += tooltipHeight / 2;
        } else {
            result.top -= chartConst.TOOLTIP_GAP;
        }

        return result;
    },

    /**
     * To calculate tooltip position about bar chart.
     * @param {object} params parameters
     *      @param {{bound: object}} params.data graph information
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPositionAboutBarChart: function(params) {
        var bound = params.bound,
            addPosition = params.addPosition,
            minusHeight = params.dimension.height - (bound.height || 0),
            positionOption = params.positionOption || '',
            tooltipWidth = params.dimension.width,
            result = {};

        result.left = bound.left + bound.width + addPosition.left;
        result.top = bound.top + addPosition.top;

        // TODO : positionOptions을 객체로 만들어서 검사하도록 변경하기 ex) positionOption.left = true
        if (positionOption.indexOf('left') > -1) {
            result.left -= tooltipWidth;
        } else if (positionOption.indexOf('center') > -1) {
            result.left -= tooltipWidth / 2;
        } else {
            result.left += chartConst.TOOLTIP_GAP;
        }

        if (positionOption.indexOf('top') > -1) {
            result.top -= minusHeight;
        } else if (positionOption.indexOf('middle') > -1) {
            result.top -= minusHeight / 2;
        }

        return result;
    },

    /**
     * Calculate tooltip position.
     * @param {object} params parameters
     *      @param {{left: number, top: number, width: number, height: number}} params.bound graph bound
     *      @param {string} params.chartType chart type
     *      @param {boolean} params.allowNegativeTooltip whether allow negative tooltip or not
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.positionOption position option (ex: 'left top')
     * @returns {{top: number, left: number}} position
     * @private
     */
    _calculateTooltipPosition: function(params) {
        var result = {},
            sizeType, positionType, addPadding;

        if (params.eventPosition) {
            return this._calculateTooltipPositionAboutPieChart(params);
        }

        if (params.chartType === chartConst.CHART_TYPE_BAR) {
            result = this._calculateTooltipPositionAboutBarChart(params);
            sizeType = 'width';
            positionType = 'left';
            addPadding = 1;
        } else {
            result = this._calculateTooltipPositionAboutNotBarChart(params);
            sizeType = 'height';
            positionType = 'top';
            addPadding = -1;
        }

        if (params.allowNegativeTooltip) {
            result = this._moveToSymmetry(result, {
                bound: params.bound,
                indexes: params.indexes,
                dimension: params.dimension,
                sizeType: sizeType,
                positionType: positionType,
                addPadding: addPadding
            });
        }
        return result;
    },

    /**
     * Get value by indexes.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @returns {(string | number)} value
     * @private
     */
    _getValueByIndexes: function(indexes) {
        return this.values[indexes.groupIndex][indexes.index];
    },

    /**
     * Move to symmetry.
     * @param {{left: number, top: number}} position tooltip position
     * @param {object} params parameters
     *      @param {{left: number, top: number, width: number, height: number}} params.bound graph bound
     *      @param {string} params.id tooltip id
     *      @param {{width: number, height: number}} params.dimension tooltip dimension
     *      @param {string} params.sizeType size type (width or height)
     *      @param {string} params.positionType position type (left or top)
     *      @param {number} params.addPadding add padding
     * @returns {{left: number, top: number}} moved position
     * @private
     */
    _moveToSymmetry: function(position, params) {
        var bound = params.bound,
            sizeType = params.sizeType,
            positionType = params.positionType,
            value = this._getValueByIndexes(params.indexes),
            center;

        if (value < 0) {
            center = bound[positionType] + (bound[sizeType] / 2) + (params.addPadding || 0);
            position[positionType] = position[positionType] - (position[positionType] - center) * 2 - params.dimension[sizeType];
        }

        return position;
    },

    /**
     * Get tooltip id.
     * @returns {string} tooltip id
     * @private
     */
    _getTooltipId: function() {
        if (!this.tooltipId) {
            this.tooltipId = chartConst.TOOLTIP_ID_PREFIX + '-' + (new Date()).getTime();
        }
        return this.tooltipId;
    },

    /**
     * To make tooltip html.
     * @param {{groupIndex: number, index: number}} indexes indexes
     * @returns {string} tooltip html
     * @private
     */
    _makeTooltipHtml: function(indexes) {
        var data = this.data[indexes.groupIndex][indexes.index];
        data.suffix = this.suffix;
        return this.tplTooltip(data);
    },

    _isChangedIndexes: function(prevIndexes, indexes) {
        return !!prevIndexes && (prevIndexes.groupIndex !== indexes.groupIndex || prevIndexes.index !== indexes.index);
    },

    /**
     * Show tooltip.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {{indexes: {groupIndex: number, index: number}, bound: object}} params tooltip data
     * @param {{left: number, top: number}} prevPosition prev position
     */
    showTooltip: function(elTooltip, params, prevPosition) {
        var indexes = params.indexes,
            curIndexes = this._getIndexesCustomAttribute(elTooltip),
            position;

        if (elTooltip.id === this._getTooltipId() && this._isChangedIndexes(curIndexes, indexes)) {
            this._fireHideAnimation(curIndexes);
        }

        elTooltip.id = this._getTooltipId();
        elTooltip.innerHTML = this._makeTooltipHtml(indexes);

        this._setIndexesCustomAttribute(elTooltip, indexes);
        this._setShowedCustomAttribute(elTooltip, true);

        dom.addClass(elTooltip, 'show');

        position = this._calculateTooltipPosition(ne.util.extend({
            dimension: this.getTooltipDimension(elTooltip),
            addPosition: ne.util.extend({
                left: 0,
                top: 0
            }, this.options.addPosition),
            positionOption: this.options.position || '',
            eventPosition: params.eventPosition
        }, params));

        this.moveToPosition(elTooltip, position, prevPosition);
        this._fireShowAnimation(indexes);
    },

    /**
     * Hide tooltip.
     * @param {HTMLElement} elTooltip tooltip element
     * @param {function} callback callback
     */
    hideTooltip: function(elTooltip) {
        var that = this,
            indexes = this._getIndexesCustomAttribute(elTooltip);
        this._setShowedCustomAttribute(elTooltip, false);
        this._fireHideAnimation(indexes);

        if (this._isChangedIndexes(this.prevIndexes, indexes)) {
            delete this.prevIndexes;
        }

        setTimeout(function() {
            if (that._isShowedTooltip(elTooltip)) {
                return;
            }
            that.hideAnimation(elTooltip);

            that = null;
            indexes = null;
        }, chartConst.HIDE_DELAY);
    },

    /**
     * Attach event
     * @param {HTMLElement} el target element
     */
    attachEvent: function(el) {
        event.bindEvent('mouseover', el, ne.util.bind(this.onMouseover, this));
        event.bindEvent('mouseout', el, ne.util.bind(this.onMouseout, this));
    }
});

ne.util.CustomEvents.mixin(Tooltip);

module.exports = Tooltip;
<|endoftext|>


<commit_before>
$("#lighthouseExportButton").on('click mouseenter', function() {
  var exports = JSON.parse(filterDataForExport());
  var href = lighthouseUrl + "pages/nitcexport.html?host=" + location.hostname +
      "&start=" + encodeURIComponent(exports.StartDate) + "&end=" +
      encodeURIComponent(exports.EndDate);
  if (exports.hasOwnProperty("EntityIds"))
      href += "&EntityIds=" + exports.EntityIds;
  if (exports.hasOwnProperty("NonIncidentTypeIds"))
      href += "&NonIncidentTypeIds=" + exports.NonIncidentTypeIds;
  if (exports.hasOwnProperty("TagIds"))
      href += "&TagIds=" + exports.TagIds;
  if (exports.hasOwnProperty("IncludeCompleted"))
      href += "&IncludeCompleted=" + exports.IncludeCompleted;
  $(this).attr("href", href);
});

function filterDataForExport() {
  var n=contentViewModel.lastReceivedFilterData;
  return n.PageIndex=1,n.PageSize=contentViewModel.totalNonIncidents(),
      n.SortField=contentViewModel.sortColumn(),
      n.SortOrder=contentViewModel.sortDirection(),
      JSON.stringify(n)
}
<commit_msg>Add statistics button<commit_after>
$("#lighthouseExportButton").on('click mouseenter', function() {
  var exports = JSON.parse(filterDataForExport());
  var href = lighthouseUrl + "pages/nitcexport.html?host=" + location.hostname +
      "&start=" + encodeURIComponent(exports.StartDate) + "&end=" +
      encodeURIComponent(exports.EndDate);
  if (exports.hasOwnProperty("EntityIds"))
      href += "&EntityIds=" + exports.EntityIds;
  if (exports.hasOwnProperty("NonIncidentTypeIds"))
      href += "&NonIncidentTypeIds=" + exports.NonIncidentTypeIds;
  if (exports.hasOwnProperty("TagIds"))
      href += "&TagIds=" + exports.TagIds;
  if (exports.hasOwnProperty("IncludeCompleted"))
      href += "&IncludeCompleted=" + exports.IncludeCompleted;
  $(this).attr("href", href);
});

$("#lighthouseStatsButton").on('click mouseenter', function() {
  var exports = JSON.parse(filterDataForExport());
  var href = lighthouseUrl + "pages/nitcstats.html?host=" + location.hostname +
      "&start=" + encodeURIComponent(exports.StartDate) + "&end=" +
      encodeURIComponent(exports.EndDate);
  if (exports.hasOwnProperty("EntityIds"))
      href += "&EntityIds=" + exports.EntityIds;
  if (exports.hasOwnProperty("NonIncidentTypeIds"))
      href += "&NonIncidentTypeIds=" + exports.NonIncidentTypeIds;
  if (exports.hasOwnProperty("TagIds"))
      href += "&TagIds=" + exports.TagIds;
  if (exports.hasOwnProperty("IncludeCompleted"))
      href += "&IncludeCompleted=" + exports.IncludeCompleted;
  $(this).attr("href", href);
});

function filterDataForExport() {
  var n=contentViewModel.lastReceivedFilterData;
  return n.PageIndex=1,n.PageSize=contentViewModel.totalNonIncidents(),
      n.SortField=contentViewModel.sortColumn(),
      n.SortOrder=contentViewModel.sortDirection(),
      JSON.stringify(n)
}
<|endoftext|>


<commit_before>var SideMenu = (function (document, hyperaudio) {

	function SideMenu (options) {
		this.options = {
			el: '#sidemenu',
			transcripts: '#panel-media',
			music: '#panel-bgm',
			stage: null // Points at a Stage instance
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		// Might rename the transcripts and music vars/options since rather ambiguous.

		this.el = typeof this.options.el == 'string' ? document.querySelector(this.options.el) : this.options.el;
		this.transcripts = typeof this.options.transcripts == 'string' ? document.querySelector(this.options.transcripts) : this.options.transcripts;
		this.music = typeof this.options.music == 'string' ? document.querySelector(this.options.music) : this.options.music;
		this.mediaCallback = this.options.callback;

		var handle = document.querySelector('#sidemenu-handle');
		handle._tap = new Tap({el: handle});
		handle.addEventListener('tap', this.toggleMenu.bind(this), false);

		this.updateStatus();

		// handle the tab bar
		var tabs = document.querySelectorAll('#sidemenu .tabbar li');
		for ( i = tabs.length-1; i >= 0; i-- ) {
			tabs[i]._tap = new Tap({el: tabs[i]});
			tabs[i].addEventListener('tap', this.selectPanel.bind(this), false);
		}

		this.initTranscripts();
		this.initMusic();
	}

	SideMenu.prototype.initTranscripts = function () {
		var self = this;

		hyperaudio.api.getTranscripts(function(success) {
			if(success) {
				var elem, trans;
				for(var i = 0, l = this.transcripts.length; i < l; i++) {
					trans = this.transcripts[i];
					elem = document.createElement('li');
					elem.setAttribute('data-id', trans._id);
					elem.innerHTML = trans.label;
					self.transcripts.appendChild(elem);
				}

				self.transcripts._tap = new Tap({el: self.transcripts});
				self.transcripts.addEventListener('tap', self.selectMedia.bind(self), false);
			}
		});
	};

	SideMenu.prototype.initMusic = function () {
		var stage = this.options.stage;

		function onDragStart (e) {
			hyperaudio.addClass(stage.target, 'dragdrop');
		}

		function onDrop (el) {
			if ( !el ) {	// we dropped outside the stage
				return;
			}

			var title = el.innerHTML;
			hyperaudio.addClass(el, 'effect');
			el.innerHTML = '<form>
' + title + '
Delay: 1s<input type="range" value="1" min="0.5" max="5" step="0.1" onchange="this.parentNode.querySelector(\'span\').innerHTML = this.value"></form>';
			stage.dropped(el, title);
		}

		if(stage.target) {
			// add drag and drop to BGM
			var items = document.querySelectorAll('#panel-bgm li');
			for (var i = items.length-1; i >= 0; i-- ) {
				items[i]._dragInstance = new DragDrop({
					handle: items[i],
					dropArea: stage.target,
					draggableClass: 'draggableEffect',
					onDragStart: onDragStart,
					onDrop: onDrop
				});
			}
		}
	};

	SideMenu.prototype.updateStatus = function () {
		this.opened = hyperaudio.hasClass(this.el, 'opened');
	};

	SideMenu.prototype.toggleMenu = function () {
		if ( this.opened ) {
			this.close();
		} else {
			this.open();
		}
	};

	SideMenu.prototype.open = function () {
		if ( this.opened ) {
			return;
		}

		hyperaudio.addClass(this.el, 'opened');
		this.opened = true;
	};

	SideMenu.prototype.close = function () {
		if ( !this.opened ) {
			return;
		}

		hyperaudio.removeClass(this.el, 'opened');
		this.opened = false;
	};

	SideMenu.prototype.selectPanel = function (e) {
		var current = document.querySelector('#sidemenu .tabbar li.selected');
		var incoming = e.currentTarget;
		hyperaudio.removeClass(current, 'selected');
		hyperaudio.addClass(incoming, 'selected');

		var panelID = 'panel' + incoming.id.replace('sidemenu', '');
		current = document.querySelector('#sidemenu .panel.selected');
		hyperaudio.removeClass(current, 'selected');
		incoming = document.querySelector('#' + panelID);
		hyperaudio.addClass(incoming, 'selected');
	};

	SideMenu.prototype.selectMedia = function (e) {
		e.stopPropagation();	// just in case

		var starter = e.target;

		if ( hyperaudio.hasClass(e.target.parentNode, 'folder') ) {
			starter = e.target.parentNode;
		}

		if ( hyperaudio.hasClass(starter, 'folder') ) {
			hyperaudio.toggleClass(starter, 'open');
			return;
		}

		if ( !starter.getAttribute('data-id') || !this.mediaCallback ) {
			return;
		}

		this.mediaCallback(starter);
	};

	return SideMenu;
})(document, hyperaudio);<commit_msg>Sidemenu only displays type html transcripts.<commit_after>var SideMenu = (function (document, hyperaudio) {

	function SideMenu (options) {
		this.options = {
			el: '#sidemenu',
			transcripts: '#panel-media',
			music: '#panel-bgm',
			stage: null // Points at a Stage instance
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		// Might rename the transcripts and music vars/options since rather ambiguous.

		this.el = typeof this.options.el == 'string' ? document.querySelector(this.options.el) : this.options.el;
		this.transcripts = typeof this.options.transcripts == 'string' ? document.querySelector(this.options.transcripts) : this.options.transcripts;
		this.music = typeof this.options.music == 'string' ? document.querySelector(this.options.music) : this.options.music;
		this.mediaCallback = this.options.callback;

		var handle = document.querySelector('#sidemenu-handle');
		handle._tap = new Tap({el: handle});
		handle.addEventListener('tap', this.toggleMenu.bind(this), false);

		this.updateStatus();

		// handle the tab bar
		var tabs = document.querySelectorAll('#sidemenu .tabbar li');
		for ( i = tabs.length-1; i >= 0; i-- ) {
			tabs[i]._tap = new Tap({el: tabs[i]});
			tabs[i].addEventListener('tap', this.selectPanel.bind(this), false);
		}

		this.initTranscripts();
		this.initMusic();
	}

	SideMenu.prototype.initTranscripts = function () {
		var self = this;

		hyperaudio.api.getTranscripts(function(success) {
			if(success) {
				var elem, trans;
				for(var i = 0, l = this.transcripts.length; i < l; i++) {
					trans = this.transcripts[i];
					if(trans.type === 'html') {
						elem = document.createElement('li');
						elem.setAttribute('data-id', trans._id);
						elem.innerHTML = trans.label;
						self.transcripts.appendChild(elem);
					}
				}

				self.transcripts._tap = new Tap({el: self.transcripts});
				self.transcripts.addEventListener('tap', self.selectMedia.bind(self), false);
			}
		});
	};

	SideMenu.prototype.initMusic = function () {
		var stage = this.options.stage;

		function onDragStart (e) {
			hyperaudio.addClass(stage.target, 'dragdrop');
		}

		function onDrop (el) {
			if ( !el ) {	// we dropped outside the stage
				return;
			}

			var title = el.innerHTML;
			hyperaudio.addClass(el, 'effect');
			el.innerHTML = '<form>
' + title + '
Delay: 1s<input type="range" value="1" min="0.5" max="5" step="0.1" onchange="this.parentNode.querySelector(\'span\').innerHTML = this.value"></form>';
			stage.dropped(el, title);
		}

		if(stage.target) {
			// add drag and drop to BGM
			var items = document.querySelectorAll('#panel-bgm li');
			for (var i = items.length-1; i >= 0; i-- ) {
				items[i]._dragInstance = new DragDrop({
					handle: items[i],
					dropArea: stage.target,
					draggableClass: 'draggableEffect',
					onDragStart: onDragStart,
					onDrop: onDrop
				});
			}
		}
	};

	SideMenu.prototype.updateStatus = function () {
		this.opened = hyperaudio.hasClass(this.el, 'opened');
	};

	SideMenu.prototype.toggleMenu = function () {
		if ( this.opened ) {
			this.close();
		} else {
			this.open();
		}
	};

	SideMenu.prototype.open = function () {
		if ( this.opened ) {
			return;
		}

		hyperaudio.addClass(this.el, 'opened');
		this.opened = true;
	};

	SideMenu.prototype.close = function () {
		if ( !this.opened ) {
			return;
		}

		hyperaudio.removeClass(this.el, 'opened');
		this.opened = false;
	};

	SideMenu.prototype.selectPanel = function (e) {
		var current = document.querySelector('#sidemenu .tabbar li.selected');
		var incoming = e.currentTarget;
		hyperaudio.removeClass(current, 'selected');
		hyperaudio.addClass(incoming, 'selected');

		var panelID = 'panel' + incoming.id.replace('sidemenu', '');
		current = document.querySelector('#sidemenu .panel.selected');
		hyperaudio.removeClass(current, 'selected');
		incoming = document.querySelector('#' + panelID);
		hyperaudio.addClass(incoming, 'selected');
	};

	SideMenu.prototype.selectMedia = function (e) {
		e.stopPropagation();	// just in case

		var starter = e.target;

		if ( hyperaudio.hasClass(e.target.parentNode, 'folder') ) {
			starter = e.target.parentNode;
		}

		if ( hyperaudio.hasClass(starter, 'folder') ) {
			hyperaudio.toggleClass(starter, 'open');
			return;
		}

		if ( !starter.getAttribute('data-id') || !this.mediaCallback ) {
			return;
		}

		this.mediaCallback(starter);
	};

	return SideMenu;
})(document, hyperaudio);<|endoftext|>


<commit_before><<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
 *  @restrict E
 *
 *  @description
 *
 *  This provides the toggle componant which can be used as checkbox and customize
 *  with color, click callback etc.
 *
 *  @scope
 *
 *  @param {string=} text Sets the display text for toggle button.
 *  @param {boolean=} state Set/get the current state of the toggler. Also can set
 *  default state to true/false.
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
 *  @param {string=} switch-color Accept color code and get applied to border, checkmark
 *  etc
 *  @param {boolean=} inactive This disables the toggler and hide the border
 *  @param {function()=} zsChange Callback function to handle change event from
 *  controller.
 *  @example
<<<<<<< HEAD
<example module="zsApp">
=======
<example module="zeus.widgets">
>>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
    <file name="index.html">

            <zs-simple-toggle text="{{ toggle.label }}"
                switch-color="#9c27b0"
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
                zs-change="clickMe()"
                state="toggle.state">
            </zs-simple-toggle>

            <zs-simple-toggle text="Inactive"
                switch-color="#12287E"
                state="true"
                inactive="true">
            </zs-simple-toggle>

    </file>
    <file name="myCtrl.js">
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c

            $scope.toggle = {
                label: "Demo Label",
                state: false
            };

            $scope.clickMe = function () {
                alert( 'You clicked Me...!!!' );
            };

        } );
    </file>
</example>
 */

angular.module( 'zeus.widgets' )
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
        restrict: 'E',
        replace: true,
        scope: {
            text: '@',
            state: '=?',
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
            color: '@switchColor',
            zsChange: '&',
            inactive: '@'
        },

        link: function ( scope, element ) {
            var wrap = $( element ),
                icon = wrap.find( '[data-role="icon"]' ),
                toggleState,
                recalcStyles,
<<<<<<> 16 ) + amt;

                if ( r > 255 ) {
                    r = 255;
                } else if ( r < 0 ) {
                    r = 0;
                }

                b = ( ( num >> 8 ) & 0x00FF ) + amt;

                if ( b > 255 ) {
                    b = 255;
                } else if ( b < 0 ) {
                    b = 0;
                }

                g = ( num & 0x0000FF ) + amt;

                if ( g > 255 ) {
                    g = 255;
                } else if ( g < 0 ) {
                    g = 0;
                }

                return ( usePound ? '#' : '' ) +
                    ( g | ( b << 8 ) | ( r << 16 ) ).toString( 16 );
            };
>>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c

            // Handler for state toggle.
            // Fired on click of slider
            toggleState = function () {
                scope.state = !scope.state;

                if ( scope.zsChange ) {
                    scope.zsChange();
                }

                recalcStyles();
            };

            attachEvents = function () {
                icon.css( {
                    borderColor: scope.color
                } );

                wrap.css( {
                    borderColor: scope.color
                } );

                wrap.click( function () {
                    scope.$apply( function () {
                        toggleState();
                    } );
                } );

                wrap.mouseover( function () {
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
                    } );
                } );

                wrap.mouseout( function () {
                    $( this ).css( {
                        backgroundColor: '#FFF'
                    } );
                } );
            };

            recalcStyles = function () {
                var bgColor = '#FFF';

                if ( scope.state ) {
                    wrap.addClass( 'state-on' );
                    wrap.removeClass( 'state-off' );
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c

                } else {
                    wrap.addClass( 'state-off' );
                    wrap.removeClass( 'state-on' );
<<<<<<>>>>>> c7d1017e86ca9ebcf90755b81da750fce22d9c2c
                }

                icon.css( {
                    backgroundColor: bgColor
                } );
            };

            scope.state = scope.state || false;

            if ( !scope.inactive ) {
                recalcStyles();
                attachEvents();
            } else {
                wrap.addClass( 'state-inactive' );
            }
            // Watch for changes in state
            scope.$watch( 'state', function () {
                recalcStyles();
            } );
        }
    };
} ] );
<commit_msg>Resolved conflicts<commit_after>/**
 * Copyright 2015, Symantec Corporation
 * All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree
 */

'use strict';
/*jshint bitwise: false */

/**
 *  @ngdoc directive
 *  @name zeus.widgets.directive:zsSimpleToggle
 *  @restrict E
 *
 *  @description
 *
 *  This provides the toggle componant which can be used as checkbox and customize
 *  with color, click callback etc.
 *
 *  @scope
 *
 *  @param {string=} text Sets the display text for toggle button.
 *  @param {boolean=} state Set/get the current state of the toggler. Also can set
 *  default state to true/false.
 *  @param {Number=} lighten Lignten ratio for mouseover background color. Can
 *  @param {string=} switch-color Accept color code and get applied to border, checkmark
 *  etc
 *  @param {boolean=} inactive This disables the toggler and hide the border
 *  @param {function()=} zsChange Callback function to handle change event from
 *  controller.
 *  @example
<example module="zeus.widgets">
    <file name="index.html">

            <zs-simple-toggle text="{{ toggle.label }}"
                switch-color="#9c27b0"
                lighten="50"
                zs-change="clickMe()"
                state="toggle.state">
            </zs-simple-toggle>

            <zs-simple-toggle text="Inactive"
                switch-color="#12287E"
                state="true"
                inactive="true">
            </zs-simple-toggle>

    </file>
    <file name="myCtrl.js">
        angular.module( 'zeus.widgets' ).controller( 'myCtrl', function ( $scope ) {

            $scope.toggle = {
                label: "Demo Label",
                state: false
            };

            $scope.clickMe = function () {
                alert( 'You clicked Me...!!!' );
            };

        } );
    </file>
</example>
 */

angular.module( 'zeus.widgets' )
  .directive( 'zsSimpleToggle', [ function () {
    return {
        templateUrl: 'html/simple_toggle.html',
        restrict: 'E',
        replace: true,
        scope: {
            text: '@',
            state: '=?',
            lighten: '@',
            color: '@switchColor',
            zsChange: '&',
            inactive: '@'
        },

        link: function ( scope, element ) {
            var wrap = $( element ),
                icon = wrap.find( '[data-role="icon"]' ),
                toggleState,
                recalcStyles,
                attachEvents,
                lighten;

            lighten = function ( col, amt ) {
                var usePound = false,
                    num, r, b, g;

                if ( col[ 0 ] === '#' ) {
                    col = col.slice( 1 );
                    usePound = true;
                }

                num = parseInt( col, 16 );
                r = ( num >> 16 ) + amt;

                if ( r > 255 ) {
                    r = 255;
                } else if ( r < 0 ) {
                    r = 0;
                }

                b = ( ( num >> 8 ) & 0x00FF ) + amt;

                if ( b > 255 ) {
                    b = 255;
                } else if ( b < 0 ) {
                    b = 0;
                }

                g = ( num & 0x0000FF ) + amt;

                if ( g > 255 ) {
                    g = 255;
                } else if ( g < 0 ) {
                    g = 0;
                }

                return ( usePound ? '#' : '' ) +
                    ( g | ( b << 8 ) | ( r << 16 ) ).toString( 16 );
            };

            // Handler for state toggle.
            // Fired on click of slider
            toggleState = function () {
                scope.state = !scope.state;

                if ( scope.zsChange ) {
                    scope.zsChange();
                }

                recalcStyles();
            };

            attachEvents = function () {
                icon.css( {
                    borderColor: scope.color
                } );

                wrap.css( {
                    borderColor: scope.color
                } );

                wrap.click( function () {
                    scope.$apply( function () {
                        toggleState();
                    } );
                } );

                wrap.mouseover( function () {
                    $( this ).css( {
                        backgroundColor: lighten( scope.color, +( scope.lighten ) )
                    } );
                } );

                wrap.mouseout( function () {
                    $( this ).css( {
                        backgroundColor: '#FFF'
                    } );
                } );
            };

            recalcStyles = function () {
                var bgColor = '#FFF';

                if ( scope.state ) {
                    wrap.addClass( 'state-on' );
                    wrap.removeClass( 'state-off' );
                    bgColor = scope.color;

                } else {
                    wrap.addClass( 'state-off' );
                    wrap.removeClass( 'state-on' );
                }

                icon.css( {
                    backgroundColor: bgColor
                } );
            };

            scope.state = scope.state || false;

            if ( !scope.inactive ) {
                recalcStyles();
                attachEvents();
            } else {
                wrap.addClass( 'state-inactive' );
            }
            // Watch for changes in state
            scope.$watch( 'state', function () {
                recalcStyles();
            } );
        }
    };
} ] );
<|endoftext|>


<commit_before>#X-Generator: crowdin.net
*=limitaciones de la licencia.
//=Permisos
navbar_overview="Informaci\u00f3n General";
navbar_overview_tooltip="Informaci\u00f3n General de los miembros del sitio";
navbar_pics="Fotograf\u00edas";
navbar_pics_tooltip="Ver los miembros del sitio con sus fotograf\u00edas";
navbar_group_membership="Grupos";
navbar_group_membership_tooltip="Ver los miembros del sitio organizados por grupo";
navbar_status="Estado del usuario en el sitio";
navbar_status_tooltip="Ver los miembros del sitio organizados por estado en el sitio";
navbar_permissions="Permisos";
navbar_permissions_tooltip="Ver y editar los permisos de los usuarios para este sitio";
title_overview="Informaci\u00f3n General";
title_pictures="Fotograf\u00edas";
title_group_membership="Grupos";
title_status="Estado del usuario en el sitio";
title_permissions="Permisos por rol";

roster_search_text="Nombre o Identificador";
roster_search_button="Buscar";
roster_clear_button="Limpiar";
roster_sections_all="Todos los grupos";
roster_section_sep_line="---------------------";
roster_group_ungrouped="Sin Grupo";
roster_group_bygroup="Por Grupo";
roster_group_unassigned="Sin Asignar";
roster_enrollment_status_all="Todos";
currently_displaying_participants="Mostrando {0} participantes";
currently_displaying_participant="Mostrando {0} participante";
role_breakdown_fragment="{0} con el rol {1}";
enrollments_currently_displaying="Mostrando {0} {1} estudiantes";
section_filter_pre="Ver";
section_filter_post="Participantes";
enrollment_status_filter="Ver estudiantes en";
enrollment_status_filter_label="Estado en el sitio";
view_table="Ver en tabla";
view_single="Ver en una columna";
print_roster="Imprimir";
export_roster="Exportar";
roster_show_names="Mostrar Nombres";
roster_hide_names="Ocultar Nombres";
roster_show_official_pictures="Fotograf\u00edas Oficiales";
roster_show_profile_pictures="Fotograf\u00edas del Perfil";
show_profile="Ver el perfil de este participante";
profile_connection_accept="Aceptar contacto";
profile_connection_add="A\u00f1adir contacto";
profile_connection_remove="Eliminar contacto";
profile_connection_requested="Contacto solicitado";
profile_connection_self="Eres t\u00fa\!"
profile_email="Correo Electr\u00f3nico";
profile_picture_alt="Foto de";
facet_name="Nombre";
facet_userId="Identificador de usuario";
facet_email="Correo Electr\u00f3nico";
facet_role="Rol";
facet_status="Estado";
facet_credits="Cr\u00e9ditos";
facet_groups="Grupos";
title_msg="Para a\u00f1adir o borrar participantes del sitio, vaya a la herramienta Informaci\u00f3n del Sitio.";
title_msg_groups="Para a\u00f1adir o borrar participantes de Grupos, vaya a la herramienta Informaci\u00f3n del Sitio.";
title_msg_permissions="Definir los permisos para los roles en este sitio."
no_participants="No se han encontrado resultados";
no_participants_msg="No se han encontrado resultados para "{0}"";
no_permission_msg="No tienes permisos para ver la Orla.";
roster_permissions_role="Rol"
roster_save_button="Guardar"
roster_cancel_button="Cancelar"

<commit_msg>SAK-26023 fixed broken build caused by translation<commit_after>//#X-Generator: crowdin.net
//=Permisos
navbar_overview="Informaci\u00f3n General";
navbar_overview_tooltip="Informaci\u00f3n General de los miembros del sitio";
navbar_pics="Fotograf\u00edas";
navbar_pics_tooltip="Ver los miembros del sitio con sus fotograf\u00edas";
navbar_group_membership="Grupos";
navbar_group_membership_tooltip="Ver los miembros del sitio organizados por grupo";
navbar_status="Estado del usuario en el sitio";
navbar_status_tooltip="Ver los miembros del sitio organizados por estado en el sitio";
navbar_permissions="Permisos";
navbar_permissions_tooltip="Ver y editar los permisos de los usuarios para este sitio";
title_overview="Informaci\u00f3n General";
title_pictures="Fotograf\u00edas";
title_group_membership="Grupos";
title_status="Estado del usuario en el sitio";
title_permissions="Permisos por rol";

roster_search_text="Nombre o Identificador";
roster_search_button="Buscar";
roster_clear_button="Limpiar";
roster_sections_all="Todos los grupos";
roster_section_sep_line="---------------------";
roster_group_ungrouped="Sin Grupo";
roster_group_bygroup="Por Grupo";
roster_group_unassigned="Sin Asignar";
roster_enrollment_status_all="Todos";
currently_displaying_participants="Mostrando {0} participantes";
currently_displaying_participant="Mostrando {0} participante";
role_breakdown_fragment="{0} con el rol {1}";
enrollments_currently_displaying="Mostrando {0} {1} estudiantes";
section_filter_pre="Ver";
section_filter_post="Participantes";
enrollment_status_filter="Ver estudiantes en";
enrollment_status_filter_label="Estado en el sitio";
view_table="Ver en tabla";
view_single="Ver en una columna";
print_roster="Imprimir";
export_roster="Exportar";
roster_show_names="Mostrar Nombres";
roster_hide_names="Ocultar Nombres";
roster_show_official_pictures="Fotograf\u00edas Oficiales";
roster_show_profile_pictures="Fotograf\u00edas del Perfil";
show_profile="Ver el perfil de este participante";
profile_connection_accept="Aceptar contacto";
profile_connection_add="A\u00f1adir contacto";
profile_connection_remove="Eliminar contacto";
profile_connection_requested="Contacto solicitado";
profile_connection_self="Eres t\u00fa\!"
profile_email="Correo Electr\u00f3nico";
profile_picture_alt="Foto de";
facet_name="Nombre";
facet_userId="Identificador de usuario";
facet_email="Correo Electr\u00f3nico";
facet_role="Rol";
facet_status="Estado";
facet_credits="Cr\u00e9ditos";
facet_groups="Grupos";
title_msg="Para a\u00f1adir o borrar participantes del sitio, vaya a la herramienta Informaci\u00f3n del Sitio.";
title_msg_groups="Para a\u00f1adir o borrar participantes de Grupos, vaya a la herramienta Informaci\u00f3n del Sitio.";
title_msg_permissions="Definir los permisos para los roles en este sitio."
no_participants="No se han encontrado resultados";
no_participants_msg="No se han encontrado resultados para \"{0}\"";
no_permission_msg="No tienes permisos para ver la Orla.";
roster_permissions_role="Rol"
roster_save_button="Guardar"
roster_cancel_button="Cancelar"

<|endoftext|>


<commit_before>if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define([], function() {
var suites = [];

suites.push({
  name: "WebSocket tests",
  desc: "collection of tests to test WebSocket communication",
  setup: function(env) {
    env.expected = { // struct of expected results for each http call
      setupTest: 'setupTest',
      test: {
        foo: "bar"
      },
      footwear: {
        leather: "boots",
        flip: "flops",
        block: "of wood"
      }
    };

    var client = new this.WebSocketClient({
      url: 'ws://localhost:9992/',
      type: 'echo-protocol',
      messages: env.expected // used for auto verification (if specified
                   // by using the sendAndVerify() method in the
                   // test).
    });
    var server = new this.WebSocketServer({
      port: 9992,
      messages: env.expected
    });

    var _this = this;
    server.run(function() {
      _this.write('websocket dummy server running');
      // setup client
      client.connect(function(connection) {
        env.connection = connection;
        env.connection.sendAndVerify('setupTest', _this);
      });
    });
  },
  tests: [
    {
      desc: "first test",
      run: function(env) {
        this.assertAnd(env.connection.connected, true);
        env.connection.sendAndVerify('test', this);
      }
    },
    {
      desc: "complex data struct",
      run: function(env) {
        env.connection.sendAndVerify('complex', this);
      }
    },
    {
      desc: "with callback",
      run: function(env) {
        var _this = this;
        env.connection.sendWithCallback('footwear', function(data) {
          _this.assert(data.utf8Data,
                 JSON.stringify(env.expected['footwear']));
        });
      }
    }
  ]
});

return suites;
});<commit_msg>fixed websocket test failure, and added a willFail test<commit_after>if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define([], function() {
var suites = [];

suites.push({
  name: "WebSocket tests",
  desc: "collection of tests to test WebSocket communication",
  setup: function(env) {
    env.expected = { // struct of expected results for each http call
      setupTest: 'setupTest',
      test: {
        foo: "bar"
      },
      footwear: {
        leather: "boots",
        flip: "flops",
        block: "of wood"
      },
      complex: {
        we: "are",
        using: [ "a", "complex", "data"],
        struct: [
          {
            here: "because",
            it: ['makes', 'us', {feel: "better"}, "about"],
          },
          "things"
        ]
      }
    };

    var client = new this.WebSocketClient({
      url: 'ws://localhost:9992/',
      type: 'echo-protocol',
      messages: env.expected // used for auto verification (if specified
                   // by using the sendAndVerify() method in the
                   // test).
    });
    var server = new this.WebSocketServer({
      port: 9992,
      messages: env.expected
    });

    var _this = this;
    server.run(function() {
      _this.write('websocket dummy server running');
      // setup client
      client.connect(function(connection) {
        env.connection = connection;
        env.connection.sendAndVerify('setupTest', _this);
      });
    });
  },
  tests: [
    {
      desc: "first test",
      run: function(env) {
        this.assertAnd(env.connection.connected, true);
        env.connection.sendAndVerify('test', this);
      }
    },
    {
      desc: "complex data struct",
      run: function(env) {
        env.connection.sendAndVerify('complex', this);
      }
    },
    {
      desc: "with callback",
      run: function(env) {
        var _this = this;
        env.connection.sendWithCallback('footwear', function(data) {
          _this.assert(data.utf8Data,
                 JSON.stringify(env.expected['footwear']));
        });
      }
    },
    {
      desc: 'lets try to fail! how exciting!',
      willFail: true,
      run: function(env) {
        env.connection.sendAndVerify('dontexist', this);
      }
    }
  ]
});

return suites;
});<|endoftext|>


<commit_before>/**
 * @class Box
 * @extends Geometry
 */

EZ3.Box = function(dimensions, resolution) {
  EZ3.Geometry.call(this);

  if (dimensions instanceof EZ3.Vector3)
    this._dimensions = dimensions;
  else
    this._dimensions = new EZ3.Vector3(1, 1, 1);

  if (resolution instanceof EZ3.Vector3)
    this._resolution = resolution;
  else
    this._resolution = new EZ3.Vector3(1, 1, 1);
};

EZ3.Box.prototype = Object.create(EZ3.Geometry.prototype);
EZ3.Box.prototype.constructor = EZ3.Box;

EZ3.Box.prototype.generate = function() {
  var uvs = [];
  var indices = [];
  var vertices = [];
  var width = this.dimensions.x;
  var height = this.dimensions.y;
  var depth = this.dimensions.z;
  var widthHalf = width * 0.5;
  var depthHalf = depth * 0.5;
  var heightHalf = height * 0.5;
  var need32Bits = false;
  var widthSegments;
  var heightSegments;
  var depthSegments;
  var buffer;
  var length;

  if (this.resolution !== undefined) {
    widthSegments = this.resolution.x;
    heightSegments = this.resolution.y;
    depthSegments = this.resolution.z;
  } else {
    widthSegments = 1;
    heightSegments = 1;
    depthSegments = 1;
  }

  function buildPlane(u, v, udir, vdir, width, height, depth) {
    var gridX = widthSegments;
    var gridY = heightSegments;
    var widthHalf = width * 0.5;
    var heightHalf = height * 0.5;
    var offset = vertices.length / 3;
    var uva = new EZ3.Vector2();
    var uvb = new EZ3.Vector2();
    var uvc = new EZ3.Vector2();
    var uvd = new EZ3.Vector2();
    var vector = new EZ3.Vector3();
    var segmentWidth;
    var segmentHeight;
    var a;
    var b;
    var c;
    var d;
    var w;
    var i;
    var j;

    if ((u === 'x' && v === 'y') || (u === 'y' && v === 'x')) {

      w = 'z';

    } else if ((u === 'x' && v === 'z') || (u === 'z' && v === 'x')) {

      w = 'y';
      gridY = depthSegments;

    } else if ((u === 'z' && v === 'y') || (u === 'y' && v === 'z')) {

      w = 'x';
      gridX = depthSegments;

    }

    segmentWidth = width / gridX;
    segmentHeight = height / gridY;

    for (i = 0; i < gridY + 1; i++) {
      for (j = 0; j < gridX + 1; j++) {
        vector[u] = (j * segmentWidth - widthHalf) * udir;
        vector[v] = (i * segmentHeight - heightHalf) * vdir;
        vector[w] = depth;

        vertices.push(vector.x, vector.y, vector.z);
      }
    }

    for (i = 0; i < gridY; ++i) {
      for (j = 0; j < gridX; ++j) {

        a = offset + (i * (gridX + 1) + j);
        b = offset + (i * (gridX + 1) + (j + 1));
        c = offset + ((i + 1) * (gridX + 1) + j);
        d = offset + ((i + 1) * (gridX + 1) + (j + 1));

        uva.set(j / gridX, i / gridY);
        uvb.set((j + 1) / gridX, i / gridY);
        uvc.set(j / gridX, (i + 1) / gridY);
        uvd.set((j + 1) / gridX, (i + 1) / gridY);

        indices.push(a, c, b, c, d, b);

        uvs.push(uva.x, uva.y, uvb.x, uvb.y, uvd.x, uvd.y);
        uvs.push(uvb.x, uvb.y, uvc.x, uvc.y, uvd.x, uvd.y);

        if (!need32Bits) {
          length = indices.length;
          need32Bits = need32Bits ||
            (a > EZ3.Math.MAX_USHORT) ||
            (b > EZ3.Math.MAX_USHORT) ||
            (c > EZ3.Math.MAX_USHORT) ||
            (d > EZ3.Math.MAX_USHORT);
        }
      }
    }
  }

  buildPlane('z', 'y', -1, -1, depth, height, +widthHalf);
  buildPlane('z', 'y', +1, -1, depth, height, -widthHalf);
  buildPlane('x', 'z', +1, +1, width, depth, +heightHalf);
  buildPlane('x', 'z', +1, -1, width, depth, -heightHalf);
  buildPlane('x', 'y', +1, -1, width, height, +depthHalf);
  buildPlane('x', 'y', -1, -1, width, height, -depthHalf);

  buffer = new EZ3.IndexBuffer(indices, false, need32Bits);
  this.buffers.add('triangle', buffer);

  buffer = new EZ3.VertexBuffer(uvs, false);
  buffer.addAttribute('uv', new EZ3.VertexBufferAttribute(2));
  this.buffers.add('uv', buffer);

  buffer = new EZ3.VertexBuffer(vertices, false);
  buffer.addAttribute('position', new EZ3.VertexBufferAttribute(3));
  this.buffers.add('position', buffer);

  this.mergeVertices();
};

Object.defineProperty(EZ3.Box.prototype, 'dimensions', {
  get: function() {
    return this._dimensions;
  },
  set: function(dimensions) {
    if (dimensions instanceof EZ3.Vector3) {
      this._dimensions = dimensions;
    }
  }
});

Object.defineProperty(EZ3.Box.prototype, 'resolution', {
  get: function() {
    return this._resolution;
  },
  set: function(resolution) {
    if (resolution instanceof EZ3.Vector3) {
      this._resolution.copy(resolution);
    }
  }
});

Object.defineProperty(EZ3.Box.prototype, 'regenerate', {
  get: function() {
    return this.dimensions.dirty || this.resolution.dirty;
  },
  set: function(regenerate) {
    this.dimensions.dirty = regenerate;
    this.resolution.dirty = regenerate;
  }
});
<commit_msg>Updated Box.js UVs<commit_after>/**
 * @class Box
 * @extends Geometry
 */

EZ3.Box = function(dimensions, resolution) {
  EZ3.Geometry.call(this);

  if (dimensions instanceof EZ3.Vector3)
    this._dimensions = dimensions;
  else
    this._dimensions = new EZ3.Vector3(1, 1, 1);

  if (resolution instanceof EZ3.Vector3)
    this._resolution = resolution;
  else
    this._resolution = new EZ3.Vector3(1, 1, 1);
};

EZ3.Box.prototype = Object.create(EZ3.Geometry.prototype);
EZ3.Box.prototype.constructor = EZ3.Box;

EZ3.Box.prototype.generate = function() {
  var uvs = [];
  var indices = [];
  var vertices = [];
  var width = this.dimensions.x;
  var height = this.dimensions.y;
  var depth = this.dimensions.z;
  var widthHalf = width * 0.5;
  var depthHalf = depth * 0.5;
  var heightHalf = height * 0.5;
  var need32Bits = false;
  var widthSegments;
  var heightSegments;
  var depthSegments;
  var buffer;
  var length;

  if (this.resolution !== undefined) {
    widthSegments = this.resolution.x;
    heightSegments = this.resolution.y;
    depthSegments = this.resolution.z;
  } else {
    widthSegments = 1;
    heightSegments = 1;
    depthSegments = 1;
  }

  function buildPlane(u, v, udir, vdir, width, height, depth) {
    var gridX = widthSegments;
    var gridY = heightSegments;
    var widthHalf = width * 0.5;
    var heightHalf = height * 0.5;
    var offset = vertices.length / 3;
    var uva = new EZ3.Vector2();
    var uvb = new EZ3.Vector2();
    var uvc = new EZ3.Vector2();
    var uvd = new EZ3.Vector2();
    var vector = new EZ3.Vector3();
    var segmentWidth;
    var segmentHeight;
    var a;
    var b;
    var c;
    var d;
    var w;
    var i;
    var j;

    if ((u === 'x' && v === 'y') || (u === 'y' && v === 'x')) {

      w = 'z';

    } else if ((u === 'x' && v === 'z') || (u === 'z' && v === 'x')) {

      w = 'y';
      gridY = depthSegments;

    } else if ((u === 'z' && v === 'y') || (u === 'y' && v === 'z')) {

      w = 'x';
      gridX = depthSegments;

    }

    segmentWidth = width / gridX;
    segmentHeight = height / gridY;

    for (i = 0; i < gridY + 1; i++) {
      for (j = 0; j < gridX + 1; j++) {
        vector[u] = (j * segmentWidth - widthHalf) * udir;
        vector[v] = (i * segmentHeight - heightHalf) * vdir;
        vector[w] = depth;

        vertices.push(vector.x, vector.y, vector.z);
      }
    }

    for (i = 0; i < gridY; ++i) {
      for (j = 0; j < gridX; ++j) {

        a = offset + (i * (gridX + 1) + j);
        b = offset + (i * (gridX + 1) + (j + 1));
        c = offset + ((i + 1) * (gridX + 1) + j);
        d = offset + ((i + 1) * (gridX + 1) + (j + 1));

        uva.set(j / gridX, i / gridY);
        uvb.set((j + 1) / gridX, i / gridY);
        uvc.set(j / gridX, (i + 1) / gridY);
        uvd.set((j + 1) / gridX, (i + 1) / gridY);

        indices.push(a, c, b, c, d, b);

        uvs.push(uva.x, uva.y, uvc.x, uvc.y, uvb.x, uvb.y);
        uvs.push(uvc.x, uvc.y, uvd.x, uvd.y, uvb.x, uvb.y);

        if (!need32Bits) {
          length = indices.length;
          need32Bits = need32Bits ||
            (a > EZ3.Math.MAX_USHORT) ||
            (b > EZ3.Math.MAX_USHORT) ||
            (c > EZ3.Math.MAX_USHORT) ||
            (d > EZ3.Math.MAX_USHORT);
        }
      }
    }
  }

  buildPlane('z', 'y', -1, -1, depth, height, +widthHalf);
  buildPlane('z', 'y', +1, -1, depth, height, -widthHalf);
  buildPlane('x', 'z', +1, +1, width, depth, +heightHalf);
  buildPlane('x', 'z', +1, -1, width, depth, -heightHalf);
  buildPlane('x', 'y', +1, -1, width, height, +depthHalf);
  buildPlane('x', 'y', -1, -1, width, height, -depthHalf);

  buffer = new EZ3.IndexBuffer(indices, false, need32Bits);
  this.buffers.add('triangle', buffer);

  buffer = new EZ3.VertexBuffer(uvs, false);
  buffer.addAttribute('uv', new EZ3.VertexBufferAttribute(2));
  this.buffers.add('uv', buffer);

  buffer = new EZ3.VertexBuffer(vertices, false);
  buffer.addAttribute('position', new EZ3.VertexBufferAttribute(3));
  this.buffers.add('position', buffer);

  this.mergeVertices();
};

Object.defineProperty(EZ3.Box.prototype, 'dimensions', {
  get: function() {
    return this._dimensions;
  },
  set: function(dimensions) {
    if (dimensions instanceof EZ3.Vector3) {
      this._dimensions = dimensions;
    }
  }
});

Object.defineProperty(EZ3.Box.prototype, 'resolution', {
  get: function() {
    return this._resolution;
  },
  set: function(resolution) {
    if (resolution instanceof EZ3.Vector3) {
      this._resolution.copy(resolution);
    }
  }
});

Object.defineProperty(EZ3.Box.prototype, 'regenerate', {
  get: function() {
    return this.dimensions.dirty || this.resolution.dirty;
  },
  set: function(regenerate) {
    this.dimensions.dirty = regenerate;
    this.resolution.dirty = regenerate;
  }
});
<|endoftext|>


<commit_before>// FIXME works for View2D only

goog.provide('ol.control.Zoom');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.View2D');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * Create a new control with 2 buttons, one for zoom in and one for zoom out.
 * This control is part of the default controls of a map. To style this control
 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomOptions=} opt_options Zoom options.
 * @todo stability experimental
 */
ol.control.Zoom = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  var className = goog.isDef(options.className) ? options.className : 'ol-zoom';

  var delta = goog.isDef(options.delta) ? options.delta : 1;

  var zoomInLabel = goog.isDef(options.zoomInLabel) ?
      options.zoomInLabel : '+';
  var zoomOutLabel = goog.isDef(options.zoomOutLabel) ?
      options.zoomOutLabel : '\u2212';

  var zoomInTipLabel = goog.isDef(options.zoomTipLabel) ?
      options.zoomInTipLabel : 'Zoom in';
  var zoomOutTipLabel = goog.isDef(options.zoomOutTipLabel) ?
      options.zoomOutTipLabel : 'Zoom out';

  var tTipZoomIn = goog.dom.createDom(goog.dom.TagName.SPAN, {
    'role' : 'tooltip'
  }, zoomInTipLabel);
  var inElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
    'class': className + '-in ol-has-tooltip',
    'name' : 'ZoomIn',
    'type' : 'button'
  }, tTipZoomIn, zoomInLabel);

  goog.events.listen(inElement, [
    goog.events.EventType.TOUCHEND,
    goog.events.EventType.CLICK
  ], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this);

  var tTipsZoomOut = goog.dom.createDom(goog.dom.TagName.SPAN, {
    'role' : 'tooltip',
    'type' : 'button'
  }, zoomOutTipLabel);
  var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
    'class': className + '-out  ol-has-tooltip',
    'name' : 'ZoomOut'
  }, tTipsZoomOut, zoomOutLabel);
  goog.events.listen(outElement, [
    goog.events.EventType.TOUCHEND,
    goog.events.EventType.CLICK
  ], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, -delta), false, this);

  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE;
  var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
      outElement);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @type {number}
   * @private
   */
  this.duration_ = goog.isDef(options.duration) ? options.duration : 250;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {number} delta Zoom delta.
 * @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
 * @private
 */
ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) {
  browserEvent.preventDefault();
  // prevent the anchor from getting appended to the url
  var map = this.getMap();
  // FIXME works for View2D only
  var view = map.getView();
  goog.asserts.assert(goog.isDef(view));
  var view2D = view.getView2D();
  goog.asserts.assertInstanceof(view2D, ol.View2D);
  var currentResolution = view2D.getResolution();
  if (goog.isDef(currentResolution)) {
    if (this.duration_ > 0) {
      map.beforeRender(ol.animation.zoom({
        resolution: currentResolution,
        duration: this.duration_,
        easing: ol.easing.easeOut
      }));
    }
    var newResolution = view2D.constrainResolution(currentResolution, delta);
    view2D.setResolution(newResolution);
  }
};
<commit_msg>Fix option name zoomInTipLabel<commit_after>// FIXME works for View2D only

goog.provide('ol.control.Zoom');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.View2D');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * Create a new control with 2 buttons, one for zoom in and one for zoom out.
 * This control is part of the default controls of a map. To style this control
 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomOptions=} opt_options Zoom options.
 * @todo stability experimental
 */
ol.control.Zoom = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  var className = goog.isDef(options.className) ? options.className : 'ol-zoom';

  var delta = goog.isDef(options.delta) ? options.delta : 1;

  var zoomInLabel = goog.isDef(options.zoomInLabel) ?
      options.zoomInLabel : '+';
  var zoomOutLabel = goog.isDef(options.zoomOutLabel) ?
      options.zoomOutLabel : '\u2212';

  var zoomInTipLabel = goog.isDef(options.zoomInTipLabel) ?
      options.zoomInTipLabel : 'Zoom in';
  var zoomOutTipLabel = goog.isDef(options.zoomOutTipLabel) ?
      options.zoomOutTipLabel : 'Zoom out';

  var tTipZoomIn = goog.dom.createDom(goog.dom.TagName.SPAN, {
    'role' : 'tooltip'
  }, zoomInTipLabel);
  var inElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
    'class': className + '-in ol-has-tooltip',
    'name' : 'ZoomIn',
    'type' : 'button'
  }, tTipZoomIn, zoomInLabel);

  goog.events.listen(inElement, [
    goog.events.EventType.TOUCHEND,
    goog.events.EventType.CLICK
  ], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this);

  var tTipsZoomOut = goog.dom.createDom(goog.dom.TagName.SPAN, {
    'role' : 'tooltip',
    'type' : 'button'
  }, zoomOutTipLabel);
  var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
    'class': className + '-out  ol-has-tooltip',
    'name' : 'ZoomOut'
  }, tTipsZoomOut, zoomOutLabel);
  goog.events.listen(outElement, [
    goog.events.EventType.TOUCHEND,
    goog.events.EventType.CLICK
  ], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, -delta), false, this);

  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE;
  var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
      outElement);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @type {number}
   * @private
   */
  this.duration_ = goog.isDef(options.duration) ? options.duration : 250;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {number} delta Zoom delta.
 * @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
 * @private
 */
ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) {
  browserEvent.preventDefault();
  // prevent the anchor from getting appended to the url
  var map = this.getMap();
  // FIXME works for View2D only
  var view = map.getView();
  goog.asserts.assert(goog.isDef(view));
  var view2D = view.getView2D();
  goog.asserts.assertInstanceof(view2D, ol.View2D);
  var currentResolution = view2D.getResolution();
  if (goog.isDef(currentResolution)) {
    if (this.duration_ > 0) {
      map.beforeRender(ol.animation.zoom({
        resolution: currentResolution,
        duration: this.duration_,
        easing: ol.easing.easeOut
      }));
    }
    var newResolution = view2D.constrainResolution(currentResolution, delta);
    view2D.setResolution(newResolution);
  }
};
<|endoftext|>


<commit_before>goog.provide('ol.control.Zoom');

goog.require('goog.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * @classdesc
 * A control with 2 buttons, one for zoom in and one for zoom out.
 * This control is one of the default controls of a map. To style this control
 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomOptions=} opt_options Zoom options.
 * @api stable
 */
ol.control.Zoom = function(opt_options) {

  var options = opt_options ? opt_options : {};

  var className = options.className ? options.className : 'ol-zoom';

  var delta = options.delta ? options.delta : 1;

  var zoomInLabel = options.zoomInLabel ? options.zoomInLabel : '+';
  var zoomOutLabel = options.zoomOutLabel ? options.zoomOutLabel : '\u2212';

  var zoomInTipLabel = options.zoomInTipLabel ?
      options.zoomInTipLabel : 'Zoom in';
  var zoomOutTipLabel = options.zoomOutTipLabel ?
      options.zoomOutTipLabel : 'Zoom out';

  var inElement = goog.dom.createDom('BUTTON', {
    'class': className + '-in',
    'type' : 'button',
    'title': zoomInTipLabel
  }, zoomInLabel);

  ol.events.listen(inElement,
      ol.events.EventType.CLICK, goog.partial(
          ol.control.Zoom.prototype.handleClick_, delta), this);

  var outElement = goog.dom.createDom('BUTTON', {
    'class': className + '-out',
    'type' : 'button',
    'title': zoomOutTipLabel
  }, zoomOutLabel);

  ol.events.listen(outElement,
      ol.events.EventType.CLICK, goog.partial(
          ol.control.Zoom.prototype.handleClick_, -delta), this);

  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
      ol.css.CLASS_CONTROL;
  var element = goog.dom.createDom('DIV', cssClasses, inElement, outElement);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @type {number}
   * @private
   */
  this.duration_ = options.duration !== undefined ? options.duration : 250;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {number} delta Zoom delta.
 * @param {Event} event The event to handle
 * @private
 */
ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
  event.preventDefault();
  this.zoomByDelta_(delta);
};

/**
 * @param {number} delta Zoom delta.
 * @private
 */
ol.control.Zoom.prototype.zoomByDelta_ = function(delta) {
  var map = this.getMap();
  var view = map.getView();
  if (!view) {
    // the map does not have a view, so we can't act
    // upon it
    return;
  }
  var currentResolution = view.getResolution();
  if (currentResolution) {
    if (this.duration_ > 0) {
      map.beforeRender(ol.animation.zoom({
        resolution: currentResolution,
        duration: this.duration_,
        easing: ol.easing.easeOut
      }));
    }
    var newResolution = view.constrainResolution(currentResolution, delta);
    view.setResolution(newResolution);
  }
};
<commit_msg>Fix checks for undefined in zoom control<commit_after>goog.provide('ol.control.Zoom');

goog.require('goog.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * @classdesc
 * A control with 2 buttons, one for zoom in and one for zoom out.
 * This control is one of the default controls of a map. To style this control
 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomOptions=} opt_options Zoom options.
 * @api stable
 */
ol.control.Zoom = function(opt_options) {

  var options = opt_options ? opt_options : {};

  var className = options.className !== undefined ? options.className : 'ol-zoom';

  var delta = options.delta !== undefined ? options.delta : 1;

  var zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';
  var zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212';

  var zoomInTipLabel = options.zoomInTipLabel !== undefined ?
      options.zoomInTipLabel : 'Zoom in';
  var zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?
      options.zoomOutTipLabel : 'Zoom out';

  var inElement = goog.dom.createDom('BUTTON', {
    'class': className + '-in',
    'type' : 'button',
    'title': zoomInTipLabel
  }, zoomInLabel);

  ol.events.listen(inElement,
      ol.events.EventType.CLICK, goog.partial(
          ol.control.Zoom.prototype.handleClick_, delta), this);

  var outElement = goog.dom.createDom('BUTTON', {
    'class': className + '-out',
    'type' : 'button',
    'title': zoomOutTipLabel
  }, zoomOutLabel);

  ol.events.listen(outElement,
      ol.events.EventType.CLICK, goog.partial(
          ol.control.Zoom.prototype.handleClick_, -delta), this);

  var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
      ol.css.CLASS_CONTROL;
  var element = goog.dom.createDom('DIV', cssClasses, inElement, outElement);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @type {number}
   * @private
   */
  this.duration_ = options.duration !== undefined ? options.duration : 250;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {number} delta Zoom delta.
 * @param {Event} event The event to handle
 * @private
 */
ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
  event.preventDefault();
  this.zoomByDelta_(delta);
};

/**
 * @param {number} delta Zoom delta.
 * @private
 */
ol.control.Zoom.prototype.zoomByDelta_ = function(delta) {
  var map = this.getMap();
  var view = map.getView();
  if (!view) {
    // the map does not have a view, so we can't act
    // upon it
    return;
  }
  var currentResolution = view.getResolution();
  if (currentResolution) {
    if (this.duration_ > 0) {
      map.beforeRender(ol.animation.zoom({
        resolution: currentResolution,
        duration: this.duration_,
        easing: ol.easing.easeOut
      }));
    }
    var newResolution = view.constrainResolution(currentResolution, delta);
    view.setResolution(newResolution);
  }
};
<|endoftext|>


<commit_before>/**
 * @module ol/interaction/DragPan
 */
import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js';
import {easeOut} from '../easing.js';
import {noModifierKeys} from '../events/condition.js';
import {FALSE} from '../functions.js';
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';

/**
 * @typedef {Object} Options
 * @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
 * to indicate whether that event should be handled.
 * Default is {@link module:ol/events/condition~noModifierKeys}.
 * @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
 */

/**
 * @classdesc
 * Allows the user to pan the map by dragging the map.
 * @api
 */
class DragPan extends PointerInteraction {
  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    super({
      stopDown: FALSE
    });

    const options = opt_options ? opt_options : {};

    /**
     * @private
     * @type {import("../Kinetic.js").default|undefined}
     */
    this.kinetic_ = options.kinetic;

    /**
     * @type {import("../pixel.js").Pixel}
     */
    this.lastCentroid = null;

    /**
     * @type {number}
     */
    this.lastPointersCount_;

    /**
     * @type {boolean}
     */
    this.panning_ = false;

    /**
     * @private
     * @type {import("../events/condition.js").Condition}
     */
    this.condition_ = options.condition ? options.condition : noModifierKeys;

    /**
     * @private
     * @type {boolean}
     */
    this.noKinetic_ = false;

  }

  /**
   * @inheritDoc
   */
  handleDragEvent(mapBrowserEvent) {
    if (!this.panning_) {
      this.panning_ = true;
      this.getMap().getView().beginInteraction();
    }
    const targetPointers = this.targetPointers;
    const centroid = centroidFromPointers(targetPointers);
    if (targetPointers.length == this.lastPointersCount_) {
      if (this.kinetic_) {
        this.kinetic_.update(centroid[0], centroid[1]);
      }
      if (this.lastCentroid) {
        const delta = [
          this.lastCentroid[0] - centroid[0],
          centroid[1] - this.lastCentroid[1]
        ];
        const map = mapBrowserEvent.map;
        const view = map.getView();
        scaleCoordinate(delta, view.getResolution());
        rotateCoordinate(delta, view.getRotation());
        view.adjustCenter(delta);
      }
    } else if (this.kinetic_) {
      // reset so we don't overestimate the kinetic energy after
      // after one finger down, tiny drag, second finger down
      this.kinetic_.begin();
    }
    this.lastCentroid = centroid;
    this.lastPointersCount_ = targetPointers.length;
  }

  /**
   * @inheritDoc
   */
  handleUpEvent(mapBrowserEvent) {
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (this.targetPointers.length === 0) {
      if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
        const distance = this.kinetic_.getDistance();
        const angle = this.kinetic_.getAngle();
        const center = /** @type {!import("../coordinate.js").Coordinate} */ (view.getCenter());
        const centerpx = map.getPixelFromCoordinate(center);
        const dest = map.getCoordinateFromPixel([
          centerpx[0] - distance * Math.cos(angle),
          centerpx[1] - distance * Math.sin(angle)
        ]);
        view.animate({
          center: view.getConstrainedCenter(dest),
          duration: 500,
          easing: easeOut
        });
      }
      if (this.panning_) {
        this.panning_ = false;
        view.endInteraction();
      }
      return false;
    } else {
      if (this.kinetic_) {
        // reset so we don't overestimate the kinetic energy after
        // after one finger up, tiny drag, second finger up
        this.kinetic_.begin();
      }
      this.lastCentroid = null;
      return true;
    }
  }

  /**
   * @inheritDoc
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      this.lastCentroid = null;
      // stop any current animation
      if (view.getAnimating()) {
        view.cancelAnimations();
      }
      if (this.kinetic_) {
        this.kinetic_.begin();
      }
      // No kinetic as soon as more than one pointer on the screen is
      // detected. This is to prevent nasty pans after pinch.
      this.noKinetic_ = this.targetPointers.length > 1;
      return true;
    } else {
      return false;
    }
  }
}

export default DragPan;
<commit_msg>Add primaryAction condition to DragPan interaction<commit_after>/**
 * @module ol/interaction/DragPan
 */
import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js';
import {easeOut} from '../easing.js';
import {noModifierKeys, primaryAction} from '../events/condition.js';
import {FALSE} from '../functions.js';
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';

/**
 * @typedef {Object} Options
 * @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
 * to indicate whether that event should be handled.
 * Default is {@link module:ol/events/condition~noModifierKeys} and {@link module:ol/events/condition~primaryAction}.
 * @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
 */

/**
 * @classdesc
 * Allows the user to pan the map by dragging the map.
 * @api
 */
class DragPan extends PointerInteraction {
  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    super({
      stopDown: FALSE
    });

    const options = opt_options ? opt_options : {};

    /**
     * @private
     * @type {import("../Kinetic.js").default|undefined}
     */
    this.kinetic_ = options.kinetic;

    /**
     * @type {import("../pixel.js").Pixel}
     */
    this.lastCentroid = null;

    /**
     * @type {number}
     */
    this.lastPointersCount_;

    /**
     * @type {boolean}
     */
    this.panning_ = false;

    /**
     * @private
     * @type {import("../events/condition.js").Condition}
     */
    this.condition_ = options.condition ? options.condition : defaultCondition;

    /**
     * @private
     * @type {boolean}
     */
    this.noKinetic_ = false;

  }

  /**
   * @inheritDoc
   */
  handleDragEvent(mapBrowserEvent) {
    if (!this.panning_) {
      this.panning_ = true;
      this.getMap().getView().beginInteraction();
    }
    const targetPointers = this.targetPointers;
    const centroid = centroidFromPointers(targetPointers);
    if (targetPointers.length == this.lastPointersCount_) {
      if (this.kinetic_) {
        this.kinetic_.update(centroid[0], centroid[1]);
      }
      if (this.lastCentroid) {
        const delta = [
          this.lastCentroid[0] - centroid[0],
          centroid[1] - this.lastCentroid[1]
        ];
        const map = mapBrowserEvent.map;
        const view = map.getView();
        scaleCoordinate(delta, view.getResolution());
        rotateCoordinate(delta, view.getRotation());
        view.adjustCenter(delta);
      }
    } else if (this.kinetic_) {
      // reset so we don't overestimate the kinetic energy after
      // after one finger down, tiny drag, second finger down
      this.kinetic_.begin();
    }
    this.lastCentroid = centroid;
    this.lastPointersCount_ = targetPointers.length;
  }

  /**
   * @inheritDoc
   */
  handleUpEvent(mapBrowserEvent) {
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (this.targetPointers.length === 0) {
      if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
        const distance = this.kinetic_.getDistance();
        const angle = this.kinetic_.getAngle();
        const center = /** @type {!import("../coordinate.js").Coordinate} */ (view.getCenter());
        const centerpx = map.getPixelFromCoordinate(center);
        const dest = map.getCoordinateFromPixel([
          centerpx[0] - distance * Math.cos(angle),
          centerpx[1] - distance * Math.sin(angle)
        ]);
        view.animate({
          center: view.getConstrainedCenter(dest),
          duration: 500,
          easing: easeOut
        });
      }
      if (this.panning_) {
        this.panning_ = false;
        view.endInteraction();
      }
      return false;
    } else {
      if (this.kinetic_) {
        // reset so we don't overestimate the kinetic energy after
        // after one finger up, tiny drag, second finger up
        this.kinetic_.begin();
      }
      this.lastCentroid = null;
      return true;
    }
  }

  /**
   * @inheritDoc
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      this.lastCentroid = null;
      // stop any current animation
      if (view.getAnimating()) {
        view.cancelAnimations();
      }
      if (this.kinetic_) {
        this.kinetic_.begin();
      }
      // No kinetic as soon as more than one pointer on the screen is
      // detected. This is to prevent nasty pans after pinch.
      this.noKinetic_ = this.targetPointers.length > 1;
      return true;
    } else {
      return false;
    }
  }
}

/**
 * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
 * @return {boolean} Combined condition result.
 */
function defaultCondition(mapBrowserEvent) {
  return noModifierKeys(mapBrowserEvent) && primaryAction(mapBrowserEvent);
}

export default DragPan;
<|endoftext|>