<commit_before>(function() {
  'use strict';

  angular
  .module('roboconf.instances')
  .controller('InstancesListingController', instancesListingController);

  instancesListingController.$inject = [
    '$scope', 'rUtils', '$routeParams',
    'rShare', '$window', 'rClient', 'rWebSocket'
  ];

  function instancesListingController($scope, rUtils, $routeParams, rShare, $window, rClient, rWebSocket) {

    // Fields
    $scope.responseStatus = -1;
    $scope.searchFilter = '';
    $scope.searchVisible = true;
    $scope.template = '';
    $scope.deletionAsked = false;
    $scope.orderingCriteria = 'instance.name';
    $scope.details = 'LIFECYCLE';

    // Menu actions
    $scope.menuActions = [
      {title: 'Create a New Instance', link: '#/app/' + $routeParams.appName + '/instances/new'},
      {title: 'separator'},
      {title: 'Deploy and Start All', fn: function() {
        performAll('deploy-all', false);
      }},
      {title: 'Stop All', fn: function() {
        performAll('stop-all', false);
      }},
      {title: 'Undeploy All', link: '', fn: function() {
        performAll('undeploy-all', false);
      }},
      {title: 'separator'},
      {title: 'Sort by name', link: '', fn: function() {
        if ($scope.orderingCriteria === 'instance.name') {
          $scope.orderingCriteria = '-instance.name';
        } else {
          $scope.orderingCriteria = 'instance.name';
        }
      }},
      {title: 'Sort by state', link: '', fn: function() {
        if ($scope.orderingCriteria === 'instance.status') {
          $scope.orderingCriteria = '-instance.status';
        } else {
          $scope.orderingCriteria = 'instance.status';
        }
      }}
    ];

    // Function declarations
    $scope.loadInstances = loadInstances;
    $scope.showInstance = showInstance;
    $scope.hideInstance = hideInstance;
    $scope.formatStatus = formatStatus;
    $scope.isNodeToHide = isNodeToHide;
    $scope.changeState = changeState;
    $scope.performAll = performAll;
    $scope.createChildInstance = createChildInstance;
    $scope.replicateInstance = replicateInstance;
    $scope.deleteInstance = deleteInstance;
    $scope.showDetailsSection = showDetailsSection;
    $scope.askToDelete = askToDelete;

    // Initial actions
    rClient.findApplication($routeParams.appName).then(function(app) {
      $scope.app = app;
      if (app.fake) {
        $scope.responseStatus = 404;
      } else {
        $scope.responseStatus = 0;
        loadInstances();
      }
    });

    // Manage the web socket
    var webSocket = rWebSocket.newWebSocket();
    webSocket.onmessage = onWebSocketMessage;
    $scope.$on('$routeChangeStart', function(event) {
      webSocket.close();
    });

    // Functions
    function loadInstances() {
      rClient.listInstances($routeParams.appName).then(function(instances) {
        $scope.responseStatus = 0;
        $scope.rootNodes = rUtils.buildInstancesTree(instances);

      }, function(response) {
        $scope.responseStatus = response.status;
      });
    }

    function showInstance(node, t) {
      var instance = node.instance;
      $scope.selectedInstance = instance;
      rUtils.showRightBlock(t);

      var isRoot = false;
      if (instance && instance.component && instance.component.installer) {
        isRoot = instance.component.installer.toLowerCase() === 'target';
      }

      var parentNotDeployed = isParentNotDeployed(node);
      $scope.template = findTemplateUrl(instance.status, isRoot, parentNotDeployed);
    }

    function showDetailsSection(section) {
      $scope.details = section;
    }

    function hideInstance() {
      $scope.selectedInstance = null;
      rUtils.hideRightBlock();
    }

    function createChildInstance() {
      if ($scope.selectedInstance) {
        rShare.feedLastItem($scope.selectedInstance);
        $window.location = '#/app/' + $routeParams.appName + '/instances/new';
      }
    }

    function replicateInstance() {
      if ($scope.selectedInstance) {
        $scope.selectedInstance.copy = true;
        createChildInstance();
      }
    }

    function askToDelete() {
      $scope.deletionAsked = ! $scope.deletionAsked;
    }

    function deleteInstance() {

      rClient.deleteInstance($routeParams.appName, $scope.selectedInstance.path).then(function() {
        $scope.deletionAsked = false;
        // The instance will be deleted once notified by the web socket.
      });
    }

    function changeState(newState) {
      rClient.changeInstanceState($routeParams.appName, $scope.selectedInstance.path, newState);
    }

    function performAll(action, useInstance) {

      var path = useInstance ? $scope.selectedInstance.path : null;
      rClient.performActionOnInstance($scope.app.name, path, action).then($scope.loadInstances);
    }

    function formatStatus(status) {
      var result = '';

      switch (status) {
      case 'NOT_DEPLOYED': result = 'STATUS_NOT_DEPLOYED'; break;
      case 'STARTING': result = 'STATUS_STARTING'; break;
      case 'DEPLOYING': result = 'STATUS_DEPLOYING_2'; break;
      case 'UNDEPLOYING': result = 'STATUS_UNDEPLOYING_2'; break;
      case 'STOPPING': result = 'STATUS_STOPPING'; break;
      case 'UNRESOLVED': result = 'STATUS_UNRESOLVED_2'; break;
      case 'DEPLOYED_STOPPED': result = 'STATUS_DEPLOYED_AND_STOPPED'; break;
      case 'DEPLOYED_STARTED': result = 'STATUS_DEPLOYED_AND_STARTED'; break;
      case 'PROBLEM': result = 'STATUS_UNDETERMINED'; break;
      case 'WAITING_FOR_ANCESTOR': result = 'STATUS_WAITING_ANCESTOR_2'; break;
      case 'CUSTOM': result = 'STATUS_CUSTOM'; break;
      }

      return result;
    }

    function isParentNotDeployed(node) {
      node = node || {};
      while (node.parent) {
        node = node.parent;
      }

      return node.instance.status === 'NOT_DEPLOYED';
    }

    function findTemplateUrl(status, isRoot, isParentNotDeployed) {

      var result;
      if (! isRoot && isParentNotDeployed) {
        result = 'app-not-deployed-no-action';
      } else {
        result = 'app' + (isRoot ? '-root' : '') + '-';
        result += status.toLowerCase().replace('_', '-');
      }

      return 'templates/instances/includes/' + result + '.html';
    }

    function isNodeToHide(instancePath) {

      // This method is only invoked on root nodes.
      // So, paths are always like '/a-sequence-without-other-slashes'
      return !! $scope.selectedInstance &&
        typeof $scope.selectedInstance.path === 'string' &&
        $scope.selectedInstance.path !== instancePath &&
        ! rUtils.startsWith($scope.selectedInstance.path, instancePath + '/');
    }

    function onWebSocketMessage(event) {

      if (event.data) {
        var obj = JSON.parse(event.data);
        if (obj.app && obj.app.name === $routeParams.appName && obj.inst) {
          var instancePath = obj.inst.path;

          // Deletion
          if (obj.event === 'DELETED') {
            rUtils.deleteInstanceNode(instancePath, $scope.rootNodes);
            if ($scope.selectedInstance && $scope.selectedInstance.path === instancePath) {
              hideInstance();
            }
          }

          // Change
          else if (obj.event === 'CHANGED') {
            var node = rUtils.findInstanceNode(instancePath, $scope.rootNodes);
            if (node) {
              node.instance.status = obj.inst.status;
              if (obj.inst.data && obj.inst.data['ip.address']) {
                node.instance.data['ip.address'] = obj.inst.data['ip.address'];
              } else {
                delete node.instance.data['ip.address'];
              }

              if ($scope.selectedInstance && $scope.selectedInstance.path === instancePath) {
                showInstance(node, 0);
              }
            }
          }

          // Creation
          else if (obj.event === 'CREATED') {
            var instancesToAdd = [obj.inst];
            rUtils.buildInstancesTree(instancesToAdd, null, null, $scope.rootNodes);
          }

          // When doing demos with several web browsers, the view is updated
          // only in the foreground browser. To force the refresh every time,
          // even in background, we must force the refreshment.
          $scope.$apply();
        }
      }
    }
  }
})();
<commit_msg>Fix a bug for children instances<commit_after>(function() {
  'use strict';

  angular
  .module('roboconf.instances')
  .controller('InstancesListingController', instancesListingController);

  instancesListingController.$inject = [
    '$scope', 'rUtils', '$routeParams',
    'rShare', '$window', 'rClient', 'rWebSocket'
  ];

  function instancesListingController($scope, rUtils, $routeParams, rShare, $window, rClient, rWebSocket) {

    // Fields
    $scope.responseStatus = -1;
    $scope.searchFilter = '';
    $scope.searchVisible = true;
    $scope.template = '';
    $scope.deletionAsked = false;
    $scope.orderingCriteria = 'instance.name';
    $scope.details = 'LIFECYCLE';

    // Menu actions
    $scope.menuActions = [
      {title: 'Create a New Instance', link: '#/app/' + $routeParams.appName + '/instances/new'},
      {title: 'separator'},
      {title: 'Deploy and Start All', fn: function() {
        performAll('deploy-all', false);
      }},
      {title: 'Stop All', fn: function() {
        performAll('stop-all', false);
      }},
      {title: 'Undeploy All', link: '', fn: function() {
        performAll('undeploy-all', false);
      }},
      {title: 'separator'},
      {title: 'Sort by name', link: '', fn: function() {
        if ($scope.orderingCriteria === 'instance.name') {
          $scope.orderingCriteria = '-instance.name';
        } else {
          $scope.orderingCriteria = 'instance.name';
        }
      }},
      {title: 'Sort by state', link: '', fn: function() {
        if ($scope.orderingCriteria === 'instance.status') {
          $scope.orderingCriteria = '-instance.status';
        } else {
          $scope.orderingCriteria = 'instance.status';
        }
      }}
    ];

    // Function declarations
    $scope.loadInstances = loadInstances;
    $scope.showInstance = showInstance;
    $scope.hideInstance = hideInstance;
    $scope.formatStatus = formatStatus;
    $scope.isNodeToHide = isNodeToHide;
    $scope.changeState = changeState;
    $scope.performAll = performAll;
    $scope.createChildInstance = createChildInstance;
    $scope.replicateInstance = replicateInstance;
    $scope.deleteInstance = deleteInstance;
    $scope.showDetailsSection = showDetailsSection;
    $scope.askToDelete = askToDelete;

    // Initial actions
    rClient.findApplication($routeParams.appName).then(function(app) {
      $scope.app = app;
      if (app.fake) {
        $scope.responseStatus = 404;
      } else {
        $scope.responseStatus = 0;
        loadInstances();
      }
    });

    // Manage the web socket
    var webSocket = rWebSocket.newWebSocket();
    webSocket.onmessage = onWebSocketMessage;
    $scope.$on('$routeChangeStart', function(event) {
      webSocket.close();
    });

    // Functions
    function loadInstances() {
      rClient.listInstances($routeParams.appName).then(function(instances) {
        $scope.responseStatus = 0;
        $scope.rootNodes = rUtils.buildInstancesTree(instances);

      }, function(response) {
        $scope.responseStatus = response.status;
      });
    }

    function showInstance(node, t) {
      var instance = node.instance;
      $scope.selectedInstance = instance;
      rUtils.showRightBlock(t);

      var isRoot = false;
      if (instance && instance.component && instance.component.installer) {
        isRoot = instance.component.installer.toLowerCase() === 'target';
      }

      var parentNotDeployed = isParentNotDeployed(node);
      $scope.template = findTemplateUrl(instance.status, isRoot, parentNotDeployed);
    }

    function showDetailsSection(section) {
      $scope.details = section;
    }

    function hideInstance() {
      $scope.selectedInstance = null;
      rUtils.hideRightBlock();
    }

    function createChildInstance() {
      if ($scope.selectedInstance) {
        rShare.feedLastItem($scope.selectedInstance);
        $window.location = '#/app/' + $routeParams.appName + '/instances/new';
      }
    }

    function replicateInstance() {
      if ($scope.selectedInstance) {
        $scope.selectedInstance.copy = true;
        createChildInstance();
      }
    }

    function askToDelete() {
      $scope.deletionAsked = ! $scope.deletionAsked;
    }

    function deleteInstance() {

      rClient.deleteInstance($routeParams.appName, $scope.selectedInstance.path).then(function() {
        $scope.deletionAsked = false;
        // The instance will be deleted once notified by the web socket.
      });
    }

    function changeState(newState) {
      rClient.changeInstanceState($routeParams.appName, $scope.selectedInstance.path, newState);
    }

    function performAll(action, useInstance) {

      var path = useInstance ? $scope.selectedInstance.path : null;
      rClient.performActionOnInstance($scope.app.name, path, action).then($scope.loadInstances);
    }

    function formatStatus(status) {
      var result = '';

      switch (status) {
      case 'NOT_DEPLOYED': result = 'STATUS_NOT_DEPLOYED'; break;
      case 'STARTING': result = 'STATUS_STARTING'; break;
      case 'DEPLOYING': result = 'STATUS_DEPLOYING_2'; break;
      case 'UNDEPLOYING': result = 'STATUS_UNDEPLOYING_2'; break;
      case 'STOPPING': result = 'STATUS_STOPPING'; break;
      case 'UNRESOLVED': result = 'STATUS_UNRESOLVED_2'; break;
      case 'DEPLOYED_STOPPED': result = 'STATUS_DEPLOYED_AND_STOPPED'; break;
      case 'DEPLOYED_STARTED': result = 'STATUS_DEPLOYED_AND_STARTED'; break;
      case 'PROBLEM': result = 'STATUS_UNDETERMINED'; break;
      case 'WAITING_FOR_ANCESTOR': result = 'STATUS_WAITING_ANCESTOR_2'; break;
      case 'CUSTOM': result = 'STATUS_CUSTOM'; break;
      }

      return result;
    }

    function isParentNotDeployed(node) {
      node = node || {};
      while (node.parent) {
        node = node.parent;
      }

      return node.instance.status === 'NOT_DEPLOYED';
    }

    function findTemplateUrl(status, isRoot, isParentNotDeployed) {

      var result;
      if (! isRoot && isParentNotDeployed) {
        result = 'app-not-deployed-no-action';
      } else {
        result = 'app' + (isRoot ? '-root' : '') + '-';
        result += status.toLowerCase().replace('_', '-');
      }

      return 'templates/instances/includes/' + result + '.html';
    }

    function isNodeToHide(instancePath) {

      // This method is only invoked on root nodes.
      // So, paths are always like '/a-sequence-without-other-slashes'
      return !! $scope.selectedInstance &&
        typeof $scope.selectedInstance.path === 'string' &&
        $scope.selectedInstance.path !== instancePath &&
        ! rUtils.startsWith($scope.selectedInstance.path, instancePath + '/');
    }

    function onWebSocketMessage(event) {

      if (event.data) {
        var obj = JSON.parse(event.data);
        if (obj.app && obj.app.name === $routeParams.appName && obj.inst) {
          var instancePath = obj.inst.path;

          // Deletion
          if (obj.event === 'DELETED') {
            rUtils.deleteInstanceNode(instancePath, $scope.rootNodes);
            if ($scope.selectedInstance && $scope.selectedInstance.path === instancePath) {
              hideInstance();
            }
          }

          // Change
          else if (obj.event === 'CHANGED') {
            var node = rUtils.findInstanceNode(instancePath, $scope.rootNodes);
            if (node) {
              node.instance.status = obj.inst.status;
              if (obj.inst.data && obj.inst.data['ip.address']) {
                node.instance.data['ip.address'] = obj.inst.data['ip.address'];
              } else if (node.instance.data) {
                delete node.instance.data['ip.address'];
              }

              if ($scope.selectedInstance && $scope.selectedInstance.path === instancePath) {
                showInstance(node, 0);
              }
            } else {
              console.log('Node ' + instancePath + ' was not found (web socket callback for instance).');
            }
          }

          // Creation
          else if (obj.event === 'CREATED') {
            var instancesToAdd = [obj.inst];
            rUtils.buildInstancesTree(instancesToAdd, null, null, $scope.rootNodes);
          }

          // When doing demos with several web browsers, the view is updated
          // only in the foreground browser. To force the refresh every time,
          // even in background, we must force the refreshment.
          $scope.$apply();
        }
      }
    }
  }
})();
<|endoftext|>


