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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */
/*global define, $, window, document */

/**
 * RemoteFunctions define the functions to be executed in the browser. This
 * modules should define a single function that returns an object of all
 * exported functions.
 */
function RemoteFunctions() {
    "use strict";

    // determine the color for a type
    function _typeColor(type, highlight) {
        switch (type) {
        case "html":
            return highlight ? "#eec" : "#ffe";
        case "css":
            return highlight ? "#cee" : "#eff";
        case "js":
            return highlight ? "#ccf" : "#eef";
        default:
            return highlight ? "#ddd" : "#eee";
        }
    }

    // compute the screen offset of an element
    function _screenOffset(element, key) {
        var value = 0;
        while (element) {
            value += element[key];
            element = element.offsetParent;
        }
        return value;
    }

    // set an event on a element
    function _trigger(element, name, value, autoRemove) {
        var key = "data-ld-" + name;
        if (value !== undefined && value !== null) {
            element.setAttribute(key, value);
            if (autoRemove) {
                window.setTimeout(element.removeAttribute.bind(element, key));
            }
        } else {
            element.removeAttribute(key);
        }
    }

    // construct the info menu
    function Menu(element) {
        this.element = element;
        _trigger(this.element, "showgoto", 1, true);
        window.setTimeout(window.remoteShowGoto);
    }

    Menu.prototype = {
        onClick: function (url, event) {
            _trigger(this.element, "goto", url, true);
            this.remove();
        },

        createBody: function () {
            if (this.body) {
                return;
            }

            // compute the position on screen
            var x = _screenOffset(this.element, "offsetLeft");
            var y = _screenOffset(this.element, "offsetTop") + this.element.offsetHeight;

            // create the container
            this.body = document.createElement("div");
            this.body.style.setProperty("z-index", 2147483647);
            this.body.style.setProperty("position", "absolute");
            this.body.style.setProperty("left", x + "px");
            this.body.style.setProperty("top", y + "px");
            this.body.style.setProperty("font-size", "11pt");

            // draw the background
            this.body.style.setProperty("background", "#fff");
            this.body.style.setProperty("border", "1px solid #888");
            this.body.style.setProperty("-webkit-box-shadow", "2px 2px 6px 0px #ccc");
            this.body.style.setProperty("border-radius", "6px");
            this.body.style.setProperty("padding", "6px");
        },

        addItem: function (target) {
            var item = document.createElement("div");
            item.style.setProperty("padding", "2px 6px");
            if (this.body.childNodes.length > 0) {
                item.style.setProperty("border-top", "1px solid #ccc");
            }
            item.style.setProperty("cursor", "pointer");
            item.style.setProperty("background", _typeColor(target.type));
            item.innerHTML = target.name;
            item.addEventListener("click", this.onClick.bind(this, target.url));

            if (target.file) {
                var file = document.createElement("i");
                file.style.setProperty("float", "right");
                file.style.setProperty("margin-left", "12px");
                file.innerHTML = " " + target.file;
                item.appendChild(file);
            }
            this.body.appendChild(item);
        },

        show: function () {
            if (!this.body) {
                this.body = this.createBody();
            }
            if (!this.body.parentNode) {
                document.body.appendChild(this.body);
            }
        },

        remove: function () {
            if (this.body && this.body.parentNode) {
                document.body.removeChild(this.body);
            }
        }

    };

    function Editor(element) {
        this.onBlur = this.onBlur.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);

        this.element = element;
        this.element.setAttribute("contenteditable", "true");
        this.element.focus();
        this.element.addEventListener("blur", this.onBlur);
        this.element.addEventListener("keypress", this.onKeyPress);

        this.revertText = this.element.innerHTML;
    }

    Editor.prototype = {
        onBlur: function (event) {
            this.element.removeAttribute("contenteditable");
            this.element.removeEventListener("blur", this.onBlur);
            this.element.removeEventListener("keypress", this.onKeyPress);
            _trigger(this.element, "edit");
        },

        onKeyPress: function (event) {
            switch (event.which) {
            case 13: // return
                this.element.blur();
                break;
            case 27: // esc
                _trigger(this.element, "edit", this.revertText, true);
                this.element.blur();
                break;
            }
        },

        onChange: function (event) {
            window.setTimeout(_trigger.bind(undefined, this.element, "edit", this.element.innerHTML));
        }
    };

    function Highlight(color, autoclear) {
        this.color = color;
        this.autoclear = !!autoclear;
        this.elements = [];
        this.orgColors = [];
    }

    Highlight.prototype = {
        _elementExists: function (element) {
            var i;
            for (i in this.elements) {
                if (this.elements[i] === element) {
                    return true;
                }
            }
            return false;
        },

        add: function (element) {
            if (this._elementExists(element) || element === document) {
                return;
            }
            if (this.autoclear) {
                this.clear();
            }
            this.elements.push(element);
            this.orgColors.push(element.style.getPropertyValue("background-color"));
            element.style.setProperty("background-color", this.color);
        },

        clear: function () {
            var i;
            for (i in this.elements) {
                var e = this.elements[i];
                e.style.setProperty("background-color", this.orgColors[i]);
            }
            this.elements = [];
            this.orgColors = [];
        }
    };

    var _currentEditor;
    function _toggleEditor(element) {
        _currentEditor = new Editor(element);
    }

    var _currentMenu;
    function _toggleMenu(element) {
        if (_currentMenu) {
            _currentMenu.remove();
        }
        _currentMenu = new Menu(element);
    }

    var _localHighlight;
    var _remoteHighlight;
    var _setup = false;

    /** Event Handlers ***********************************************************/

    function onMouseOver(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.add(event.target);
    }

    function onMouseOut(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.clear();
    }

    function onMouseMove(event) {
        onMouseOver(event);
        document.removeEventListener("mousemove", onMouseMove);
    }

    function onClick(event) {
        if (!event.metaKey) {
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        if (event.altKey) {
            _toggleEditor(event.target);
        } else {
            _toggleMenu(event.target);
        }
    }

    function onKeyUp(event) {
        if (_setup && !event.metaKey) {
            document.removeEventListener("keyup", onKeyUp);
            document.removeEventListener("mouseover", onMouseOver);
            document.removeEventListener("mouseout", onMouseOut);
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("click", onClick);
            _localHighlight.clear();
            _localHighlight = undefined;
            _setup = false;
        }
    }

    function onKeyDown(event) {
        if (!_setup && event.metaKey) {
            document.addEventListener("keyup", onKeyUp);
            document.addEventListener("mouseover", onMouseOver);
            document.addEventListener("mouseout", onMouseOut);
            document.addEventListener("mousemove", onMouseMove);
            document.addEventListener("click", onClick);
            _localHighlight = new Highlight("#ecc");
            _setup = true;
        }
    }

    /** Public Commands **********************************************************/

    // show goto
    function showGoto(targets) {
        if (!_currentMenu) {
            return;
        }
        _currentMenu.createBody();
        var i;
        for (i in targets) {
            _currentMenu.addItem(targets[i]);
        }
        _currentMenu.show();
    }

    // remove active highlights
    function hideHighlight() {
        if (_remoteHighlight) {
            _remoteHighlight.clear();
        }
    }

    // highlight a node
    function highlight(node, clear) {
        if (!_remoteHighlight) {
            _remoteHighlight = new Highlight("#cfc");
        }
        if (clear) {
            _remoteHighlight.clear();
        }
        _remoteHighlight.add(node);
    }

    // highlight a rule
    function highlightRule(rule) {
        hideHighlight();
        var i, nodes = document.querySelectorAll(rule);
        for (i = 0; i < nodes.length; i++) {
            highlight(nodes[i]);
        }
    }

    // install event listeners
    /* FUTURE
    window.document.addEventListener("keydown", onKeyDown);
    */

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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */
/*global define, $, window, document */

/**
 * RemoteFunctions define the functions to be executed in the browser. This
 * modules should define a single function that returns an object of all
 * exported functions.
 */
function RemoteFunctions(experimental) {
    "use strict";

    // determine the color for a type
    function _typeColor(type, highlight) {
        switch (type) {
        case "html":
            return highlight ? "#eec" : "#ffe";
        case "css":
            return highlight ? "#cee" : "#eff";
        case "js":
            return highlight ? "#ccf" : "#eef";
        default:
            return highlight ? "#ddd" : "#eee";
        }
    }

    // compute the screen offset of an element
    function _screenOffset(element, key) {
        var value = 0;
        while (element) {
            value += element[key];
            element = element.offsetParent;
        }
        return value;
    }

    // set an event on a element
    function _trigger(element, name, value, autoRemove) {
        var key = "data-ld-" + name;
        if (value !== undefined && value !== null) {
            element.setAttribute(key, value);
            if (autoRemove) {
                window.setTimeout(element.removeAttribute.bind(element, key));
            }
        } else {
            element.removeAttribute(key);
        }
    }

    // construct the info menu
    function Menu(element) {
        this.element = element;
        _trigger(this.element, "showgoto", 1, true);
        window.setTimeout(window.remoteShowGoto);
        this.remove = this.remove.bind(this);
    }

    Menu.prototype = {
        onClick: function (url, event) {
            event.preventDefault();
            _trigger(this.element, "goto", url, true);
            this.remove();
        },

        createBody: function () {
            if (this.body) {
                return;
            }

            // compute the position on screen
            var x = _screenOffset(this.element, "offsetLeft");
            var y = _screenOffset(this.element, "offsetTop") + this.element.offsetHeight;

            // create the container
            this.body = document.createElement("div");
            this.body.style.setProperty("z-index", 2147483647);
            this.body.style.setProperty("position", "absolute");
            this.body.style.setProperty("left", x + "px");
            this.body.style.setProperty("top", y + "px");
            this.body.style.setProperty("font-size", "11pt");

            // draw the background
            this.body.style.setProperty("background", "#fff");
            this.body.style.setProperty("border", "1px solid #888");
            this.body.style.setProperty("-webkit-box-shadow", "2px 2px 6px 0px #ccc");
            this.body.style.setProperty("border-radius", "6px");
            this.body.style.setProperty("padding", "6px");
        },

        addItem: function (target) {
            var item = document.createElement("div");
            item.style.setProperty("padding", "2px 6px");
            if (this.body.childNodes.length > 0) {
                item.style.setProperty("border-top", "1px solid #ccc");
            }
            item.style.setProperty("cursor", "pointer");
            item.style.setProperty("background", _typeColor(target.type));
            item.innerHTML = target.name;
            item.addEventListener("click", this.onClick.bind(this, target.url));

            if (target.file) {
                var file = document.createElement("i");
                file.style.setProperty("float", "right");
                file.style.setProperty("margin-left", "12px");
                file.innerHTML = " " + target.file;
                item.appendChild(file);
            }
            this.body.appendChild(item);
        },

        show: function () {
            if (!this.body) {
                this.body = this.createBody();
            }
            if (!this.body.parentNode) {
                document.body.appendChild(this.body);
            }
            document.addEventListener("click", this.remove);
        },

        remove: function () {
            if (this.body && this.body.parentNode) {
                document.body.removeChild(this.body);
            }
            document.removeEventListener("click", this.remove);
        }

    };

    function Editor(element) {
        this.onBlur = this.onBlur.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);

        this.element = element;
        this.element.setAttribute("contenteditable", "true");
        this.element.focus();
        this.element.addEventListener("blur", this.onBlur);
        this.element.addEventListener("keypress", this.onKeyPress);

        this.revertText = this.element.innerHTML;

        _trigger(this.element, "edit", 1);
    }

    Editor.prototype = {
        onBlur: function (event) {
            this.element.removeAttribute("contenteditable");
            this.element.removeEventListener("blur", this.onBlur);
            this.element.removeEventListener("keypress", this.onKeyPress);
            _trigger(this.element, "edit", 0, true);
        },

        onKeyPress: function (event) {
            switch (event.which) {
            case 13: // return
                this.element.blur();
                break;
            case 27: // esc
                this.element.innerHTML = this.revertText;
                this.element.blur();
                break;
            }
        }
    };

    function Highlight(color, trigger) {
        this.color = color;
        this.trigger = !!trigger;
        this.elements = [];
        this.orgColors = [];
    }

    Highlight.prototype = {
        _elementExists: function (element) {
            var i;
            for (i in this.elements) {
                if (this.elements[i] === element) {
                    return true;
                }
            }
            return false;
        },

        add: function (element) {
            if (this._elementExists(element) || element === document) {
                return;
            }
            if (this.trigger) {
                _trigger(element, "highlight", 1);
            }
            this.elements.push(element);
            this.orgColors.push(element.style.getPropertyValue("background-color"));
            element.style.setProperty("background-color", this.color);
        },

        clear: function () {
            var i;
            for (i in this.elements) {
                var e = this.elements[i];
                e.style.setProperty("background-color", this.orgColors[i]);
                _trigger(e, "highlight", 0, true);
            }
            this.elements = [];
            this.orgColors = [];
        }
    };

    var _currentEditor;
    function _toggleEditor(element) {
        _currentEditor = new Editor(element);
    }

    var _currentMenu;
    function _toggleMenu(element) {
        if (_currentMenu) {
            _currentMenu.remove();
        }
        _currentMenu = new Menu(element);
    }

    var _localHighlight;
    var _remoteHighlight;
    var _setup = false;

    /** Event Handlers ***********************************************************/

    function onMouseOver(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.add(event.target);
    }

    function onMouseOut(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.clear();
    }

    function onMouseMove(event) {
        onMouseOver(event);
        document.removeEventListener("mousemove", onMouseMove);
    }

    function onClick(event) {
        if (!event.metaKey) {
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        if (event.altKey) {
            _toggleEditor(event.target);
        } else {
            _toggleMenu(event.target);
        }
    }

    function onKeyUp(event) {
        if (_setup && !event.metaKey) {
            document.removeEventListener("keyup", onKeyUp);
            document.removeEventListener("mouseover", onMouseOver);
            document.removeEventListener("mouseout", onMouseOut);
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("click", onClick);
            _localHighlight.clear();
            _localHighlight = undefined;
            _setup = false;
        }
    }

    function onKeyDown(event) {
        if (!_setup && event.metaKey) {
            document.addEventListener("keyup", onKeyUp);
            document.addEventListener("mouseover", onMouseOver);
            document.addEventListener("mouseout", onMouseOut);
            document.addEventListener("mousemove", onMouseMove);
            document.addEventListener("click", onClick);
            _localHighlight = new Highlight("#ecc", true);
            _setup = true;
        }
    }

    /** Public Commands **********************************************************/

    // show goto
    function showGoto(targets) {
        if (!_currentMenu) {
            return;
        }
        _currentMenu.createBody();
        var i;
        for (i in targets) {
            _currentMenu.addItem(targets[i]);
        }
        _currentMenu.show();
    }

    // remove active highlights
    function hideHighlight() {
        if (_remoteHighlight) {
            _remoteHighlight.clear();
        }
    }

    // highlight a node
    function highlight(node, clear) {
        if (!_remoteHighlight) {
            _remoteHighlight = new Highlight("#cfc");
        }
        if (clear) {
            _remoteHighlight.clear();
        }
        _remoteHighlight.add(node);
    }

    // highlight a rule
    function highlightRule(rule) {
        hideHighlight();
        var i, nodes = document.querySelectorAll(rule);
        for (i = 0; i < nodes.length; i++) {
            highlight(nodes[i]);
        }
    }

    // init
    if (experimental) {
        window.document.addEventListener("keydown", onKeyDown);
    }

    return {
        "showGoto": showGoto,
        "hideHighlight": hideHighlight,
        "highlight": highlight,
        "highlightRule": highlightRule
    };
}<|endoftext|>


<commit_before>(function() {
  'use strict';
  angular.module('civic.events')
    .directive('browseGrid', browseGrid)
    .controller('BrowseGridController', BrowseGridController);

  // @ngInject
  function browseGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
        mode: '=',
        page: '='
      },
      templateUrl: 'app/views/browse/directives/browseGrid.tpl.html',
      controller: 'BrowseGridController'
    };
    return directive;
  }

  // @ngInject
  function BrowseGridController($scope,
                                $state,
                                $window,
                                $location,
                                uiGridConstants,
                                Datatables,
                                _) {
    var ctrl = $scope.ctrl = {};

    var pageCount = 25;
    var maxRows = ctrl.maxRows = pageCount;

    // declare ui paging/sorting/filtering vars
    ctrl.mode = $scope.mode;
    ctrl.totalItems = Number();
    ctrl.page = $scope.page;
    ctrl.count= Number();

    ctrl.filters = [];

    if(ctrl.mode !== 'evidence_items') {
      ctrl.sorting = [{
        field: 'evidence_item_count',
        direction: 'desc'
      }];
    } else {
      ctrl.sorting = [{
        field: 'id',
        direction: 'asc'
      }];
    }

    $scope.$watch('ctrl.totalItems', function() {
      ctrl.totalPages = Math.ceil(ctrl.totalItems / pageCount);
    });

    ctrl.gridOptions = {
      enablePaginationControls: false,

      useExternalFiltering: true,
      useExternalSorting: true,
      useExternalPaging: true,

      paginationPageSizes: [maxRows],
      paginationPageSize: maxRows,
      minRowsToShow: maxRows + 1,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,

      enableFiltering: true,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      rowTemplate: 'app/views/browse/directives/browseGridRow.tpl.html'
    };

    // set up column defs and data transforms for each mode
    var modeColumnDefs = {
      'assertions': [
        {
          name: 'gene_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'disease',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'status',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          sort: {
            direction: uiGridConstants.DESC
          },
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
      ],
      'evidence_items': [
        {
          name: 'gene_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'disease',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'source_citation',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'source_title',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
      ],
      'variants': [
        {
          name: 'variant',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'entrez_gene',
          width: '15%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'diseases',
          displayName: 'Diseases',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'drugs',
          displayName: 'Drugs',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'evidence_item_count',
          width: '10%',
          displayName: 'Evidence',
          sort: {
            direction: uiGridConstants.DESC
          },
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'genes': [
        {
          name: 'name',
          width: '15%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene_aliases',
          width: '30%',
          displayName: 'Gene Aliases',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'diseases',
          //width: '30%',
          displayName: 'Diseases',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'drugs',
          //width: '30%',
          displayName: 'Drugs',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'variant_count',
          displayName: 'Variants',
          width: '10%',
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          width: '10%',
          displayName: 'Evidence',
          sort: {
            direction: uiGridConstants.DESC
          },
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'variant_groups': [
        {
          name: 'name',
          displayName: 'Name',
          width: '20%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variants',
          displayName: 'Variants',
          width: '35%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'variant_count',
          displayName: 'Count',
          width: '7%',
          enableFiltering: false,
          allowCellFocus: false
        },
        {
          name: 'entrez_genes',
          displayName: 'Genes',
          width: '23%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          type: 'number',
          displayName: 'Evidence Items',
          width: '15%',
          enableFiltering: false,
          allowCellFocus: false,
          sort: { direction: uiGridConstants.DESC },
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'sources': [
        {
          name: 'pubmed_id',
          displayName: 'Pubmed ID',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'author_list',
          displayName: 'Authors',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'publication_year',
          displayName: 'Year',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          width: '8%'
        },
        {
          name: 'journal',
          displayName: 'Journal',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          width: '15%',
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'name',
          displayName: 'Name',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: true,
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          type: 'number',
          displayName: 'Evidence Items',
          width: '10%',
          enableFiltering: false,
          allowCellFocus: false,
          sort: { direction: uiGridConstants.DESC }
        }
      ]
    };

    ctrl.gridOptions.onRegisterApi = function(gridApi) {
      ctrl.gridApi = gridApi;
      // called from pagination directive when page changes
      ctrl.pageChanged = function() {
        $location.search('page', ctrl.page);
        updateData();
      };

      // reset paging and do some other stuff on filter changes
      gridApi.core.on.filterChanged($scope, function() {
        // updateData with new filters
        var filteredCols = _.filter(this.grid.columns, function(col) {
          return _.has(col.filter, 'term') && !_.isEmpty(col.filter.term) && _.isString(col.filter.term);
        });
        if (filteredCols.length > 0) {
          ctrl.filters = _.map(filteredCols, function(col) {
            return {
              'field': col.field,
              'term': col.filter.term
            };
          });
        } else {
          ctrl.filters = [];
        }
        ctrl.page = 1;
        updateData();
      });

      gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
        if (sortColumns.length > 0) {
          ctrl.sorting = _.map(sortColumns, function(col) {
            return {
              'field': col.field,
              'direction': col.sort.direction
            };
          });
        } else {
          ctrl.sorting = [];
        }
        updateData();
      });

      // called when user clicks on a row
      gridApi.selection.on.rowSelectionChanged($scope, function(row, event){
        var state = '';
        var params = {};
        if(ctrl.mode === 'variants') {
          state = 'events.genes.summary.variants.summary';
          params = {
            geneId: row.entity.gene_id,
            variantId: row.entity.variant_id,
            '#': 'variant'
          };
        } else if (ctrl.mode === 'genes'){
          state = 'events.genes.summary';
          params = {
            geneId: row.entity.id,
            '#': 'gene'
          };
        } else if (ctrl.mode === 'variant_groups') {
          state = 'events.genes.summary.variantGroups.summary';
          params = {
            geneId: row.entity.gene_ids[0],
            variantGroupId: row.entity.id,
            '#': 'variant-group'
          };
        } else if (ctrl.mode === 'sources') {
          state = 'sources.summary';
          params = {
            sourceId: row.entity.id
          };
        } else if (ctrl.mode === 'assertions') {
          state = 'assertions.summary';
          params = {
            assertionId: row.entity.id
          };
        } else if (ctrl.mode === 'evidence_items') {
          state = 'events.genes.summary.variants.summary.evidence.summary';
          params = {
            geneId: row.entity.gene_id,
            variantId: row.entity.variant_id,
            evidenceId: row.entity.id,
            '#': 'variant'
          };
        }

        if(event.metaKey) {
          // if meta key (alt or command) pressed, generate a state URL and open it in a new tab/window
          // shift would be preferable to meta but ui-grid's selection module appears to be capturing shift-clicks for multi-select feature
          // keep an eye on: https://github.com/angular-ui/ui-grid/issues/4926
          var url = $state.href(state, params, {absolute: true});
          $window.open(url, '_blank');
        } else {
          $state.go(state, params);
        }

      });
    };

    function updateData() {
      fetchData(ctrl.mode, ctrl.count, ctrl.page, ctrl.sorting, ctrl.filters)
        .then(function(data){
          if(ctrl.mode === 'variant_groups') {
            // add variant_count attribute
            _.forEach(data.result, function(variant_group) {
              variant_group.variant_count = variant_group.variants.split(', ').length;
              return variant_group;
            });
            ctrl.gridOptions.data = data.result;
          } else {
            ctrl.gridOptions.data = data.result;
          }
          ctrl.gridOptions.columnDefs = modeColumnDefs[ctrl.mode];
          ctrl.totalItems = data.total;
        });
    }

    function fetchData(mode, count, page, sorting, filters) {
      var request;

      request= {
        mode: mode,
        count: count,
        page: page
      };

      if (filters.length > 0) {
        _.each(filters, function(filter) {
          request['filter[' + filter.field + ']'] = filter.term;
        });
      }

      if (sorting.length > 0) {
        _.each(sorting, function(sort) {
          request['sorting[' + sort.field + ']'] = sort.direction;
        });
      }
      return Datatables.query(request);
    }

    updateData();
  }
})();
<commit_msg>fixed ID filtering for assertions<commit_after>(function() {
  'use strict';
  angular.module('civic.events')
    .directive('browseGrid', browseGrid)
    .controller('BrowseGridController', BrowseGridController);

  // @ngInject
  function browseGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
        mode: '=',
        page: '='
      },
      templateUrl: 'app/views/browse/directives/browseGrid.tpl.html',
      controller: 'BrowseGridController'
    };
    return directive;
  }

  // @ngInject
  function BrowseGridController($scope,
                                $state,
                                $window,
                                $location,
                                uiGridConstants,
                                Datatables,
                                _) {
    var ctrl = $scope.ctrl = {};

    var pageCount = 25;
    var maxRows = ctrl.maxRows = pageCount;

    // declare ui paging/sorting/filtering vars
    ctrl.mode = $scope.mode;
    ctrl.totalItems = Number();
    ctrl.page = $scope.page;
    ctrl.count= Number();

    ctrl.filters = [];

    if(ctrl.mode !== 'evidence_items' && ctrl.mode !== 'assertions') {
      ctrl.sorting = [{
        field: 'evidence_item_count',
        direction: 'desc'
      }];
    } else {
      ctrl.sorting = [{
        field: 'id',
        direction: 'asc'
      }];
    }

    $scope.$watch('ctrl.totalItems', function() {
      ctrl.totalPages = Math.ceil(ctrl.totalItems / pageCount);
    });

    ctrl.gridOptions = {
      enablePaginationControls: false,

      useExternalFiltering: true,
      useExternalSorting: true,
      useExternalPaging: true,

      paginationPageSizes: [maxRows],
      paginationPageSize: maxRows,
      minRowsToShow: maxRows + 1,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,

      enableFiltering: true,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      rowTemplate: 'app/views/browse/directives/browseGridRow.tpl.html'
    };

    // set up column defs and data transforms for each mode
    var modeColumnDefs = {
      'assertions': [
        {
          name: 'id',
          displayName: 'AID',
          visible: true,
          width: '7%',
          type: 'number',
          enableSorting: true,
          enableFiltering: true,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'disease',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'status',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          sort: {
            direction: uiGridConstants.DESC
          },
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
      ],
      'evidence_items': [
        {
          name: 'id',
          displayName: 'EID',
          visible: true,
          type: 'number',
          enableSorting: true,
          enableFiltering: true,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant_name',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'disease',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'source_citation',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'source_title',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
      ],
      'variants': [
        {
          name: 'variant',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'entrez_gene',
          width: '15%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'diseases',
          displayName: 'Diseases',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'drugs',
          displayName: 'Drugs',
          width: '25%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'evidence_item_count',
          width: '10%',
          displayName: 'Evidence',
          sort: {
            direction: uiGridConstants.DESC
          },
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'genes': [
        {
          name: 'name',
          width: '15%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene_aliases',
          width: '30%',
          displayName: 'Gene Aliases',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'diseases',
          //width: '30%',
          displayName: 'Diseases',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'drugs',
          //width: '30%',
          displayName: 'Drugs',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'variant_count',
          displayName: 'Variants',
          width: '10%',
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          width: '10%',
          displayName: 'Evidence',
          sort: {
            direction: uiGridConstants.DESC
          },
          enableFiltering: false,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'variant_groups': [
        {
          name: 'name',
          displayName: 'Name',
          width: '20%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variants',
          displayName: 'Variants',
          width: '35%',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html'
        },
        {
          name: 'variant_count',
          displayName: 'Count',
          width: '7%',
          enableFiltering: false,
          allowCellFocus: false
        },
        {
          name: 'entrez_genes',
          displayName: 'Genes',
          width: '23%',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          type: 'number',
          displayName: 'Evidence Items',
          width: '15%',
          enableFiltering: false,
          allowCellFocus: false,
          sort: { direction: uiGridConstants.DESC },
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ],
      'sources': [
        {
          name: 'pubmed_id',
          displayName: 'Pubmed ID',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'author_list',
          displayName: 'Authors',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'publication_year',
          displayName: 'Year',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          },
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          width: '8%'
        },
        {
          name: 'journal',
          displayName: 'Journal',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          width: '15%',
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'name',
          displayName: 'Name',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: true,
          cellTemplate: 'app/views/browse/directives/browseGridTooltipCell.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item_count',
          type: 'number',
          displayName: 'Evidence Items',
          width: '10%',
          enableFiltering: false,
          allowCellFocus: false,
          sort: { direction: uiGridConstants.DESC }
        }
      ]
    };

    ctrl.gridOptions.onRegisterApi = function(gridApi) {
      ctrl.gridApi = gridApi;
      // called from pagination directive when page changes
      ctrl.pageChanged = function() {
        $location.search('page', ctrl.page);
        updateData();
      };

      // reset paging and do some other stuff on filter changes
      gridApi.core.on.filterChanged($scope, function() {
        // updateData with new filters
        var filteredCols = _.filter(this.grid.columns, function(col) {
          return _.has(col.filter, 'term') && !_.isEmpty(col.filter.term) && _.isString(col.filter.term);
        });
        if (filteredCols.length > 0) {
          ctrl.filters = _.map(filteredCols, function(col) {
            return {
              'field': col.field,
              'term': col.filter.term
            };
          });
        } else {
          ctrl.filters = [];
        }
        ctrl.page = 1;
        updateData();
      });

      gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
        if (sortColumns.length > 0) {
          ctrl.sorting = _.map(sortColumns, function(col) {
            return {
              'field': col.field,
              'direction': col.sort.direction
            };
          });
        } else {
          ctrl.sorting = [];
        }
        updateData();
      });

      // called when user clicks on a row
      gridApi.selection.on.rowSelectionChanged($scope, function(row, event){
        var state = '';
        var params = {};
        if(ctrl.mode === 'variants') {
          state = 'events.genes.summary.variants.summary';
          params = {
            geneId: row.entity.gene_id,
            variantId: row.entity.variant_id,
            '#': 'variant'
          };
        } else if (ctrl.mode === 'genes'){
          state = 'events.genes.summary';
          params = {
            geneId: row.entity.id,
            '#': 'gene'
          };
        } else if (ctrl.mode === 'variant_groups') {
          state = 'events.genes.summary.variantGroups.summary';
          params = {
            geneId: row.entity.gene_ids[0],
            variantGroupId: row.entity.id,
            '#': 'variant-group'
          };
        } else if (ctrl.mode === 'sources') {
          state = 'sources.summary';
          params = {
            sourceId: row.entity.id
          };
        } else if (ctrl.mode === 'assertions') {
          state = 'assertions.summary';
          params = {
            assertionId: row.entity.id
          };
        } else if (ctrl.mode === 'evidence_items') {
          state = 'events.genes.summary.variants.summary.evidence.summary';
          params = {
            geneId: row.entity.gene_id,
            variantId: row.entity.variant_id,
            evidenceId: row.entity.id,
            '#': 'variant'
          };
        }

        if(event.metaKey) {
          // if meta key (alt or command) pressed, generate a state URL and open it in a new tab/window
          // shift would be preferable to meta but ui-grid's selection module appears to be capturing shift-clicks for multi-select feature
          // keep an eye on: https://github.com/angular-ui/ui-grid/issues/4926
          var url = $state.href(state, params, {absolute: true});
          $window.open(url, '_blank');
        } else {
          $state.go(state, params);
        }

      });
    };

    function updateData() {
      fetchData(ctrl.mode, ctrl.count, ctrl.page, ctrl.sorting, ctrl.filters)
        .then(function(data){
          if(ctrl.mode === 'variant_groups') {
            // add variant_count attribute
            _.forEach(data.result, function(variant_group) {
              variant_group.variant_count = variant_group.variants.split(', ').length;
              return variant_group;
            });
            ctrl.gridOptions.data = data.result;
          } else {
            ctrl.gridOptions.data = data.result;
          }
          ctrl.gridOptions.columnDefs = modeColumnDefs[ctrl.mode];
          ctrl.totalItems = data.total;
        });
    }

    function fetchData(mode, count, page, sorting, filters) {
      var request;

      request= {
        mode: mode,
        count: count,
        page: page
      };

      if (filters.length > 0) {
        _.each(filters, function(filter) {
          request['filter[' + filter.field + ']'] = filter.term;
        });
      }

      if (sorting.length > 0) {
        _.each(sorting, function(sort) {
          request['sorting[' + sort.field + ']'] = sort.direction;
        });
      }
      return Datatables.query(request);
    }

    updateData();
  }
})();
<|endoftext|>


<commit_before>/**
 * Composite of multiple related drawables.
 * A drawable should extend this class if its
 * individual components need to re-use the same
 * points or vectors
 *
 * Copyright (c) 2013 Marshall Farrier
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Dependencies:
 * extend.js
 * drawable.js
 * point.js
 */

/** @namespace */
var _c = _c || {};

(function(_c) {
    "use strict";

    /** @namespace */
    _c.draw = _c.draw || {};

    /**
     * Creates a new _c.draw.Composite
     * @constructor
     * @member {Object.<string, _c.draw.Drawable>} drawables - collection of named drawables
     * @member {string[]} keys - array containing the name of each drawable.
     * This array determines the order in which draw operations will be
     * performed. Only drawables whose names appear in this array
     * will be drawn by the default Composite#draw() method.
     * @member {Object.<string, _c.draw.Point>} [points] - collection of points
     * that may be re-used in several distinct drawables. The center of a circle might,
     * for example, also represent the corner of a rectangle.
     * @member {Object.<string, _c.draw.Vector>} [vectors] - collection of vectors
     *
     * Inherited from _c.draw.Drawable:
     * @member {function} draw
     * @member {function} [contains]
     */
    _c.draw.Composite = _c.draw.Drawable.extend({

        /**
         * @constructs _c.draw.Composite
         * @param {object} params
         * @param {Object.<string, _c.draw.Drawable>} params.drawables - collection of named drawables
         * @param {string[]} params.keys - array containing the name of each drawable.
         * This array determines the order in which draw operations will be
         * performed. Only drawables whose names appear in this array
         * will be drawn by the default Composite#draw() method.
         * @param {Object.<string, _c.draw.Point>} [params.points] - collection of points
         * that may be re-used in several distinct drawables. The center of a circle might,
         * for example, also represent the corner of a rectangle.
         * @param {Object.<string, _c.draw.Vector>} [params.vectors] - collection of vectors
         * @param {Object.<string, *>} [params.config] - allows the drawable to include miscellaneous
         * configuration parameters.
         * @param {Object.<string, function>} [params.draw] - modifies the default draw behavior
         * of calling the draw() method of each drawable in the order specified by the keys array.
         * @param {function} [params.draw.before] - action to be taken before the default draw
         * method is called
         * @param {function} [params.draw.after] - action to be taken after the default draw method
         * is called
         * @param {function} [params.draw.main] - overrides the default draw method and obviates
         * params.draw.before and params.draw.after. That is, if params.draw.main is provided, it
         * must include the entire draw method.
         * @param {function} [params.finish] - called (using this as 'this argument') after
         * all components have been initially constructed. Used to set up pointers between
         * components, which presupposes that the components have been initialized.
         * For example, a drawable circle might want to use a named point as its center so that the
         * same point can also be used as endpoint of a line.
         */
        /**
         * @method params.draw.before
         * // similarly for params.draw.after and params.draw.main
         * @param {object} context - context into which the drawable will be drawn
         */
        init: function(params) {
            var _this = this,
                _draw = params.draw || {},
                _beforeDraw = _draw.before || function(context) {},
                _afterDraw = _draw.after || function(context) {};

            this.drawables = params.drawables;
            this.keys = params.keys;
            this.points = params.points || {};
            this.vectors = params.vectors || {};
            this.config = params.config || {};
            if (_draw.main) {
                this.draw = function(context) {
                    return _draw.main.call(this, context);
                }
            }
            else {
                this.draw = function(context) {
                    _beforeDraw.call(this, context);
                    this.keys.forEach(function(key) {
                        _this.drawables[key].draw(context);
                    });
                    _afterDraw.call(this, context);
                }
            }
            if (params.finish) {
                params.finish.call(this);
            }
        }
    });
})(_c);
<commit_msg>Improved naming<commit_after>/**
 * Composite of multiple related drawables.
 * A drawable should extend this class if its
 * individual components need to re-use the same
 * points or vectors
 *
 * Copyright (c) 2013 Marshall Farrier
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Dependencies:
 * extend.js
 * drawable.js
 * point.js
 */

/** @namespace */
var _c = _c || {};

(function(_c) {
    "use strict";

    /** @namespace */
    _c.draw = _c.draw || {};

    /**
     * Creates a new _c.draw.Composite
     * @constructor
     * @member {Object.<string, _c.draw.Drawable>} drawables - collection of named drawables
     * @member {string[]} keys - array containing the name of each drawable.
     * This array determines the order in which draw operations will be
     * performed. Only drawables whose names appear in this array
     * will be drawn by the default Composite#draw() method.
     * @member {Object.<string, _c.draw.Point>} [points] - collection of points
     * that may be re-used in several distinct drawables. The center of a circle might,
     * for example, also represent the corner of a rectangle.
     * @member {Object.<string, _c.draw.Vector>} [vectors] - collection of vectors
     *
     * Inherited from _c.draw.Drawable:
     * @member {function} draw
     * @member {function} [contains]
     */
    _c.draw.Composite = _c.draw.Drawable.extend({

        /**
         * @constructs _c.draw.Composite
         * @param {object} params
         * @param {Object.<string, _c.draw.Drawable>} params.drawables - collection of named drawables
         * @param {string[]} params.keys - array containing the name of each drawable.
         * This array determines the order in which draw operations will be
         * performed. Only drawables whose names appear in this array
         * will be drawn by the default Composite#draw() method.
         * @param {Object.<string, _c.draw.Point>} [params.points] - collection of points
         * that may be re-used in several distinct drawables. The center of a circle might,
         * for example, also represent the corner of a rectangle.
         * @param {Object.<string, _c.draw.Vector>} [params.vectors] - collection of vectors
         * @param {Object.<string, *>} [params.config] - allows the drawable to include miscellaneous
         * configuration parameters.
         * @param {Object.<string, function>} [params.draw] - modifies the default draw behavior
         * of calling the draw() method of each drawable in the order specified by the keys array.
         * @param {function} [params.draw.before] - action to be taken before the default draw
         * method is called
         * @param {function} [params.draw.after] - action to be taken after the default draw method
         * is called
         * @param {function} [params.draw.all] - overrides the default draw method and obviates
         * params.draw.before and params.draw.after. That is, if params.draw.allis provided, it
         * will be used as the entire draw method.
         * @param {function} [params.finish] - called (using this as 'this argument') after
         * all components have been initially constructed. Used to set up pointers between
         * components, which presupposes that the components have been initialized.
         * For example, a drawable circle might want to use a named point as its center so that the
         * same point can also be used as endpoint of a line.
         */
        /**
         * @method params.draw.before
         * // similarly for params.draw.after and params.draw.main
         * @param {object} context - context into which the drawable will be drawn
         */
        init: function(params) {
            var _this = this,
                _draw = params.draw || {},
                _beforeDraw = _draw.before || function(context) {},
                _afterDraw = _draw.after || function(context) {};

            this.drawables = params.drawables;
            this.keys = params.keys;
            this.points = params.points || {};
            this.vectors = params.vectors || {};
            this.config = params.config || {};
            if (_draw.all) {
                this.draw = function(context) {
                    return _draw.all.call(this, context);
                }
            }
            else {
                this.draw = function(context) {
                    _beforeDraw.call(this, context);
                    this.keys.forEach(function(key) {
                        _this.drawables[key].draw(context);
                    });
                    _afterDraw.call(this, context);
                }
            }
            if (params.finish) {
                params.finish.call(this);
            }
        }
    });
})(_c);
<|endoftext|>


<commit_before>import { includes, defaults, defaultsDeep, isFunction, range, without } from "lodash";
import { Helpers, Scale, Domain } from "victory-core";

const orientationSign = {
  top: -1,
  left: -1,
  right: 1,
  bottom: 1
};

export default {
  // exposed for use by VictoryChart
  getDomain(props, axis) {
    const inherentAxis = this.getAxis(props);
    if (axis && axis !== inherentAxis) {
      return undefined;
    }
    let domain;
    if (Array.isArray(props.domain)) {
      domain = props.domain;
    } else if (props.domain && props.domain[inherentAxis]) {
      domain = props.domain[inherentAxis];
    } else if (Array.isArray(props.tickValues) && props.tickValues.length > 1) {
      domain = Domain.getDomainFromTickValues(props);
    }
    const paddedDomain = Domain.padDomain(domain, props, inherentAxis);
    return domain ? Domain.cleanDomain(paddedDomain, props, inherentAxis) : undefined;
  },

  // exposed for use by VictoryChart
  getAxis(props, flipped) {
    if (props.orientation) {
      const vertical = {top: "x", bottom: "x", left: "y", right: "y"};
      return vertical[props.orientation];
    }
    const axisType = props.dependentAxis ? "dependent" : "independent";
    const flippedAxis = { dependent: "x", independent: "y"};
    const normalAxis = { independent: "x", dependent: "y"};
    return flipped ? flippedAxis[axisType] : normalAxis[axisType];
  },

  // exposed for use by VictoryChart
  getScale(props) {
    const axis = this.getAxis(props);
    const scale = Scale.getBaseScale(props, axis);
    const domain = this.getDomain(props) || scale.domain();
    scale.range(Helpers.getRange(props, axis));
    scale.domain(domain);
    return scale;
  },

  getStyleObject(props) {
    const { theme, dependentAxis } = props;
    const generalAxisStyle = theme && theme.axis && theme.axis.style;
    const axisType = dependentAxis ? "dependentAxis" : "independentAxis";
    const specificAxisStyle = theme && theme[axisType] && theme[axisType].style;

    return generalAxisStyle && specificAxisStyle
      ? defaultsDeep({},
          specificAxisStyle,
          generalAxisStyle
        )
      : specificAxisStyle || generalAxisStyle;
  },

  getStyles(props, styleObject) {
    const style = props.style || {};
    styleObject = styleObject || {};
    const parentStyleProps = { height: "auto", width: "100%" };
    return {
      parent: defaults(parentStyleProps, style.parent, styleObject.parent),
      axis: defaults({}, style.axis, styleObject.axis),
      axisLabel: defaults({}, style.axisLabel, styleObject.axisLabel),
      grid: defaults({}, style.grid, styleObject.grid),
      ticks: defaults({}, style.ticks, styleObject.ticks),
      tickLabels: defaults({}, style.tickLabels, styleObject.tickLabels)
    };
  },

  getTickProps(layout, style, datum) {
    const { position, transform } = layout;
    return {
      x1: transform.x,
      y1: transform.y,
      x2: transform.x + position.x2,
      y2: transform.y + position.y2,
      style,
      datum
    };
  },

  getTickLabelProps(layout, style, anchors, datum, text) { // eslint-disable-line max-params
    const { position, transform } = layout;
    return {
      style,
      x: transform.x + position.x,
      y: transform.y + position.y,
      verticalAnchor: anchors.verticalAnchor,
      textAnchor: anchors.textAnchor,
      angle: style.angle,
      text,
      datum
    };
  },

  getGridProps(layout, style, datum) {
    const {edge, transform} = layout;
    return {
      x1: transform.x,
      y1: transform.y,
      x2: edge.x + transform.x,
      y2: edge.y + transform.y,
      style,
      datum
    };
  },

  getAxisProps(modifiedProps, calculatedValues, globalTransform) {
    const { style, padding, isVertical } = calculatedValues;
    const { width, height } = modifiedProps;
    return {
      style: style.axis,
      x1: isVertical ? globalTransform.x : padding.left + globalTransform.x,
      x2: isVertical ? globalTransform.x : width - padding.right + globalTransform.x,
      y1: isVertical ? padding.top + globalTransform.y : globalTransform.y,
      y2: isVertical ? height - padding.bottom + globalTransform.y : globalTransform.y
    };
  },

  getLayoutProps(modifiedProps, calculatedValues) {
    const offset = this.getOffset(modifiedProps, calculatedValues);
    return {
      globalTransform: this.getTransform(modifiedProps, calculatedValues, offset),
      gridOffset: this.getGridOffset(modifiedProps, calculatedValues, offset),
      gridEdge: this.getGridEdge(modifiedProps, calculatedValues)
    };
  },

  getEvaluatedStyles(style, tick, index) {
    return {
      tickStyle: Helpers.evaluateStyle(style.ticks, tick, index),
      labelStyle: Helpers.evaluateStyle(style.tickLabels, tick, index),
      gridStyle: Helpers.evaluateStyle(style.grid, tick, index)
    };
  },

  getRole(props) {
    if (props.dependentAxis) {
      return props.theme && props.theme.dependentAxis
        ? "dependentAxis"
        : "axis";
    }

    return props.theme && props.theme.independentAxis
      ? "independentAxis"
      : "axis";
  },

  getShallowMergedThemeProps(props, role) {
    const axisTheme = props.theme.axis || {};
    return defaults({}, props.theme[role], axisTheme);
  },

  modifyProps(props, fallbackProps, role) {
    if (role !== "axis") {
      props.theme[role] = this.getShallowMergedThemeProps(props, role);
    }
    return Helpers.modifyProps(props, fallbackProps, role);
  },

  getBaseProps(props, fallbackProps) {
    const role = this.getRole(props);
    props = this.modifyProps(props, fallbackProps, role);
    const calculatedValues = this.getCalculatedValues(props);
    const {
      style, orientation, isVertical, scale, ticks, tickFormat, stringTicks, anchors
    } = calculatedValues;

    const {
      globalTransform, gridOffset, gridEdge
    } = this.getLayoutProps(props, calculatedValues);

    const axisProps = this.getAxisProps(props, calculatedValues, globalTransform);
    const axisLabelProps = this.getAxisLabelProps(props, calculatedValues, globalTransform);

    const childProps = { parent: {
      style: style.parent, ticks, scale, width: props.width, height: props.height
    }};
    for (let index = 0, len = ticks.length; index < len; index++) {
      const tick = stringTicks ? props.tickValues[(ticks[index]) - 1] : ticks[index];

      const styles = this.getEvaluatedStyles(style, tick, index);
      const tickLayout = {
        position: this.getTickPosition(styles.tickStyle, orientation, isVertical),
        transform: this.getTickTransform(scale(ticks[index]), globalTransform, isVertical)
      };

      const gridLayout = {
        edge: gridEdge,
        transform: {
          x: isVertical ?
            -gridOffset.x + globalTransform.x : scale(ticks[index]) + globalTransform.x,
          y: isVertical ?
            scale(ticks[index]) + globalTransform.y : gridOffset.y + globalTransform.y
        }
      };

      childProps[index] = {
        axis: axisProps,
        axisLabel: axisLabelProps,
        ticks: this.getTickProps(tickLayout, styles.tickStyle, tick),
        tickLabels: this.getTickLabelProps(
          tickLayout, styles.labelStyle, anchors, tick, tickFormat(tick, index)
        ),
        grid: this.getGridProps(gridLayout, styles.gridStyle, tick)
      };
    }
    return childProps;
  },

  getCalculatedValues(props) {
    const defaultStyles = this.getStyleObject(props);
    const style = this.getStyles(props, defaultStyles);
    const padding = Helpers.getPadding(props);
    const orientation = props.orientation || (props.dependentAxis ? "left" : "bottom");
    const isVertical = Helpers.isVertical(props);
    const labelPadding = this.getLabelPadding(props, style);
    const stringTicks = Helpers.stringTicks(props);
    const scale = this.getScale(props);
    const ticks = this.getTicks(props, scale);
    const tickFormat = this.getTickFormat(props, scale, ticks);
    const anchors = this.getAnchors(orientation, isVertical);

    return {
      style, padding, orientation, isVertical, labelPadding, stringTicks,
      anchors, scale, ticks, tickFormat
    };
  },

  getAxisLabelProps(props, calculatedValues, globalTransform) {
    const {style, orientation, padding, labelPadding, isVertical} = calculatedValues;
    const sign = orientationSign[orientation];
    const hPadding = padding.left + padding.right;
    const vPadding = padding.top + padding.bottom;
    const verticalAnchor = sign < 0 ? "end" : "start";
    const labelStyle = style.axisLabel;
    const angle = isVertical ? -90 : 0;
    const x = isVertical ? globalTransform.x + (sign * labelPadding) :
      ((props.width - hPadding) / 2) + padding.left + globalTransform.x;
    const y = isVertical ?
      ((props.height - vPadding) / 2) + padding.bottom + globalTransform.y :
      (sign * labelPadding) + globalTransform.y;
    return {
      x,
      y,
      verticalAnchor: labelStyle.verticalAnchor || verticalAnchor,
      textAnchor: labelStyle.textAnchor || "middle",
      angle: labelStyle.angle || angle,
      style: labelStyle,
      text: props.label
    };
  },

  getTicks(props, scale) {
    if (props.tickValues) {
      if (Helpers.stringTicks(props)) {
        return range(1, props.tickValues.length + 1);
      }
      return props.tickValues.length ? props.tickValues : scale.domain();
    } else if (scale.ticks && isFunction(scale.ticks)) {
      const scaleTicks = scale.ticks(props.tickCount);
      const ticks = Array.isArray(scaleTicks) && scaleTicks.length ? scaleTicks : scale.domain();
      if (props.crossAxis) {
        return includes(ticks, 0) ? without(ticks, 0) : ticks;
      }
      return ticks;
    }
    return scale.domain();
  },

  getAnchors(orientation, isVertical) {
    const anchorOrientation = { top: "end", left: "end", right: "start", bottom: "start" };
    const anchor = anchorOrientation[orientation];
    return {
      textAnchor: isVertical ? anchor : "middle",
      verticalAnchor: isVertical ? "middle" : anchor
    };
  },

  getTickFormat(props, scale) {
    if (props.tickFormat && isFunction(props.tickFormat)) {
      return props.tickFormat;
    } else if (props.tickFormat && Array.isArray(props.tickFormat)) {
      return (x, index) => props.tickFormat[index];
    } else if (Helpers.stringTicks(props)) {
      return (x, index) => props.tickValues[index];
    } else if (scale.tickFormat && isFunction(scale.tickFormat)) {
      return scale.tickFormat();
    } else {
      return (x) => x;
    }
  },

  getLabelPadding(props, style) {
    const labelStyle = style.axisLabel || {};
    if (typeof labelStyle.padding !== "undefined" && labelStyle.padding !== null) {
      return labelStyle.padding;
    }
    const isVertical = Helpers.isVertical(props);
    // TODO: magic numbers
    const fontSize = labelStyle.fontSize || 14;
    return props.label ? (fontSize * (isVertical ? 2.3 : 1.6)) : 0;
  },

  getOffset(props, calculatedValues) {
    const {
      style, padding, isVertical, orientation, labelPadding, stringTicks, ticks
    } = calculatedValues;
    const xPadding = orientation === "right" ? padding.right : padding.left;
    const yPadding = orientation === "top" ? padding.top : padding.bottom;
    const fontSize = style.axisLabel.fontSize || 14;
    const offsetX = (props.offsetX !== null) && (props.offsetX !== undefined)
      ? props.offsetX : xPadding;
    const offsetY = (props.offsetY !== null) && (props.offsetY !== undefined)
      ? props.offsetY : yPadding;
    const tickSizes = ticks.map((data) => {
      const tick = stringTicks ? props.tickValues[data - 1] : data;
      const tickStyle = Helpers.evaluateStyle(style.ticks, tick);
      return tickStyle.size || 0;
    });
    const totalPadding = fontSize + (2 * Math.max(...tickSizes)) + labelPadding;
    const minimumPadding = 1.2 * fontSize; // TODO: magic numbers
    const x = isVertical ? totalPadding : minimumPadding;
    const y = isVertical ? minimumPadding : totalPadding;
    return {
      x: (offsetX !== null) && (offsetX !== undefined) ? offsetX : x,
      y: (offsetY !== null) && (offsetY !== undefined) ? offsetY : y
    };
  },

  getTransform(props, calculatedValues, offset) {
    const {orientation} = calculatedValues;
    return {
      top: {x: 0, y: offset.y},
      bottom: {x: 0, y: props.height - offset.y},
      left: {x: offset.x, y: 0},
      right: {x: props.width - offset.x, y: 0}
    }[orientation];
  },

  getTickPosition(style, orientation, isVertical) {
    const size = style.size || 0;
    const padding = style.padding || 0;
    const tickSpacing = size + padding;
    const sign = orientationSign[orientation];
    return {
      x: isVertical ? sign * tickSpacing : 0,
      x2: isVertical ? sign * size : 0,
      y: isVertical ? 0 : sign * tickSpacing,
      y2: isVertical ? 0 : sign * size
    };
  },

  getTickTransform(tick, globalTransform, isVertical) {
    return {
      x: isVertical ? globalTransform.x : tick + globalTransform.x,
      y: isVertical ? tick + globalTransform.y : globalTransform.y
    };
  },

  getGridEdge(props, calculatedValues) {
    const {orientation, padding, isVertical} = calculatedValues;
    const sign = -orientationSign[orientation];
    const x = isVertical ?
      sign * (props.width - (padding.left + padding.right)) : 0;
    const y = isVertical ?
      0 : sign * (props.height - (padding.top + padding.bottom));
    return {x, y};
  },

  getGridOffset(props, calculatedValues, offset) {
    const {padding, orientation } = calculatedValues;
    const xPadding = orientation === "right" ? padding.right : padding.left;
    const yPadding = orientation === "top" ? padding.top : padding.bottom;
    return {
      x: props.crossAxis ? offset.x - xPadding : 0,
      y: props.crossAxis ? offset.y - yPadding : 0
    };
  }
};
<commit_msg>apply tick padding and label padding<commit_after>import { includes, defaults, defaultsDeep, isFunction, range, without } from "lodash";
import { Helpers, Scale, Domain } from "victory-core";

const orientationSign = {
  top: -1,
  left: -1,
  right: 1,
  bottom: 1
};

export default {
  // exposed for use by VictoryChart
  getDomain(props, axis) {
    const inherentAxis = this.getAxis(props);
    if (axis && axis !== inherentAxis) {
      return undefined;
    }
    let domain;
    if (Array.isArray(props.domain)) {
      domain = props.domain;
    } else if (props.domain && props.domain[inherentAxis]) {
      domain = props.domain[inherentAxis];
    } else if (Array.isArray(props.tickValues) && props.tickValues.length > 1) {
      domain = Domain.getDomainFromTickValues(props);
    }
    const paddedDomain = Domain.padDomain(domain, props, inherentAxis);
    return domain ? Domain.cleanDomain(paddedDomain, props, inherentAxis) : undefined;
  },

  // exposed for use by VictoryChart
  getAxis(props, flipped) {
    if (props.orientation) {
      const vertical = {top: "x", bottom: "x", left: "y", right: "y"};
      return vertical[props.orientation];
    }
    const axisType = props.dependentAxis ? "dependent" : "independent";
    const flippedAxis = { dependent: "x", independent: "y"};
    const normalAxis = { independent: "x", dependent: "y"};
    return flipped ? flippedAxis[axisType] : normalAxis[axisType];
  },

  // exposed for use by VictoryChart
  getScale(props) {
    const axis = this.getAxis(props);
    const scale = Scale.getBaseScale(props, axis);
    const domain = this.getDomain(props) || scale.domain();
    scale.range(Helpers.getRange(props, axis));
    scale.domain(domain);
    return scale;
  },

  getStyleObject(props) {
    const { theme, dependentAxis } = props;
    const generalAxisStyle = theme && theme.axis && theme.axis.style;
    const axisType = dependentAxis ? "dependentAxis" : "independentAxis";
    const specificAxisStyle = theme && theme[axisType] && theme[axisType].style;

    return generalAxisStyle && specificAxisStyle
      ? defaultsDeep({},
          specificAxisStyle,
          generalAxisStyle
        )
      : specificAxisStyle || generalAxisStyle;
  },

  getStyles(props, styleObject) {
    const style = props.style || {};
    styleObject = styleObject || {};
    const parentStyleProps = { height: "auto", width: "100%" };
    return {
      parent: defaults(parentStyleProps, style.parent, styleObject.parent),
      axis: defaults({}, style.axis, styleObject.axis),
      axisLabel: defaults({}, style.axisLabel, styleObject.axisLabel),
      grid: defaults({}, style.grid, styleObject.grid),
      ticks: defaults({}, style.ticks, styleObject.ticks),
      tickLabels: defaults({}, style.tickLabels, styleObject.tickLabels)
    };
  },

  getTickProps(layout, style, datum) {
    const { position, transform } = layout;
    return {
      x1: transform.x,
      y1: transform.y,
      x2: transform.x + position.x2,
      y2: transform.y + position.y2,
      style,
      datum
    };
  },

  getTickLabelProps(layout, style, anchors, datum, text) { // eslint-disable-line max-params
    const { position, transform } = layout;
    return {
      style,
      x: transform.x + position.x,
      y: transform.y + position.y,
      verticalAnchor: anchors.verticalAnchor,
      textAnchor: anchors.textAnchor,
      angle: style.angle,
      text,
      datum
    };
  },

  getGridProps(layout, style, datum) {
    const {edge, transform} = layout;
    return {
      x1: transform.x,
      y1: transform.y,
      x2: edge.x + transform.x,
      y2: edge.y + transform.y,
      style,
      datum
    };
  },

  getAxisProps(modifiedProps, calculatedValues, globalTransform) {
    const { style, padding, isVertical } = calculatedValues;
    const { width, height } = modifiedProps;
    return {
      style: style.axis,
      x1: isVertical ? globalTransform.x : padding.left + globalTransform.x,
      x2: isVertical ? globalTransform.x : width - padding.right + globalTransform.x,
      y1: isVertical ? padding.top + globalTransform.y : globalTransform.y,
      y2: isVertical ? height - padding.bottom + globalTransform.y : globalTransform.y
    };
  },

  getLayoutProps(modifiedProps, calculatedValues) {
    const offset = this.getOffset(modifiedProps, calculatedValues);
    return {
      globalTransform: this.getTransform(modifiedProps, calculatedValues, offset),
      gridOffset: this.getGridOffset(modifiedProps, calculatedValues, offset),
      gridEdge: this.getGridEdge(modifiedProps, calculatedValues)
    };
  },

  getEvaluatedStyles(style, tick, index) {
    return {
      tickStyle: Helpers.evaluateStyle(style.ticks, tick, index),
      labelStyle: Helpers.evaluateStyle(style.tickLabels, tick, index),
      gridStyle: Helpers.evaluateStyle(style.grid, tick, index)
    };
  },

  getRole(props) {
    if (props.dependentAxis) {
      return props.theme && props.theme.dependentAxis
        ? "dependentAxis"
        : "axis";
    }

    return props.theme && props.theme.independentAxis
      ? "independentAxis"
      : "axis";
  },

  getShallowMergedThemeProps(props, role) {
    const axisTheme = props.theme.axis || {};
    return defaults({}, props.theme[role], axisTheme);
  },

  modifyProps(props, fallbackProps, role) {
    if (role !== "axis") {
      props.theme[role] = this.getShallowMergedThemeProps(props, role);
    }
    return Helpers.modifyProps(props, fallbackProps, role);
  },

  getBaseProps(props, fallbackProps) {
    const role = this.getRole(props);
    props = this.modifyProps(props, fallbackProps, role);
    const calculatedValues = this.getCalculatedValues(props);
    const {
      style, orientation, isVertical, scale, ticks, tickFormat, stringTicks, anchors
    } = calculatedValues;

    const {
      globalTransform, gridOffset, gridEdge
    } = this.getLayoutProps(props, calculatedValues);

    const axisProps = this.getAxisProps(props, calculatedValues, globalTransform);
    const axisLabelProps = this.getAxisLabelProps(props, calculatedValues, globalTransform);

    const childProps = { parent: {
      style: style.parent, ticks, scale, width: props.width, height: props.height
    }};
    for (let index = 0, len = ticks.length; index < len; index++) {
      const tick = stringTicks ? props.tickValues[(ticks[index]) - 1] : ticks[index];

      const styles = this.getEvaluatedStyles(style, tick, index);
      const tickLayout = {
        position: this.getTickPosition(styles, orientation, isVertical),
        transform: this.getTickTransform(scale(ticks[index]), globalTransform, isVertical)
      };

      const gridLayout = {
        edge: gridEdge,
        transform: {
          x: isVertical ?
            -gridOffset.x + globalTransform.x : scale(ticks[index]) + globalTransform.x,
          y: isVertical ?
            scale(ticks[index]) + globalTransform.y : gridOffset.y + globalTransform.y
        }
      };
      childProps[index] = {
        axis: axisProps,
        axisLabel: axisLabelProps,
        ticks: this.getTickProps(tickLayout, styles.tickStyle, tick),
        tickLabels: this.getTickLabelProps(
          tickLayout, styles.labelStyle, anchors, tick, tickFormat(tick, index)
        ),
        grid: this.getGridProps(gridLayout, styles.gridStyle, tick)
      };
    }
    return childProps;
  },

  getCalculatedValues(props) {
    const defaultStyles = this.getStyleObject(props);
    const style = this.getStyles(props, defaultStyles);
    const padding = Helpers.getPadding(props);
    const orientation = props.orientation || (props.dependentAxis ? "left" : "bottom");
    const isVertical = Helpers.isVertical(props);
    const labelPadding = this.getLabelPadding(props, style);
    const stringTicks = Helpers.stringTicks(props);
    const scale = this.getScale(props);
    const ticks = this.getTicks(props, scale);
    const tickFormat = this.getTickFormat(props, scale, ticks);
    const anchors = this.getAnchors(orientation, isVertical);

    return {
      style, padding, orientation, isVertical, labelPadding, stringTicks,
      anchors, scale, ticks, tickFormat
    };
  },

  getAxisLabelProps(props, calculatedValues, globalTransform) {
    const {style, orientation, padding, labelPadding, isVertical} = calculatedValues;
    const sign = orientationSign[orientation];
    const hPadding = padding.left + padding.right;
    const vPadding = padding.top + padding.bottom;
    const verticalAnchor = sign < 0 ? "end" : "start";
    const labelStyle = style.axisLabel;
    const angle = isVertical ? -90 : 0;
    const x = isVertical ? globalTransform.x + (sign * labelPadding) :
      ((props.width - hPadding) / 2) + padding.left + globalTransform.x;
    const y = isVertical ?
      ((props.height - vPadding) / 2) + padding.bottom + globalTransform.y :
      (sign * labelPadding) + globalTransform.y;
    return {
      x,
      y,
      verticalAnchor: labelStyle.verticalAnchor || verticalAnchor,
      textAnchor: labelStyle.textAnchor || "middle",
      angle: labelStyle.angle || angle,
      style: labelStyle,
      text: props.label
    };
  },

  getTicks(props, scale) {
    if (props.tickValues) {
      if (Helpers.stringTicks(props)) {
        return range(1, props.tickValues.length + 1);
      }
      return props.tickValues.length ? props.tickValues : scale.domain();
    } else if (scale.ticks && isFunction(scale.ticks)) {
      const scaleTicks = scale.ticks(props.tickCount);
      const ticks = Array.isArray(scaleTicks) && scaleTicks.length ? scaleTicks : scale.domain();
      if (props.crossAxis) {
        return includes(ticks, 0) ? without(ticks, 0) : ticks;
      }
      return ticks;
    }
    return scale.domain();
  },

  getAnchors(orientation, isVertical) {
    const anchorOrientation = { top: "end", left: "end", right: "start", bottom: "start" };
    const anchor = anchorOrientation[orientation];
    return {
      textAnchor: isVertical ? anchor : "middle",
      verticalAnchor: isVertical ? "middle" : anchor
    };
  },

  getTickFormat(props, scale) {
    if (props.tickFormat && isFunction(props.tickFormat)) {
      return props.tickFormat;
    } else if (props.tickFormat && Array.isArray(props.tickFormat)) {
      return (x, index) => props.tickFormat[index];
    } else if (Helpers.stringTicks(props)) {
      return (x, index) => props.tickValues[index];
    } else if (scale.tickFormat && isFunction(scale.tickFormat)) {
      return scale.tickFormat();
    } else {
      return (x) => x;
    }
  },

  getLabelPadding(props, style) {
    const labelStyle = style.axisLabel || {};
    if (typeof labelStyle.padding !== "undefined" && labelStyle.padding !== null) {
      return labelStyle.padding;
    }
    const isVertical = Helpers.isVertical(props);
    // TODO: magic numbers
    const fontSize = labelStyle.fontSize || 14;
    return props.label ? (fontSize * (isVertical ? 2.3 : 1.6)) : 0;
  },

  getOffset(props, calculatedValues) {
    const {
      style, padding, isVertical, orientation, labelPadding, stringTicks, ticks
    } = calculatedValues;
    const xPadding = orientation === "right" ? padding.right : padding.left;
    const yPadding = orientation === "top" ? padding.top : padding.bottom;
    const fontSize = style.axisLabel.fontSize || 14;
    const offsetX = (props.offsetX !== null) && (props.offsetX !== undefined)
      ? props.offsetX : xPadding;
    const offsetY = (props.offsetY !== null) && (props.offsetY !== undefined)
      ? props.offsetY : yPadding;
    const tickSizes = ticks.map((data) => {
      const tick = stringTicks ? props.tickValues[data - 1] : data;
      const tickStyle = Helpers.evaluateStyle(style.ticks, tick);
      return tickStyle.size || 0;
    });
    const totalPadding = fontSize + (2 * Math.max(...tickSizes)) + labelPadding;
    const minimumPadding = 1.2 * fontSize; // TODO: magic numbers
    const x = isVertical ? totalPadding : minimumPadding;
    const y = isVertical ? minimumPadding : totalPadding;
    return {
      x: (offsetX !== null) && (offsetX !== undefined) ? offsetX : x,
      y: (offsetY !== null) && (offsetY !== undefined) ? offsetY : y
    };
  },

  getTransform(props, calculatedValues, offset) {
    const {orientation} = calculatedValues;
    return {
      top: {x: 0, y: offset.y},
      bottom: {x: 0, y: props.height - offset.y},
      left: {x: offset.x, y: 0},
      right: {x: props.width - offset.x, y: 0}
    }[orientation];
  },

  getTickPosition(style, orientation, isVertical) {
    const {tickStyle, labelStyle} = style;
    const size = tickStyle.size || 0;
    const tickPadding = tickStyle.padding || 0;
    const labelPadding = labelStyle.padding || 0;
    const tickSpacing = size + tickPadding + labelPadding;
    const sign = orientationSign[orientation];
    return {
      x: isVertical ? sign * tickSpacing : 0,
      x2: isVertical ? sign * size : 0,
      y: isVertical ? 0 : sign * tickSpacing,
      y2: isVertical ? 0 : sign * size
    };
  },

  getTickTransform(tick, globalTransform, isVertical) {
    return {
      x: isVertical ? globalTransform.x : tick + globalTransform.x,
      y: isVertical ? tick + globalTransform.y : globalTransform.y
    };
  },

  getGridEdge(props, calculatedValues) {
    const {orientation, padding, isVertical} = calculatedValues;
    const sign = -orientationSign[orientation];
    const x = isVertical ?
      sign * (props.width - (padding.left + padding.right)) : 0;
    const y = isVertical ?
      0 : sign * (props.height - (padding.top + padding.bottom));
    return {x, y};
  },

  getGridOffset(props, calculatedValues, offset) {
    const {padding, orientation } = calculatedValues;
    const xPadding = orientation === "right" ? padding.right : padding.left;
    const yPadding = orientation === "top" ? padding.top : padding.bottom;
    return {
      x: props.crossAxis ? offset.x - xPadding : 0,
      y: props.crossAxis ? offset.y - yPadding : 0
    };
  }
};
<|endoftext|>


<commit_before><commit_msg>remove linesPerSecond<commit_after><|endoftext|>