<commit_before>(function(describe){
    "use strict";
    describe("chu controllers test suite", function(){
        var createController, $scope, $stateParams, $httpBackend, $state, adminApi;
        var formService, SERVER_URL;

        beforeEach(function(){
            module("mflAdminApp");
            inject(["$rootScope", "$controller", "$stateParams", "$httpBackend",
                   "$state", "adminApi","mfl.common.forms.changes","SERVER_URL",
                   function($rootScope, $controller,_$stateParams,
                    _$httpBackend, _$state, _adminApi, frm, _SERVER_URL){
                $scope = $rootScope.$new();
                SERVER_URL = _SERVER_URL;
                $httpBackend = _$httpBackend;
                $stateParams = _$stateParams;
                $state = _$state;
                adminApi = _adminApi;
                formService = frm;
                var data = {
                    $scope: $scope
                };
                createController = function(ctrl, params){
                    return $controller(ctrl, _.extend(data, params));

                };
            }]);
        });

        afterEach(function(){
            $httpBackend.verifyNoOutstandingRequest();
        });

        it("should have `mfl.setup.controller.chuStatus.town` defined",
           function(){
                var ctrl = createController("mfl.setup.controller.town.list", {});
                expect(ctrl).toBeDefined();
            });
    });
})(describe);
<commit_msg>added towns tests suite<commit_after>(function(describe){
    "use strict";
    describe("towns controllers test suite", function(){
        var createController, $scope, $stateParams, $httpBackend, $state, adminApi;
        var formService, SERVER_URL;

        beforeEach(function(){
            module("mflAdminApp");
            inject(["$rootScope", "$controller", "$stateParams", "$httpBackend",
                   "$state", "adminApi","mfl.common.forms.changes","SERVER_URL",
                   function($rootScope, $controller,_$stateParams,
                    _$httpBackend, _$state, _adminApi, frm, _SERVER_URL){
                $scope = $rootScope.$new();
                SERVER_URL = _SERVER_URL;
                $httpBackend = _$httpBackend;
                $stateParams = _$stateParams;
                $state = _$state;
                adminApi = _adminApi;
                formService = frm;
                var data = {
                    $scope: $scope
                };
                createController = function(ctrl, params){
                    return $controller(ctrl, _.extend(data, params));

                };
            }]);
        });

        afterEach(function(){
            $httpBackend.verifyNoOutstandingRequest();
        });

        it("should have `mfl.setup.controller.chuStatus.town` defined",
           function(){
                var ctrl = createController("mfl.setup.controller.town.list", {});
                expect(ctrl).toBeDefined();
            });
    });
})(describe);
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";

export default class CohortStatsFilter extends LitElement {

    constructor() {
        super();

        // Set status and init private properties
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            cohorts: {
                type: Array
            },
            onlyCohortAll: {
                type: Boolean
            },
            cohortStatsAlt: {
                type: String
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);

        this.defaultComparator = "<";
    }

    connectedCallback() {
        super.connectedCallback();

        this.cohortsPerStudy = this.cohorts ? this.cohorts[this.opencgaSession.study.id] : null;
        this.state = {};
    }

    update(changedProperties) {
        if (changedProperties.has("opencgaSession") || changedProperties.has("cohorts")) {
            this.state = {};
            this.cohortsPerStudy = this._getCohorts();
            // this.requestUpdate();
        }

        if (changedProperties.has("cohortStatsAlt")) {
            this.state = {};
            if (this.cohortStatsAlt) {
                const cohorts = this.cohortStatsAlt.split(";");
                cohorts.forEach(cohortStat => {
                    const [studyId, cohortFreq] = cohortStat.split(":");
                    if (!this.state[studyId]) {
                        this.state[studyId] = [];
                    }
                    const [cohort, comparator, value] = cohortFreq.split(/(<=?|>=?|=)/);
                    this.state[studyId].push({cohort, comparator, value});
                });
            }
            // this.requestUpdate();
        }
        super.update(changedProperties);
    }

    _getCohorts() {
        let studiesAndCohorts = [];
        if (this.opencgaSession?.project?.studies) { //  && this.onlyCohortAll
            for (const study of this.opencgaSession.project.studies) {
                if (study.cohorts?.length) {
                    if (this.onlyCohortAll) {
                        studiesAndCohorts.push({
                            ...study,
                            cohorts: [{id: "ALL"}]
                        });
                    } else {
                        studiesAndCohorts = this.cohorts;
                    }
                }
            }
        }
        return studiesAndCohorts;
    }

    handleCollapseAction(e) {
        const id = e.target.dataset.id;
        const elem = $("#" + id)[0];
        elem.hidden = !elem.hidden;
        if (elem.hidden) {
            e.target.className = "fa fa-plus";
        } else {
            e.target.className = "fa fa-minus";
        }
    }

    getStudyIdFromFqn(fqn) {
        // replaces characters not valid in an DOM Element ID
        return fqn.split(":")[1]?.replace(/@|:/g, "_");
    }

    filterChange(e, study, cohort) {
        e.stopPropagation();

        // e.detail.value is not defined iff you are changing the comparator and a value hasn't been set yet
        const index = this.state[study]?.findIndex(c => c.cohort === cohort);
        if (e?.detail?.value) {
            if (index >= 0) {
                this.state[study][index].comparator = e.detail.comparator;
                this.state[study][index].value = e.detail.numValue;
            } else {
                if (!this.state[study]) {
                    this.state[study] = [];
                }
                this.state[study].push({cohort: cohort, comparator: e.detail.comparator, value: e.detail.numValue});
            }
        } else {
            if (index >= 0) {
                this.state[study].splice(index, 1);
            }

            // If not cohort are left then we remove everything?
            if (this.state[study].length === 0) {
                delete this.state[study];
            }
        }

        // serialize this.state in the form of "STUDY_ID:COHORT_ID<VALUE;.."
        const value = Object.entries(this.state)
            // .filter(([, v]) => v.value)
            .map(([studyId, cohorts]) => {
                return cohorts.map(c => `${studyId}:${c.cohort}${c.comparator}${c.value}`).join(";");
            })
            .join(";");
        const event = new CustomEvent("filterChange", {
            detail: {
                value: value
            }
        });
        this.dispatchEvent(event);
    }

    render() {
        if (!this.cohortsPerStudy?.length) {
            return html`<span>Cohort Variants Stats not available.</span>`;
        }

        return html`
            ${this.cohortsPerStudy
            .map(study => html`

                        Study ${this.getStudyIdFromFqn(study.fqn)} cohorts

                        ${study.cohorts.map(cohort => {
                            const stateCohort = this.state?.[study.id]?.find(c => c.id === cohort.id);
                            return html`

                                    <number-field-filter
                                        .value="${stateCohort?.value ?
                                            (this.state?.[study.id]?.comparator ?? this.defaultComparator) + (this.state?.[study.id]?.value ?? "") :
                                            ""}"
                                        .config="${{comparator: true, layout: [3, 4, 5]}}"
                                        .label="${cohort.id}"
                                        type="text"
                                        data-study="${study.id}"
                                        data-cohort="${cohort.id}"
                                        data-action="comparator"
                                        @filterChange="${e => this.filterChange(e, study.id, cohort.id)}">
                                </number-field-filter>

`;
                        })}

            `)}`;
    }

}

customElements.define("cohort-stats-filter", CohortStatsFilter);
<commit_msg>wc: cohort-stats-filter.js bugs fixed #475<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import "../forms/number-field-filter.js";

export default class CohortStatsFilter extends LitElement {

    constructor() {
        super();

        // Set status and init private properties
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            cohorts: {
                type: Array
            },
            onlyCohortAll: {
                type: Boolean
            },
            cohortStatsAlt: {
                type: String
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);

        this.defaultComparator = "<";
    }

    connectedCallback() {
        super.connectedCallback();

        this.cohortsPerStudy = this.cohorts ? this.cohorts[this.opencgaSession.study.id] : null;
        this.state = {};
    }

    update(changedProperties) {
        if (changedProperties.has("opencgaSession") || changedProperties.has("cohorts")) {
            this.state = {};
            this.cohortsPerStudy = this._getCohorts();
            // this.requestUpdate();
        }

        if (changedProperties.has("cohortStatsAlt")) {
            this.state = {};
            if (this.cohortStatsAlt) {
                const cohorts = this.cohortStatsAlt.split(";");
                cohorts.forEach(cohortStat => {
                    const [studyId, cohortFreq] = cohortStat.split(":");
                    if (!this.state[studyId]) {
                        this.state[studyId] = [];
                    }
                    const [cohort, comparator, value] = cohortFreq.split(/(<=?|>=?|=)/);
                    this.state[studyId].push({cohort, comparator, value});
                });
            }
            // this.requestUpdate();
        }
        super.update(changedProperties);
    }

    _getCohorts() {
        let studiesAndCohorts = [];
        if (this.opencgaSession?.project?.studies) { //  && this.onlyCohortAll
            for (const study of this.opencgaSession.project.studies) {
                if (study.cohorts?.length) {
                    if (this.onlyCohortAll) {
                        studiesAndCohorts.push({
                            ...study,
                            cohorts: [{id: "ALL"}]
                        });
                    } else {
                        studiesAndCohorts = this.cohorts;
                    }
                }
            }
        }
        return studiesAndCohorts;
    }

    handleCollapseAction(e) {
        const id = e.target.dataset.id;
        const elem = $("#" + id)[0];
        elem.hidden = !elem.hidden;
        if (elem.hidden) {
            e.target.className = "fa fa-plus";
        } else {
            e.target.className = "fa fa-minus";
        }
    }

    getStudyIdFromFqn(fqn) {
        // replaces characters not valid in an DOM Element ID
        return fqn.split(":")[1]?.replace(/@|:/g, "_");
    }

    filterChange(e, study, cohort) {
        e.stopPropagation();

        // e.detail.value is not defined iff you are changing the comparator and a value hasn't been set yet
        const index = this.state[study]?.findIndex(c => c.cohort === cohort);
        if (e?.detail?.value) {
            if (index >= 0) {
                this.state[study][index].comparator = e.detail.comparator;
                this.state[study][index].value = e.detail.numValue;
            } else {
                if (!this.state[study]) {
                    this.state[study] = [];
                }
                this.state[study].push({cohort: cohort, comparator: e.detail.comparator, value: e.detail.numValue});
            }
        } else {
            if (index >= 0) {
                this.state[study].splice(index, 1);
            }

            // If not cohort are left then we remove everything?
            if (this.state[study]?.length === 0) {
                delete this.state[study];
            }
        }

        // serialize this.state in the form of "STUDY_ID:COHORT_ID<VALUE;.."
        const value = Object.entries(this.state)
            // .filter(([, v]) => v.value)
            .map(([studyId, cohorts]) => {
                return cohorts.map(c => `${studyId}:${c.cohort}${c.comparator}${c.value}`).join(";");
            })
            .join(";");
        const event = new CustomEvent("filterChange", {
            detail: {
                value: value
            }
        });
        this.dispatchEvent(event);
    }

    render() {
        if (!this.cohortsPerStudy?.length) {
            return html`<span>Cohort Variants Stats not available.</span>`;
        }

        return html`
            ${this.cohortsPerStudy
            .map(study => html`

                        Study ${this.getStudyIdFromFqn(study.fqn)} cohorts

                        ${study.cohorts.map(cohort => {
                            const stateCohort = this.state?.[study.id]?.find(c => c.cohort === cohort.id);
                            return html`

                                    <number-field-filter
                                        .value="${stateCohort?.value ?
                                            (stateCohort?.comparator ?? this.defaultComparator) + (stateCohort.value ?? "") :
                                            ""}"
                                        .config="${{comparator: true, layout: [3, 4, 5]}}"
                                        .label="${cohort.id}"
                                        type="text"
                                        data-study="${study.id}"
                                        data-cohort="${cohort.id}"
                                        data-action="comparator"
                                        @filterChange="${e => this.filterChange(e, study.id, cohort.id)}">
                                </number-field-filter>

`;
                        })}

            `)}`;
    }

}

customElements.define("cohort-stats-filter", CohortStatsFilter);
<|endoftext|>


<commit_before>/*global StyledElements, Wirecloud*/

(function () {

    "use strict";

    var clickCallback = function clickCallback(e) {
        e.preventDefault();
        e.stopPropagation();
        if (this.enabled) {
            this.events.click.dispatch(this);
        }
    };

    var keydownCallback = function keydownCallback(e) {
        if (this.enabled && e.keyCode === 13) {
            this.events.click.dispatch(this);
        }
    };

    var onmouseenter = function onmouseenter() {
        this.events.mouseenter.dispatch(this);
    };

    var onmouseleave = function onmouseleave() {
        this.events.mouseleave.dispatch(this);
    };

    var onfocus = function onfocus() {
        this.events.focus.dispatch(this);
    };

    var onblur = function onblur() {
        this.events.blur.dispatch(this);
    };

    /**
     *
     * Eventos que soporta este componente:
     *      - click: evento lanzado cuando se pulsa el botón.
     */
    var StyledButton = function StyledButton(options) {
        var defaultOptions = {
            'text': null,
            'title': '',
            'class': '',
            'plain': false,
            'iconHeight': 24,
            'iconWidth': 24,
            'icon': null,
            'iconClass': null,
            'usedInForm': false
        };
        options = Wirecloud.Utils.merge(defaultOptions, options);

        // Necesario para permitir herencia
        if (options.extending) {
            return;
        }

        StyledElements.StyledElement.call(this, ['click', 'focus', 'blur', 'mouseenter', 'mouseleave']);

        if (options.usedInForm) {
            this.wrapperElement = document.createElement("button");
            this.wrapperElement.setAttribute('type', 'button');
        } else {
            this.wrapperElement = document.createElement("div");
        }
        this.wrapperElement.setAttribute('tabindex', '0');
        this.wrapperElement.className = Wirecloud.Utils.appendWord(options['class'], "styled_button");

        if (options.plain) {
            this.wrapperElement.classList.add('plain');
        }

        if (options.icon != null) {
            this.icon = document.createElement("img");
            this.icon.className = "icon";
            this.icon.style.width = options.iconWidth + 'px';
            this.icon.style.height = options.iconHeight + 'px';
            this.icon.src = options.icon;
            this.wrapperElement.appendChild(this.icon);
        }

        if (options.text != null || options.iconClass != null) {
            this.label = document.createElement('span');
            if (options.text != null) {
                this.label.appendChild(document.createTextNode(options.text));
            }
            if (options.iconClass != null) {
                this.label.classList.add(options.iconClass);
            }
            this.wrapperElement.appendChild(this.label);
        }

        if (options.title) {
            this.setTitle(options.title);
        }

        /* Event handlers */
        this._clickCallback = clickCallback.bind(this);
        this._keydownCallback = keydownCallback.bind(this);

        this.wrapperElement.addEventListener('mousedown', Wirecloud.Utils.stopPropagationListener, true);
        this.wrapperElement.addEventListener('click', this._clickCallback, true);
        this.wrapperElement.addEventListener('keydown', this._keydownCallback, true);
        this.wrapperElement.addEventListener('focus', onfocus.bind(this), true);
        this.wrapperElement.addEventListener('blur', onblur.bind(this), true);
        this.wrapperElement.addEventListener('mouseenter', onmouseenter.bind(this), false);
        this.wrapperElement.addEventListener('mouseleave', onmouseleave.bind(this), false);
    };
    StyledButton.prototype = new StyledElements.StyledElement();

    StyledButton.prototype.focus = function focus() {
        this.wrapperElement.focus();
    };

    StyledButton.prototype.blur = function blur() {
        this.wrapperElement.blur();
    };

    StyledButton.prototype.setLabel = function setLabel(label) {
        this.label.textContent = label;
    };

    StyledButton.prototype.setTitle = function setTitle(title) {
        if (this.tooltip == null) {
            this.tooltip = new StyledElements.Tooltip({content: title, placement: ['bottom', 'top', 'right', 'left']});
            this.tooltip.bind(this);
        }
        this.tooltip.options.content = title;
    };

    StyledButton.prototype.click = function click() {
        if (this.enabled) {
            this.events.click.dispatch(this);
        }
    };

    StyledButton.prototype.destroy = function destroy() {

        this.wrapperElement.removeEventListener('mousedown', Wirecloud.Utils.stopPropagationListener, true);
        this.wrapperElement.removeEventListener('click', this._clickCallback, true);
        this.wrapperElement.removeEventListener('keydown', this._keydownCallback, true);

        delete this._clickCallback;
        delete this._keydownCallback;

        StyledElements.StyledElement.prototype.destroy.call(this);
    };

    StyledElements.StyledButton = StyledButton;
})();
<commit_msg>New button methods: addIconClassName and removeIconClassName<commit_after>/*global StyledElements, Wirecloud*/

(function () {

    "use strict";

    var clickCallback = function clickCallback(e) {
        e.preventDefault();
        e.stopPropagation();
        if (this.enabled) {
            this.events.click.dispatch(this);
        }
    };

    var keydownCallback = function keydownCallback(e) {
        if (this.enabled && e.keyCode === 13) {
            this.events.click.dispatch(this);
        }
    };

    var onmouseenter = function onmouseenter() {
        this.events.mouseenter.dispatch(this);
    };

    var onmouseleave = function onmouseleave() {
        this.events.mouseleave.dispatch(this);
    };

    var onfocus = function onfocus() {
        this.events.focus.dispatch(this);
    };

    var onblur = function onblur() {
        this.events.blur.dispatch(this);
    };

    /**
     *
     * Eventos que soporta este componente:
     *      - click: evento lanzado cuando se pulsa el botón.
     */
    var StyledButton = function StyledButton(options) {
        var defaultOptions = {
            'text': null,
            'title': '',
            'class': '',
            'plain': false,
            'iconHeight': 24,
            'iconWidth': 24,
            'icon': null,
            'iconClass': null,
            'usedInForm': false
        };
        options = Wirecloud.Utils.merge(defaultOptions, options);

        // Necesario para permitir herencia
        if (options.extending) {
            return;
        }

        StyledElements.StyledElement.call(this, ['click', 'focus', 'blur', 'mouseenter', 'mouseleave']);

        if (options.usedInForm) {
            this.wrapperElement = document.createElement("button");
            this.wrapperElement.setAttribute('type', 'button');
        } else {
            this.wrapperElement = document.createElement("div");
        }
        this.wrapperElement.setAttribute('tabindex', '0');
        this.wrapperElement.className = Wirecloud.Utils.appendWord(options['class'], "styled_button");

        if (options.plain) {
            this.wrapperElement.classList.add('plain');
        }

        if (options.icon != null) {
            this.icon = document.createElement("img");
            this.icon.className = "icon";
            this.icon.style.width = options.iconWidth + 'px';
            this.icon.style.height = options.iconHeight + 'px';
            this.icon.src = options.icon;
            this.wrapperElement.appendChild(this.icon);
        }

        if (options.text != null || options.iconClass != null) {
            this.label = document.createElement('span');
            if (options.text != null) {
                this.label.appendChild(document.createTextNode(options.text));
            }
            if (options.iconClass != null) {
                this.label.classList.add(options.iconClass);
            }
            this.wrapperElement.appendChild(this.label);
        }

        if (options.title) {
            this.setTitle(options.title);
        }

        /* Event handlers */
        this._clickCallback = clickCallback.bind(this);
        this._keydownCallback = keydownCallback.bind(this);

        this.wrapperElement.addEventListener('mousedown', Wirecloud.Utils.stopPropagationListener, true);
        this.wrapperElement.addEventListener('click', this._clickCallback, true);
        this.wrapperElement.addEventListener('keydown', this._keydownCallback, true);
        this.wrapperElement.addEventListener('focus', onfocus.bind(this), true);
        this.wrapperElement.addEventListener('blur', onblur.bind(this), true);
        this.wrapperElement.addEventListener('mouseenter', onmouseenter.bind(this), false);
        this.wrapperElement.addEventListener('mouseleave', onmouseleave.bind(this), false);
    };
    StyledButton.prototype = new StyledElements.StyledElement();

    StyledButton.prototype.focus = function focus() {
        this.wrapperElement.focus();
    };

    StyledButton.prototype.blur = function blur() {
        this.wrapperElement.blur();
    };

    StyledButton.prototype.setLabel = function setLabel(label) {
        this.label.textContent = label;
    };

    StyledButton.prototype.addIconClassName = function addIconClassName(classname) {
        this.label.classList.add(classname);
    };

    StyledButton.prototype.removeIconClassName = function removeIconClassName(classname) {
        this.label.classList.remove(classname);
    };

    StyledButton.prototype.setTitle = function setTitle(title) {
        if (this.tooltip == null) {
            this.tooltip = new StyledElements.Tooltip({content: title, placement: ['bottom', 'top', 'right', 'left']});
            this.tooltip.bind(this);
        }
        this.tooltip.options.content = title;
    };

    StyledButton.prototype.click = function click() {
        if (this.enabled) {
            this.events.click.dispatch(this);
        }
    };

    StyledButton.prototype.destroy = function destroy() {

        this.wrapperElement.removeEventListener('mousedown', Wirecloud.Utils.stopPropagationListener, true);
        this.wrapperElement.removeEventListener('click', this._clickCallback, true);
        this.wrapperElement.removeEventListener('keydown', this._keydownCallback, true);

        delete this._clickCallback;
        delete this._keydownCallback;

        StyledElements.StyledElement.prototype.destroy.call(this);
    };

    StyledElements.StyledButton = StyledButton;
})();
<|endoftext|>


<commit_before>import React, { useState } from "react";
import { sameDate } from "../../scripts/HelperFunctions";
import InsertObjectPopover from "./InsertObjectPopover";
import DraggableTravelObject from "../TravelObjects/DraggableTravelObject";
import { ItemTypes, moveTravelObject } from "../../scripts/DragTravelObject";
import { useDrop } from "react-dnd";

export default function OneHourInterval(props) {
  const [slots, setSlots] = useState(null);
  const displayHeightOfADiv = 45.47;
  const padding = 22.0;
  const minPerDiv = 30.0;
  const [anchorEl, setAnchorEl] = React.useState(null);

  const [{ isOver, canDrop }, drop] = useDrop({
    accept: ItemTypes.TRAVELOBJECT,
    drop: (item, monitor) => moveTravelObject(item, monitor),
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
      canDrop: !!monitor.canDrop(),
    }),
  });

  const handleOnClickInterval = (idV, event) => {
    if (event.target.className === "Interval") {
      let data = props.onClickInterval(idV);
      if (data.freeTimeSlot !== undefined) {
        setSlots(data);
        setAnchorEl(event.currentTarget);
      }
    }
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  /*Given startDate and endDate of a TravelObject, return the height of display (unit: pixel) */
  const getHeightPercentage = (startDate, endDate) => {
    let dif = 0;
    if (sameDate(startDate, endDate)) {
      dif =
        endDate.getHours() * 60 +
        endDate.getMinutes() -
        startDate.getHours() * 60 -
        startDate.getMinutes();
    } else if (!sameDate(props.displayDate, endDate)) {
      dif = 24 * 60 - startDate.getHours() * 60 - startDate.getMinutes();
    } else {
      dif = endDate.getHours() * 60 + endDate.getMinutes();
    }

    let height = (dif * displayHeightOfADiv) / minPerDiv;
    return height < padding ? 0 : height - padding;
  };

  const getHeightFromMin = (min) => {
    return (min * displayHeightOfADiv) / minPerDiv - padding;
  };

  /*Given a startDate of a TravelObject, return the top pixel*/
  const getTopPixel = (startDate) => {
    if (!sameDate(props.displayDate, startDate)) {
      return 0;
    }
    let dif =
      startDate.getMinutes() < 30
        ? startDate.getMinutes()
        : startDate.getMinutes() - 30;
    return (dif / minPerDiv) * displayHeightOfADiv;
  };

  var item00 = [];
  var item30 = [];

  if (props.items !== null) {
    props.items.forEach((item) => {
      let height =
        item.data.type === "hotel"
          ? getHeightFromMin(30)
          : getHeightPercentage(item.data.startDate, item.data.endDate);
      let top =
        item.data.type === "hotel"
          ? getTopPixel(item.data.endDate)
          : getTopPixel(item.data.startDate);
      let travelObject = (
        <DraggableTravelObject
          key={item.data.id}
          displayDate={props.displayDate}
          data={item.data}
          onRemoveItem={props.onRemoveItem}
          onEditItem={props.onEditItem}
          onAddItem={props.onAddItem}
          onClickObject={props.onClickObject}
          styleConfig={{
            top: top.toString() + "px",
            height: height.toString() + "px",
            width: "216px",
            overflowY: "scroll",
            position: "absolute",
            zIndex: props.zIndex.toString(),
          }}
        />
      );

      if (item.div === ":00") {
        item00.push(travelObject);
      } else if (item.div === ":30") {
        item30.push(travelObject);
      }
    });
  }
  return (

        {props.idV + ":00"}
         handleOnClickInterval(props.idV + ":00", event)}
        >
          {item00.length === 0 ? null : item00}

         handleOnClickInterval(props.idV + ":30", event)}
        >
          {item30.length === 0 ? null : item30}

      <InsertObjectPopover
        anchorEl={anchorEl}
        slots={slots}
        onClickTimeslot={props.onClickTimeslot}
        onAddItem={props.onAddItem}
        onOpenSuggestions={props.onOpenSuggestions}
        onClose={handleClose}
        startDate={props.startDate}
      />

  );
}
<commit_msg>Refactor ItemTypes<commit_after>import React, { useState } from "react";
import { sameDate } from "../../scripts/HelperFunctions";
import InsertObjectPopover from "./InsertObjectPopover";
import DraggableFinalized from "../TravelObjects/DraggableFinalized";
import { ItemTypes, moveTravelObject } from "../../scripts/DragTravelObject";
import { useDrop } from "react-dnd";

export default function OneHourInterval(props) {
  const [slots, setSlots] = useState(null);
  const displayHeightOfADiv = 45.47;
  const padding = 22.0;
  const minPerDiv = 30.0;
  const [anchorEl, setAnchorEl] = React.useState(null);

  const [{ isOver, canDrop }, drop] = useDrop({
    accept: ItemTypes.FINALIZEDTRAVELOBJECT,
    drop: (item, monitor) => moveTravelObject(item, monitor),
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
      canDrop: !!monitor.canDrop(),
    }),
  });

  const handleOnClickInterval = (idV, event) => {
    if (event.target.className === "Interval") {
      let data = props.onClickInterval(idV);
      if (data.freeTimeSlot !== undefined) {
        setSlots(data);
        setAnchorEl(event.currentTarget);
      }
    }
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  /*Given startDate and endDate of a TravelObject, return the height of display (unit: pixel) */
  const getHeightPercentage = (startDate, endDate) => {
    let dif = 0;
    if (sameDate(startDate, endDate)) {
      dif =
        endDate.getHours() * 60 +
        endDate.getMinutes() -
        startDate.getHours() * 60 -
        startDate.getMinutes();
    } else if (!sameDate(props.displayDate, endDate)) {
      dif = 24 * 60 - startDate.getHours() * 60 - startDate.getMinutes();
    } else {
      dif = endDate.getHours() * 60 + endDate.getMinutes();
    }

    let height = (dif * displayHeightOfADiv) / minPerDiv;
    return height < padding ? 0 : height - padding;
  };

  const getHeightFromMin = (min) => {
    return (min * displayHeightOfADiv) / minPerDiv - padding;
  };

  /*Given a startDate of a TravelObject, return the top pixel*/
  const getTopPixel = (startDate) => {
    if (!sameDate(props.displayDate, startDate)) {
      return 0;
    }
    let dif =
      startDate.getMinutes() < 30
        ? startDate.getMinutes()
        : startDate.getMinutes() - 30;
    return (dif / minPerDiv) * displayHeightOfADiv;
  };

  var item00 = [];
  var item30 = [];

  if (props.items !== null) {
    props.items.forEach((item) => {
      let height =
        item.data.type === "hotel"
          ? getHeightFromMin(30)
          : getHeightPercentage(item.data.startDate, item.data.endDate);
      let top =
        item.data.type === "hotel"
          ? getTopPixel(item.data.endDate)
          : getTopPixel(item.data.startDate);
      let travelObject = (
        <DraggableFinalized
          key={item.data.id}
          displayDate={props.displayDate}
          data={item.data}
          onRemoveItem={props.onRemoveItem}
          onEditItem={props.onEditItem}
          onAddItem={props.onAddItem}
          onClickObject={props.onClickObject}
          styleConfig={{
            top: top.toString() + "px",
            height: height.toString() + "px",
            width: "216px",
            overflowY: "scroll",
            position: "absolute",
            zIndex: props.zIndex.toString(),
          }}
        />
      );

      if (item.div === ":00") {
        item00.push(travelObject);
      } else if (item.div === ":30") {
        item30.push(travelObject);
      }
    });
  }
  return (

        {props.idV + ":00"}
         handleOnClickInterval(props.idV + ":00", event)}
        >
          {item00.length === 0 ? null : item00}

         handleOnClickInterval(props.idV + ":30", event)}
        >
          {item30.length === 0 ? null : item30}

      <InsertObjectPopover
        anchorEl={anchorEl}
        slots={slots}
        onClickTimeslot={props.onClickTimeslot}
        onAddItem={props.onAddItem}
        onOpenSuggestions={props.onOpenSuggestions}
        onClose={handleClose}
        startDate={props.startDate}
      />

  );
}
<|endoftext|>


<commit_before>dbs_chartValue = function(pId) {
	var xChart = $(pId).closest(".dbs_chart");
	if (xChart.attr("type") == "line"){
		dbsfaces.chartValue.drawLines(pId);
	}

	setTimeout(function(){
		dbsfaces.chartValue.showLabel(pId);
	},0);

	$(pId).mouseenter(function (e){
		//Coloca item como primeiro elemento para aparecer acima dos demais
//		this.parentElement.appendChild(this);
		dbsfaces.tooltip.showTooltip(pId + '_tooltip');
		$(pId + '_tooltip').addClass("-selected");
		if ($(pId + " > .-info > .-label").length > 0){
			$(pId + " > .-info > .-label").get(0).classList.add("-selected");
		}
		if ($(pId + " > .-info > .-value").length > 0){
			$(pId + " > .-info > .-value").get(0).classList.add("-selected");
		}
		dbsfaces.chartValue.selectValue(pId, true);
	});
	$(pId).mouseleave(function (e){
		dbsfaces.tooltip.hideTooltip(pId + '_tooltip');
		$(pId + '_tooltip').removeClass("-selected");
		if ($(pId + " > .-info > .-label").length > 0){
			$(pId + " > .-info > .-label").get(0).classList.remove("-selected");
		}
		if ($(pId + " > .-info > .-value").length > 0){
			$(pId + " > .-info > .-value").get(0).classList.remove("-selected");
		}
		dbsfaces.chartValue.selectValue(pId, false);
	});
};

dbsfaces.chartValue = {
	drawLines: function(pId){
		var xValue = $(pId);
		if (xValue.length == 0){
			return;
		}
		var xLineGroup = $(pId).siblings(".-line");
		var xValueAnterior = xValue.prevAll(".dbs_chartValue").first();

		dbsfaces.chartValue.drawLine(xLineGroup, xValueAnterior);
		dbsfaces.chartValue.drawLine(xLineGroup, xValue);

		return;
	},

	drawLine: function(pLineGroup, pValue){
		if (pValue.length == 0){return;}
		var xValuePosterior = pValue.nextAll(".dbs_chartValue").first().children(".-point");
		if (xValuePosterior.length == 0){return;}
		var xValue = pValue.children(".-point");
		var xId = pValue.attr("id");
		var xX1 = xValue.attr("cx");
		var xY1 = xValue.attr("cy");
		var xX2 = xValuePosterior.attr("cx");
		var xY2 = xValuePosterior.attr("cy");
		var xLine = pLineGroup.children("line[index='" + xId + "']");
		if (xLine.length == 0){
			xLine = $(document.createElementNS('http://www.w3.org/2000/svg','line'));
		}
		xLine.attr("index", xId)
			 .attr("x1", xX1)
			 .attr("y1", xY1)
			 .attr("x2", xX2)
			 .attr("y2", xY2);
		pLineGroup.append(xLine);
	},

	showLabel: function(pId){
		var xChart = $(pId).closest(".dbs_chart");
		if (xChart.attr("type") == "bar"
		 || xChart.attr("type") == "line"){
			dbsfaces.chartValue.showLabelBarAndLine(pId);
		}
	},

	//Verifica sopreposição dos labels
	showLabelBarAndLine: function(pId){
		var xValue = $(pId);
		if (xValue.length == 0){return;}

		var xLabelAtual = xValue.children(".-info").children(".-label");
		if (xLabelAtual.length == 0){return;}

		//Procura valor anterior que contenha label sendo exibido
		var xLabelAnterior = xValue.prevAll(".dbs_chartValue").children(".-info").children(".-label").not("[class ~= '-hide']").first();
		var xXAtual = 0;
		var xXAnterior = 0;
		//Calcula posição final da label anterior
		if (xLabelAnterior.length != 0){
			xXAnterior = Number(xLabelAnterior.attr("x")) + (xLabelAnterior.get(0).getComputedTextLength() / 2) + 4;
		}
		//Calcula posição inicial da label atual
		xXAtual = Number(xLabelAtual.attr("x")) - (xLabelAtual.get(0).getComputedTextLength() / 2);
		//Exclui sobreposição de texto
		if (xXAnterior > xXAtual){
			xLabelAtual.get(0).classList.add("-hide");
		}else{
			xLabelAtual.get(0).classList.remove("-hide");
		}
	},

	selectValue: function(pId, pSelect){
		var xValue = $(pId);
		if (xValue.length == 0){return;}

		var xCharts = xValue.closest(".dbs_charts");
		var xLabelAtual = xValue.children(".-info");

		var xGridLabels = xCharts.find(".-container > .-data > .-container > .-content > .-value > .-grid > .-label");
//		var xDataLabels = xValue.siblings(".dbs_chartValue").children(".-info").children(".-label").not("[class ~= '-hide']").not(xLabelAtual);
		var xChartValues = xCharts.find(".dbs_chartValue").not(xValue);
		var xDataLabels = xChartValues.children(".-info");
		if (pSelect){
			xDataLabels.hide();
			xGridLabels.hide();
			xChartValues.each(function(){
				  this.classList.add("-dim");
			});
			xValue.get(0).classList.add("-selected");

		}else{
			xDataLabels.show();
			xGridLabels.show();
			xChartValues.each(function(){
				  this.classList.remove("-dim");
			});
			xValue.get(0).classList.remove("-selected");
		}
	}

};

<commit_msg>Força exibição em primeiro plano de item selecionado<commit_after>dbs_chartValue = function(pId) {
	var xChart = $(pId).closest(".dbs_chart");
	if (xChart.attr("type") == "line"){
		dbsfaces.chartValue.drawLines(pId);
	}

	setTimeout(function(){
		dbsfaces.chartValue.showLabel(pId);
	},0);

	$(pId).mouseenter(function (e){
		//Coloca item como primeiro elemento para aparecer acima dos demais
		dbsfaces.chartValue.moveToFront(this);

		dbsfaces.tooltip.showTooltip(pId + '_tooltip');
		$(pId + '_tooltip').addClass("-selected");
		if ($(pId + " > .-info > .-label").length > 0){
			$(pId + " > .-info > .-label").get(0).classList.add("-selected");
		}
		if ($(pId + " > .-info > .-value").length > 0){
			$(pId + " > .-info > .-value").get(0).classList.add("-selected");
		}
		dbsfaces.chartValue.selectValue(pId, true);
	});
	$(pId).mouseleave(function (e){
		dbsfaces.tooltip.hideTooltip(pId + '_tooltip');
		$(pId + '_tooltip').removeClass("-selected");
		if ($(pId + " > .-info > .-label").length > 0){
			$(pId + " > .-info > .-label").get(0).classList.remove("-selected");
		}
		if ($(pId + " > .-info > .-value").length > 0){
			$(pId + " > .-info > .-value").get(0).classList.remove("-selected");
		}
		dbsfaces.chartValue.selectValue(pId, false);
	});
};

dbsfaces.chartValue = {
	drawLines: function(pId){
		var xValue = $(pId);
		if (xValue.length == 0){
			return;
		}
		var xLineGroup = $(pId).siblings(".-line");
		var xValueAnterior = xValue.prevAll(".dbs_chartValue").first();

		dbsfaces.chartValue.drawLine(xLineGroup, xValueAnterior);
		dbsfaces.chartValue.drawLine(xLineGroup, xValue);

		return;
	},

	drawLine: function(pLineGroup, pValue){
		if (pValue.length == 0){return;}
		var xValuePosterior = pValue.nextAll(".dbs_chartValue").first().children(".-point");
		if (xValuePosterior.length == 0){return;}
		var xValue = pValue.children(".-point");
		var xId = pValue.attr("id");
		var xX1 = xValue.attr("cx");
		var xY1 = xValue.attr("cy");
		var xX2 = xValuePosterior.attr("cx");
		var xY2 = xValuePosterior.attr("cy");
		var xLine = pLineGroup.children("line[index='" + xId + "']");
		if (xLine.length == 0){
			xLine = $(document.createElementNS('http://www.w3.org/2000/svg','line'));
		}
		xLine.attr("index", xId)
			 .attr("x1", xX1)
			 .attr("y1", xY1)
			 .attr("x2", xX2)
			 .attr("y2", xY2);
		pLineGroup.append(xLine);
	},
	showLabel: function(pId){
		var xChart = $(pId).closest(".dbs_chart");
		if (xChart.attr("type") == "bar"
		 || xChart.attr("type") == "line"){
			dbsfaces.chartValue.showLabelBarAndLine(pId);
		}
	},

	//Verifica sopreposição dos labels
	showLabelBarAndLine: function(pId){
		var xValue = $(pId);
		if (xValue.length == 0){return;}

		var xLabelAtual = xValue.children(".-info").children(".-label");
		if (xLabelAtual.length == 0){return;}

		//Procura valor anterior que contenha label sendo exibido
		var xLabelAnterior = xValue.prevAll(".dbs_chartValue").children(".-info").children(".-label").not("[class ~= '-hide']").first();
		var xXAtual = 0;
		var xXAnterior = 0;
		//Calcula posição final da label anterior
		if (xLabelAnterior.length != 0){
			xXAnterior = Number(xLabelAnterior.attr("x")) + (xLabelAnterior.get(0).getComputedTextLength() / 2) + 4;
		}
		//Calcula posição inicial da label atual
		xXAtual = Number(xLabelAtual.attr("x")) - (xLabelAtual.get(0).getComputedTextLength() / 2);
		//Exclui sobreposição de texto
		if (xXAnterior > xXAtual){
			xLabelAtual.get(0).classList.add("-hide");
		}else{
			xLabelAtual.get(0).classList.remove("-hide");
		}
	},

	//Coloca item como primeiro elemento para aparecer acima dos demais
	moveToFront: function(pItem){
		var xChart = $(pItem).closest(".dbs_chart");
		if (xChart.attr("type") == "bar"
		 || xChart.attr("type") == "line"){
			pItem.parentElement.appendChild(pItem);
		}
	},

	selectValue: function(pId, pSelect){
		var xValue = $(pId);
		if (xValue.length == 0){return;}

		var xCharts = xValue.closest(".dbs_charts");
		var xLabelAtual = xValue.children(".-info");

		var xGridLabels = xCharts.find(".-container > .-data > .-container > .-content > .-value > .-grid > .-label");
//		var xDataLabels = xValue.siblings(".dbs_chartValue").children(".-info").children(".-label").not("[class ~= '-hide']").not(xLabelAtual);
		var xChartValues = xCharts.find(".dbs_chartValue").not(xValue);
		var xDataLabels = xChartValues.children(".-info");
		if (pSelect){
			xDataLabels.hide();
			xGridLabels.hide();
			xChartValues.each(function(){
				  this.classList.add("-dim");
			});
			xValue.get(0).classList.add("-selected");

		}else{
			xDataLabels.show();
			xGridLabels.show();
			xChartValues.each(function(){
				  this.classList.remove("-dim");
			});
			xValue.get(0).classList.remove("-selected");
		}
	}

};

<|endoftext|>


<commit_before>/**
 * Application View
 *
 */
define([
  'jquery',
  'backbone',
  'models/job'
],
function($,
         Backbone,
         JobModel) {

  var ApplicationView;

  ApplicationView = Backbone.View.extend({

    el: '.app',

    events: {
      'click .new-job': 'newJob',
      'click .view-graph': 'showGraph',
      'click .view-alt-graph': 'showGraph',
      'click .total-jobs': 'showAll'
    },

    initialize: function() {
      this.listenTo(app.jobsCollection, {
        add: this.updateJobsCount,
        remove: this.updateJobsCount,
        reset: this.updateJobsCount,
        sync: this.setPersisted
      });
    },

    setPersisted: function(collection, resp, options) {
      collection.each && collection.each(function(job) {
        job.set({persisted: true}, {silent: true});
      });
    },

    newJob: function(event) {
      var model = new JobModel({persisted: false});

      app.detailsCollection.unshift(model, {
        validate: false,
        create: true
      });

      $('.right-pane').scrollTop(0);
    },

    showGraph: function(e) {
      var graphView, targetName, $target, related, graphType;
      e && e.preventDefault() && e.stopPropagation() && e.stopImmediatePropagation();

      $target    = $(e.currentTarget);
      targetName = $target.data('job-id');
      graphType = 'static';
      app.lightbox.showGraphView(graphType, targetName);
    },

    showAll: function() {
      app.resultsCollection.reset(app.jobsCollection.models);
      $('#search-filter').val('')
    },

    updateJobsCount: function() {
      this.$('.all-jobs-count').text(app.jobsCollection.length);
    }

  });

  return ApplicationView;
});
<commit_msg>[application_view] update jobs count on init<commit_after>/**
 * Application View
 *
 */
define([
  'jquery',
  'backbone',
  'models/job'
],
function($,
         Backbone,
         JobModel) {

  var ApplicationView;

  ApplicationView = Backbone.View.extend({

    el: '.app',

    events: {
      'click .new-job': 'newJob',
      'click .view-graph': 'showGraph',
      'click .view-alt-graph': 'showGraph',
      'click .total-jobs': 'showAll'
    },

    initialize: function() {
      this.listenTo(app.jobsCollection, {
        add: this.updateJobsCount,
        remove: this.updateJobsCount,
        reset: this.updateJobsCount,
        sync: this.setPersisted
      });
      this.updateJobsCount();
    },

    setPersisted: function(collection, resp, options) {
      collection.each && collection.each(function(job) {
        job.set({persisted: true}, {silent: true});
      });
    },

    newJob: function(event) {
      var model = new JobModel({persisted: false});

      app.detailsCollection.unshift(model, {
        validate: false,
        create: true
      });

      $('.right-pane').scrollTop(0);
    },

    showGraph: function(e) {
      var graphView, targetName, $target, related, graphType;
      e && e.preventDefault() && e.stopPropagation() && e.stopImmediatePropagation();

      $target    = $(e.currentTarget);
      targetName = $target.data('job-id');
      graphType = 'static';
      app.lightbox.showGraphView(graphType, targetName);
    },

    showAll: function() {
      app.resultsCollection.reset(app.jobsCollection.models);
      $('#search-filter').val('')
    },

    updateJobsCount: function() {
      this.$('.all-jobs-count').text(app.jobsCollection.length);
    }

  });

  return ApplicationView;
});
<|endoftext|>


<commit_before>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require, exports, module) {
    'use strict';

    var Util = require('util');
    var $ = require('jquery');
    var Backbone = require('backbone');
    var Epoxy = require('backbone-epoxy');
    var App = require('app');
    var ModalEditDashboard = require('modals/modalEditDashboard');
    var ModalConfirm = require('modals/modalConfirm');
    var ModalAddWidget = require('modals/addWidget/modalAddWidget');
    var modalAddSharedWidget = require('modals/addSharedWidget/modalAddSharedWidget');
    var Localization = require('localization');
    var GadgetCollection = require('dashboard/GadgetCollection');
    var GadgetView = require('dashboard/GadgetView');
    var GadgetModel = require('dashboard/GadgetModel');
    var WidgetModel = require('newWidgets/WidgetModel');
    var WidgetConfig = require('widget/widgetsConfig');

    require('gridstackUi');
    require('fullscreen');
    var config = App.getInstance();

    var DashboardItemView = Epoxy.View.extend({
        className: 'dashboard-item-view',
        template: 'tpl-dashboard-item',

        events: {
            'click [data-js-edit]': 'onClickEdit',
            'click [data-js-remove]': 'onClickRemove',
            'click [data-js-full-screen]': 'onClickFullScreen',
            'click [data-js-close-fullscreen]': 'onClickExitFullScreen',
            'click [data-js-add-widget]': 'onClickAddWidget',
            'click [data-js-add-shared-widget]': 'onClickAddSharedWidget',
        },

        bindings: {
            ':el': 'classes: {"not-my": not(isMy)}',
            '[data-js-owner-name]': 'text: owner',
            '[data-js-add-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}',
            '[data-js-add-shared-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}'
        },

        computeds: {
            validateForAddWidget: {
                deps: ['widgets'],
                get: function(widgets) {
                    widgets = this.model.getWidgets();
                    return widgets.length < config.maxWidgetsOnDashboard;
                }
            },
            getAddBtnTitle: {
                deps: ['widgets'],
                get: function(widgets){
                    widgets = this.model.getWidgets();
                    return widgets.length >= config.maxWidgetsOnDashboard ? Localization.dashboard.maxWidgetsAdded : '';
                }
            }
        },

        initialize: function(options) {
            this.gadgetViews = [];
            this.scrollElement = config.mainScrollElement;
            this.onShowAsync = $.Deferred();
            this.render();
            var self = this;
            if(this.model.get('notLoad')) {
                this.$el.addClass('load');
                this.model.update().done(function() {
                    self.$el.removeClass('load');
                    self.postInit();
                    self.applyBindings();
                })
            } else {
                this.postInit();
            }
        },
        postInit: function() {
            var self = this;
            WidgetConfig.updateInstance().done(function() {
                self.gadgetCollection = new GadgetCollection([], {dashboardModel: self.model});
                self.listenTo(self.gadgetCollection, 'add', self.onAddGadget);
                self.listenTo(self.gadgetCollection, 'remove:view', self.onRemoveGadget);
                self.listenTo(self.gadgetCollection, 'remove', self.checkEmptyDashboard);
                self.activateGridStack();
                self.listenTo(self.model, 'add:widget', self.onAddNewGadget);
                self.listenTo(self.model, 'change:isShared', self.onShareDashboard);
            });

        },
        render: function() {
            this.$el.html(Util.templates(this.template, {}));
        },
        onAddNewGadget: function(model) {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(model);
            this.updateScroll();
        },
        onShareDashboard: function(){
            if(this.model.get('isShared')){
                _.each(this.gadgetViews, function(view){
                    view.model.set('isShared', true);
                }, this);
            }
        },
        activateGridStack: function() {
            var $gridStack = $('[data-js-grid-stack]', this.$el);
            $gridStack.gridstack({
                cellHeight: config.widgetGridCellHeight,
                verticalMargin: config.widgetGridVerticalMargin,
                draggable: {
                    handle: '[data-js-drag-handle]'
                },
                resizable: {
                    handles: 'se, sw'
                },
                disableDrag: !this.model.get('isMy'),
                disableResize: !this.model.get('isMy'),
            });
            this.gridStack = $gridStack.data('gridstack');
            this.createGadgets();
            var self = this;
            $gridStack.on('change', function (e, items) {
                _.each(items, function(item) {
                    var id = item.el.data('id');
                    if(!id) return;
                    var gadgetModel = self.gadgetCollection.get(id);
                    if(!gadgetModel) return;
                    gadgetModel.set({
                        x: item.x,
                        y: item.y,
                        width: item.width,
                        height: item.height,
                    });
                });
                self.gadgetCollection.sort();
                self.updateScroll();
            });
            $gridStack.on('resizestart', function (event, ui) {
                var view = event.target.backboneView;
                view && view.startResize();
            });
            $gridStack.on('resizestop', function (event, ui) {
                var view = event.target.backboneView;
                setTimeout(function(){
                    view && view.stopResize();
                }, 300);
            });

        },
        onClickFullScreen: function(e) {
            e.preventDefault();
            $('body').fullscreen({toggleClass: 'fullscreen'});
            this.updateGadgetsTimer();
        },
        onAddGadget: function(gadgetModel) {
            var view = new GadgetView({model: gadgetModel, dashboardModel: this.model});
            this.gridStack.addWidget.apply(this.gridStack, view.getDataForGridStack());
            this.gadgetViews.push(view);
        },
        onRemoveGadget: function(view) {
            this.gridStack.removeWidget(view.el);
        },
        checkEmptyDashboard: function() {
            if(!this.model.getWidgets().length) {
                this.$el.addClass('not-found');
            } else {
                this.$el.removeClass('not-found');
            }
        },
        createGadgets: function() {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(this.model.getWidgets(), {silent: true, parse: true});
            this.gadgetCollection.forEach(function(model){
                this.onAddGadget(model);
            }, this);
            this.updateScroll();
        },
        updateScroll: function() {
            var self = this;
            this.onShowAsync.done(function() {
                self.scrollerAnimate = new ScrollerAnimate(self.gadgetViews);
                self.scrollElement
                    .off('scroll.dashboardPage')
                    .on("scroll.dashboardPage", function (e) {
                        self.onScroll();
                    });
                self.onScroll();
            })
        },
        onShow: function() {
            this.onShowAsync.resolve();
        },
        onScroll: function() {
            var scrollTop = this.scrollElement.scrollTop();
            this.scrollerAnimate.activateScroll(scrollTop);
        },
        onClickEdit: function(e) {
            e.preventDefault();
            e.stopPropagation();
            var self = this;
            (new ModalEditDashboard({
                dashboardCollection: this.model.collection,
                dashboardModel: this.model,
                mode: 'edit',
            })).show().done(function(newModel) {
                self.model.set(newModel.toJSON());
            })
        },
        onClickRemove: function(e) {
            e.preventDefault();
            e.stopPropagation();
            var self = this;
            (new ModalConfirm({
                headerText: Localization.dialogHeader.dashboardDelete,
                bodyText: Util.replaceTemplate(Localization.dialog.dashboardDelete, this.model.get('name')),
                okButtonDanger: true,
                cancelButtonText: Localization.ui.cancel,
                okButtonText: Localization.ui.delete,
            })).show().done(function() {
                var collection = self.model.collection;
                self.model.collection.remove(self.model);
                self.destroy();
                collection.resetActive();
            })
        },
        onClickExitFullScreen: function(e) {
            clearTimeout(this.updateTimer);
            e.preventDefault();
            e.stopPropagation();
            $.fullscreen.exit();
        },
        updateGadgetsTimer: function() {
            clearTimeout(this.updateTimer);
            var self = this;
            this.updateTimer = setTimeout(function() {
                _.each(self.gadgetCollection.models, function(gadgetModel) {
                    gadgetModel.trigger('update:timer');
                });
                self.updateGadgetsTimer();
            }, 60000);
        },
        onClickAddWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickAddSharedWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            (new modalAddSharedWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        destroy: function () {
            clearTimeout(this.updateTimer);
            $.fullscreen.exit();
            this.undelegateEvents();
            this.gridStack && this.gridStack.destroy();
            this.scrollElement.off('scroll.dashboardPage');
            this.stopListening();
            this.unbind();
            this.$el.remove();
        },
    });

    function ScrollerAnimate(blocks){
        this.blocks = blocks;
        this.scrollMap = [];
        this.documentHeight = 0;

        this._createScrollMap = function(){
            this.scrollMap = [];
            this.documentHeight = document.documentElement.clientHeight;
            for(var i = 0; i < this.blocks.length; i++){
                this.scrollMap.push({
                    scrollStart: this.blocks[i].el.offsetTop,
                    scrollEnd: this.blocks[i].el.offsetTop + this.blocks[i].el.offsetHeight
                });
            }
        };

        this.activateScroll = function(scrollTop){
            var scrollBottom = scrollTop + this.documentHeight;
            var showBlockIndexs = [];
            for(var i = 0; i < this.scrollMap.length; i++){
                if((this.scrollMap[i].scrollStart <= scrollBottom && scrollTop < this.scrollMap[i].scrollStart)
                    || (this.scrollMap[i].scrollEnd <= scrollBottom && scrollTop < this.scrollMap[i].scrollEnd)
                    || (this.scrollMap[i].scrollEnd > scrollBottom && scrollTop >= this.scrollMap[i].scrollStart)){
                    showBlockIndexs.push(i);
                    if(!this.blocks[i].activate){
                        this.blocks[i].activate = true;
                        this.blocks[i].activateGadget();
                    }
                }
            }
            // return middle block index
            if(showBlockIndexs.length != 2) return showBlockIndexs[parseInt(showBlockIndexs.length/2)];
            var middleScreen = scrollBottom - this.documentHeight/2,
                blockSeparate = this.scrollMap[showBlockIndexs[0]].scrollEnd;
            if(blockSeparate > middleScreen) return showBlockIndexs[0];
            return showBlockIndexs[1];
        };

        this.resize = function(){
            this._createScrollMap();
            this.activateScroll(config.mainScrollElement.scrollTop());
        }

        this._createScrollMap();
    }

    return DashboardItemView;
});
<commit_msg>fixed update gadgets on resize window<commit_after>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require, exports, module) {
    'use strict';

    var Util = require('util');
    var $ = require('jquery');
    var Backbone = require('backbone');
    var Epoxy = require('backbone-epoxy');
    var App = require('app');
    var ModalEditDashboard = require('modals/modalEditDashboard');
    var ModalConfirm = require('modals/modalConfirm');
    var ModalAddWidget = require('modals/addWidget/modalAddWidget');
    var modalAddSharedWidget = require('modals/addSharedWidget/modalAddSharedWidget');
    var Localization = require('localization');
    var GadgetCollection = require('dashboard/GadgetCollection');
    var GadgetView = require('dashboard/GadgetView');
    var GadgetModel = require('dashboard/GadgetModel');
    var WidgetModel = require('newWidgets/WidgetModel');
    var WidgetConfig = require('widget/widgetsConfig');

    require('gridstackUi');
    require('fullscreen');
    var config = App.getInstance();

    var DashboardItemView = Epoxy.View.extend({
        className: 'dashboard-item-view',
        template: 'tpl-dashboard-item',

        events: {
            'click [data-js-edit]': 'onClickEdit',
            'click [data-js-remove]': 'onClickRemove',
            'click [data-js-full-screen]': 'onClickFullScreen',
            'click [data-js-close-fullscreen]': 'onClickExitFullScreen',
            'click [data-js-add-widget]': 'onClickAddWidget',
            'click [data-js-add-shared-widget]': 'onClickAddSharedWidget',
        },

        bindings: {
            ':el': 'classes: {"not-my": not(isMy)}',
            '[data-js-owner-name]': 'text: owner',
            '[data-js-add-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}',
            '[data-js-add-shared-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}'
        },

        computeds: {
            validateForAddWidget: {
                deps: ['widgets'],
                get: function(widgets) {
                    widgets = this.model.getWidgets();
                    return widgets.length < config.maxWidgetsOnDashboard;
                }
            },
            getAddBtnTitle: {
                deps: ['widgets'],
                get: function(widgets){
                    widgets = this.model.getWidgets();
                    return widgets.length >= config.maxWidgetsOnDashboard ? Localization.dashboard.maxWidgetsAdded : '';
                }
            }
        },

        initialize: function(options) {
            this.gadgetViews = [];
            this.scrollElement = config.mainScrollElement;
            this.onShowAsync = $.Deferred();
            this.render();
            var self = this;
            if(this.model.get('notLoad')) {
                this.$el.addClass('load');
                this.model.update().done(function() {
                    self.$el.removeClass('load');
                    self.postInit();
                    self.applyBindings();
                })
            } else {
                this.postInit();
            }
        },
        postInit: function() {
            var self = this;
            WidgetConfig.updateInstance().done(function() {
                self.gadgetCollection = new GadgetCollection([], {dashboardModel: self.model});
                self.listenTo(self.gadgetCollection, 'add', self.onAddGadget);
                self.listenTo(self.gadgetCollection, 'remove:view', self.onRemoveGadget);
                self.listenTo(self.gadgetCollection, 'remove', self.checkEmptyDashboard);
                self.activateGridStack();
                self.listenTo(self.model, 'add:widget', self.onAddNewGadget);
                self.listenTo(self.model, 'change:isShared', self.onShareDashboard);
            });

        },
        render: function() {
            this.$el.html(Util.templates(this.template, {}));
        },
        onAddNewGadget: function(model) {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(model);
            this.updateScroll();
        },
        onShareDashboard: function(){
            if(this.model.get('isShared')){
                _.each(this.gadgetViews, function(view){
                    view.model.set('isShared', true);
                }, this);
            }
        },
        activateGridStack: function() {
            var $gridStack = $('[data-js-grid-stack]', this.$el);
            $gridStack.gridstack({
                cellHeight: config.widgetGridCellHeight,
                verticalMargin: config.widgetGridVerticalMargin,
                draggable: {
                    handle: '[data-js-drag-handle]'
                },
                resizable: {
                    handles: 'se, sw'
                },
                disableDrag: !this.model.get('isMy'),
                disableResize: !this.model.get('isMy'),
            });
            this.gridStack = $gridStack.data('gridstack');
            this.createGadgets();
            var self = this;
            $gridStack.on('change', function (e, items) {
                _.each(items, function(item) {
                    var id = item.el.data('id');
                    if(!id) return;
                    var gadgetModel = self.gadgetCollection.get(id);
                    if(!gadgetModel) return;
                    gadgetModel.set({
                        x: item.x,
                        y: item.y,
                        width: item.width,
                        height: item.height,
                    });
                });
                self.gadgetCollection.sort();
                self.updateScroll();
            });
            $gridStack.on('resizestart', function (event, ui) {
                var view = event.target.backboneView;
                view && view.startResize();
            });
            $gridStack.on('resizestop', function (event, ui) {
                var view = event.target.backboneView;
                setTimeout(function(){
                    view && view.stopResize();
                }, 300);
            });

        },
        onClickFullScreen: function(e) {
            e.preventDefault();
            $('body').fullscreen({toggleClass: 'fullscreen'});
            this.updateGadgetsTimer();
        },
        onAddGadget: function(gadgetModel) {
            var view = new GadgetView({model: gadgetModel, dashboardModel: this.model});
            this.gridStack.addWidget.apply(this.gridStack, view.getDataForGridStack());
            this.gadgetViews.push(view);
        },
        onRemoveGadget: function(view) {
            this.gridStack.removeWidget(view.el);
        },
        checkEmptyDashboard: function() {
            if(!this.model.getWidgets().length) {
                this.$el.addClass('not-found');
            } else {
                this.$el.removeClass('not-found');
            }
        },
        createGadgets: function() {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(this.model.getWidgets(), {silent: true, parse: true});
            this.gadgetCollection.forEach(function(model){
                this.onAddGadget(model);
            }, this);
            this.updateScroll();
            var self = this;
            this.$el.on('resize', function(){
                self.scrollerAnimate.resize();
            });
        },
        updateScroll: function() {
            var self = this;
            this.onShowAsync.done(function() {
                self.scrollerAnimate = new ScrollerAnimate(self.gadgetViews);
                self.scrollElement
                    .off('scroll.dashboardPage')
                    .on("scroll.dashboardPage", function (e) {
                        self.onScroll();
                    });
                self.onScroll();
            })
        },
        onShow: function() {
            this.onShowAsync.resolve();
        },
        onScroll: function() {
            var scrollTop = this.scrollElement.scrollTop();
            this.scrollerAnimate.activateScroll(scrollTop);
        },
        onClickEdit: function(e) {
            e.preventDefault();
            e.stopPropagation();
            var self = this;
            (new ModalEditDashboard({
                dashboardCollection: this.model.collection,
                dashboardModel: this.model,
                mode: 'edit',
            })).show().done(function(newModel) {
                self.model.set(newModel.toJSON());
            })
        },
        onClickRemove: function(e) {
            e.preventDefault();
            e.stopPropagation();
            var self = this;
            (new ModalConfirm({
                headerText: Localization.dialogHeader.dashboardDelete,
                bodyText: Util.replaceTemplate(Localization.dialog.dashboardDelete, this.model.get('name')),
                okButtonDanger: true,
                cancelButtonText: Localization.ui.cancel,
                okButtonText: Localization.ui.delete,
            })).show().done(function() {
                var collection = self.model.collection;
                self.model.collection.remove(self.model);
                self.destroy();
                collection.resetActive();
            })
        },
        onClickExitFullScreen: function(e) {
            clearTimeout(this.updateTimer);
            e.preventDefault();
            e.stopPropagation();
            $.fullscreen.exit();
        },
        updateGadgetsTimer: function() {
            clearTimeout(this.updateTimer);
            var self = this;
            this.updateTimer = setTimeout(function() {
                _.each(self.gadgetCollection.models, function(gadgetModel) {
                    gadgetModel.trigger('update:timer');
                });
                self.updateGadgetsTimer();
            }, 60000);
        },
        onClickAddWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickAddSharedWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            (new modalAddSharedWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        destroy: function () {
            clearTimeout(this.updateTimer);
            $.fullscreen.exit();
            this.undelegateEvents();
            this.gridStack && this.gridStack.destroy();
            this.$el.off('resize');
            this.scrollElement.off('scroll.dashboardPage');
            this.stopListening();
            this.unbind();
            this.$el.remove();
        },
    });

    function ScrollerAnimate(blocks){
        this.blocks = blocks;
        this.scrollMap = [];
        this.documentHeight = 0;

        this._createScrollMap = function(){
            this.scrollMap = [];
            this.documentHeight = document.documentElement.clientHeight;
            for(var i = 0; i < this.blocks.length; i++){
                this.scrollMap.push({
                    scrollStart: this.blocks[i].el.offsetTop,
                    scrollEnd: this.blocks[i].el.offsetTop + this.blocks[i].el.offsetHeight
                });
            }
        };

        this.activateScroll = function(scrollTop){
            var scrollBottom = scrollTop + this.documentHeight;
            var showBlockIndexs = [];
            for(var i = 0; i < this.scrollMap.length; i++){
                if((this.scrollMap[i].scrollStart <= scrollBottom && scrollTop < this.scrollMap[i].scrollStart)
                    || (this.scrollMap[i].scrollEnd <= scrollBottom && scrollTop < this.scrollMap[i].scrollEnd)
                    || (this.scrollMap[i].scrollEnd > scrollBottom && scrollTop >= this.scrollMap[i].scrollStart)){
                    showBlockIndexs.push(i);
                    if(!this.blocks[i].activate){
                        this.blocks[i].activate = true;
                        this.blocks[i].activateGadget();
                    }
                }
            }
            // return middle block index
            if(showBlockIndexs.length != 2) return showBlockIndexs[parseInt(showBlockIndexs.length/2)];
            var middleScreen = scrollBottom - this.documentHeight/2,
                blockSeparate = this.scrollMap[showBlockIndexs[0]].scrollEnd;
            if(blockSeparate > middleScreen) return showBlockIndexs[0];
            return showBlockIndexs[1];
        };

        this.resize = function(){
            this._createScrollMap();
            this.activateScroll(config.mainScrollElement.scrollTop());
        }

        this._createScrollMap();
    }

    return DashboardItemView;
});
<|endoftext|>


<commit_before>(function () {
  "use strict";
  /**
   * Main controller for the phylogenomics pipeline page.
   * @param $http AngularJS http object
   * @constructor
   */
  function PipelineController($http) {
    var vm = this;
    /*
     * Whether or not the page is waiting for a response from the server.
     */
    vm.loading = false;

    /**
     * Launch the phylogenomics pipeline
     */
    vm.launch = function () {
      var
      // reference file id
      ref = Number(angular.element('option:selected').val()),
      // User defined name for the pipeline
      name = angular.element('#pipeline-name').val(),
      // All the selected sample single or pair-end files
      radioBtns = angular.element("input[type='radio']:checked"),
      // Holds all the ids for the selected single-end
      single = [],
      // Holds all the ids for the selected paired-end
      paired = [];

      if (name === null || name.length === 0) {
        vm.error = PIPELINE.required;
      } else {
        // Hide the launch buttons and display a message that it has been sent.
        vm.loading = true;

        // Get a list of paired and single end files to run.
        _.forEach(radioBtns, function (c) {
          c = $(c);
          if (c.attr('data-type') === 'single_end') {
            single.push(Number(c.val()));
          }
          else {
            paired.push(Number(c.val()));
          }
        });

        var paras = {};
        _.forEach(PIPELINE.parameters, function (p) {
          paras[p.name] = p.value;
        });

        // Create the parameter object;
        var params = {};
        if($.isNumeric(ref)){
          params['ref'] = ref;
        }
        if(single.length>0) {
          params['single'] = single;
        }
        if(paired.length>0) {
          params['paired'] = paired;
        }
        if(_.keys(paras).length>0) {
          params['paras'] = paras;
        }
        params['name'] = angular.element("#pipeline-name").val();

        $http({
          url     : PIPELINE.url,
          method  : 'POST',
          dataType: 'json',
          params  : params,
          headers : {
            "Content-Type": "application/json"
          }
        })
          .success(function (data) {
            if (data.result === 'success') {
              vm.success = true;
            }
            else {
              if (data.error) {
                vm.error = data.error;
              }
              else if (data.parameters) {
                vm.paramError = data.parameters;
              }
            }
          });
      }
    };
  }

  function ParameterModalController($modal) {
    var vm = this;

    vm.openModal = function () {
      $modal.open({
        templateUrl: '/parameters.html',
        controller : 'ParameterController as paras'
      });
    };
  }

  function ParameterController($modalInstance) {
    var vm = this;
    PIPELINE.defaults = PIPELINE.defaults || angular.copy(PIPELINE.parameters);
    vm.parameters = angular.copy(PIPELINE.parameters);

    vm.update = function () {
      PIPELINE.parameters = angular.copy(vm.parameters);
      $modalInstance.close();
    };

    vm.close = function () {
      $modalInstance.dismiss();
    };

    vm.reset = function (index) {
      vm.parameters[index] = angular.copy(PIPELINE.defaults[index]);

    };
  }

  angular.module('irida.pipelines', [])
    .controller('PipelineController', ['$http', PipelineController])
    .controller('ParameterModalController', ["$modal", ParameterModalController])
    .controller('ParameterController', ['$modalInstance', ParameterController])
  ;
})();<commit_msg>Removed references to phylogenomics.<commit_after>(function () {
  "use strict";
  /**
   * Main controller for the pipeline launch page.
   * @param $http AngularJS http object
   * @constructor
   */
  function PipelineController($http) {
    var vm = this;
    /*
     * Whether or not the page is waiting for a response from the server.
     */
    vm.loading = false;

    /**
     * Launch the pipeline
     */
    vm.launch = function () {
      var
      // reference file id
      ref = Number(angular.element('option:selected').val()),
      // User defined name for the pipeline
      name = angular.element('#pipeline-name').val(),
      // All the selected sample single or pair-end files
      radioBtns = angular.element("input[type='radio']:checked"),
      // Holds all the ids for the selected single-end
      single = [],
      // Holds all the ids for the selected paired-end
      paired = [];

      if (name === null || name.length === 0) {
        vm.error = PIPELINE.required;
      } else {
        // Hide the launch buttons and display a message that it has been sent.
        vm.loading = true;

        // Get a list of paired and single end files to run.
        _.forEach(radioBtns, function (c) {
          c = $(c);
          if (c.attr('data-type') === 'single_end') {
            single.push(Number(c.val()));
          }
          else {
            paired.push(Number(c.val()));
          }
        });

        var paras = {};
        _.forEach(PIPELINE.parameters, function (p) {
          paras[p.name] = p.value;
        });

        // Create the parameter object;
        var params = {};
        if($.isNumeric(ref)){
          params['ref'] = ref;
        }
        if(single.length>0) {
          params['single'] = single;
        }
        if(paired.length>0) {
          params['paired'] = paired;
        }
        if(_.keys(paras).length>0) {
          params['paras'] = paras;
        }
        params['name'] = angular.element("#pipeline-name").val();

        $http({
          url     : PIPELINE.url,
          method  : 'POST',
          dataType: 'json',
          params  : params,
          headers : {
            "Content-Type": "application/json"
          }
        })
          .success(function (data) {
            if (data.result === 'success') {
              vm.success = true;
            }
            else {
              if (data.error) {
                vm.error = data.error;
              }
              else if (data.parameters) {
                vm.paramError = data.parameters;
              }
            }
          });
      }
    };
  }

  function ParameterModalController($modal) {
    var vm = this;

    vm.openModal = function () {
      $modal.open({
        templateUrl: '/parameters.html',
        controller : 'ParameterController as paras'
      });
    };
  }

  function ParameterController($modalInstance) {
    var vm = this;
    PIPELINE.defaults = PIPELINE.defaults || angular.copy(PIPELINE.parameters);
    vm.parameters = angular.copy(PIPELINE.parameters);

    vm.update = function () {
      PIPELINE.parameters = angular.copy(vm.parameters);
      $modalInstance.close();
    };

    vm.close = function () {
      $modalInstance.dismiss();
    };

    vm.reset = function (index) {
      vm.parameters[index] = angular.copy(PIPELINE.defaults[index]);

    };
  }

  angular.module('irida.pipelines', [])
    .controller('PipelineController', ['$http', PipelineController])
    .controller('ParameterModalController', ["$modal", ParameterModalController])
    .controller('ParameterController', ['$modalInstance', ParameterController])
  ;
})();<|endoftext|>