<commit_before>import React, { Component, PropTypes } from 'react';
import Slide from '../slide';
import BulletPoint from '../bullet-point';
import Presentation from '../../containers/presentation';
import CodeBlock from '../../containers/code-block';

require('./app.scss');

class App extends Component {
    render() {
        return (
            <Presentation>
                {/* Introduction slides */}
                <Slide title="ReactJS"></Slide>
                <Slide title="What is ReactJS?">
                    <BulletPoint>A generic way to create UI build blocks -- kind of like legos.</BulletPoint>
                    <BulletPoint>Each building block (component) has exactly what it needs.</BulletPoint>
                </Slide>
                <Slide title="The V in MVC">
                    <BulletPoint>Templating language?</BulletPoint>
                    <BulletPoint>Framework vs library?</BulletPoint>
                    <BulletPoint>Hold over till web components?</BulletPoint>
                </Slide>
                <Slide title="Why Use ReactJS?">
                    <BulletPoint>Thinking in modularity.</BulletPoint>
                    <BulletPoint>Able to work with other frameworks and libraries.</BulletPoint>
                    <BulletPoint>Performance optimizations.</BulletPoint>
                    <BulletPoint>Enforces UI and workflow patterns.</BulletPoint>
                    <BulletPoint>Easy to reason about your UI code and logic.</BulletPoint>
                </Slide>
                <Slide title="Challenges in Using ReactJS">
                    <BulletPoint>ReactJS alone can not be used to create an application.</BulletPoint>
                    <BulletPoint>Learning lots of new tools.</BulletPoint>
                    <BulletPoint>Setup and structure.</BulletPoint>
                </Slide>
                <Slide title="Anatomy of a Component">
                    <CodeBlock source="/src/components/bullet-point/index.js" />
                </Slide>
                <Slide title="Usage of a Component">
                    <BulletPoint>Component Code</BulletPoint>
                    <CodeBlock source="/src/examples/bullet-point-usage.js" />
                    <BulletPoint>Rendered HTML</BulletPoint>
                    <CodeBlock source="/src/examples/bullet-point-rendered.txt" />
                </Slide>
                <Slide title="Isn't That Code Example Doing It Wrong?">
                    <BulletPoint>Why keep HTML, Javascript and CSS all together?</BulletPoint>
                    <BulletPoint>Separation of concerns is around presentation and data management.</BulletPoint>
                    <BulletPoint>Source of truth for the code.</BulletPoint>
                </Slide>
                <Slide title="JSX">
                    <BulletPoint>Is an optional HTML-like syntax to create JavaScript objects.</BulletPoint>
                    <BulletPoint>It is possible to use React's createElement to generate the HTML but JSX tends to be easier to read.</BulletPoint>
                    <BulletPoint>With out JSX:</BulletPoint>
                    <CodeBlock>
                        {`React.createElement(\n    'a',\n    {href: 'https://facebook.github.io/react/', style: {color: '#f00'}, className="red-link"},\n    'Hello!'\n)`}
                    </CodeBlock>
                    <BulletPoint>With JSX:</BulletPoint>
                    <CodeBlock>
                        {`<a className="red-link" href="https://facebook.github.io/react/" style={{color: '#f00'}}>\n    Hello!\n</a>`}
                    </CodeBlock>
                </Slide>
                <Slide title="Component Props">
                    <BulletPoint>Data passed in through parent.</BulletPoint>
                    <BulletPoint>Props can not be changed from within the component.</BulletPoint>
                    <BulletPoint>Similar to HTML attributes.</BulletPoint>
                    <BulletPoint>Default props can be set and types of the props defined</BulletPoint>
                </Slide>
                <Slide title="Props in action">
                    <CodeBlock source="/src/examples/slide.txt" />
                </Slide>
                <Slide title="Component State">
                    <BulletPoint>Private data mangaged by the component.</BulletPoint>
                    <BulletPoint>State can change over time from within the component.</BulletPoint>
                    <BulletPoint>Best practices is to use sparingly.</BulletPoint>
                </Slide>
                <Slide title="State in action">
                    <CodeBlock source="/src/examples/state.txt" />
                </Slide>
                <Slide title="Lifecycle Methods">
                    <BulletPoint>Methods called during the creation, manipulation and deletion of a component.</BulletPoint>
                    <BulletPoint>Mounting: componentWillMount, componentDidMount</BulletPoint>
                    <BulletPoint>Updating: componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate</BulletPoint>
                    <BulletPoint>Unmounting: componentWillUnmount</BulletPoint>
                </Slide>
                <Slide title="Render">
                    <BulletPoint>All components must have a render function</BulletPoint>
                    <BulletPoint>Re-render everything makes everything simple.</BulletPoint>
                    <BulletPoint>Virtual DOM helps keeps render fast.</BulletPoint>
                    <BulletPoint>The Virtual DOM is not the same thing as Shadow DOM.</BulletPoint>
                </Slide>
                <Slide title="Component Communication">
                    <BulletPoint>What is Flux?</BulletPoint>
                    <BulletPoint>Unidirectional data flow: props flow down and events flow up.</BulletPoint>
                    <BulletPoint>Views dispatch actions.</BulletPoint>
                    <BulletPoint>An action describles the change with the minimum amount of information needed.</BulletPoint>
                    <BulletPoint>The store responses to dispatched actions.</BulletPoint>
                    <BulletPoint>The store will emit a change event.</BulletPoint>
                    <BulletPoint>The view listens to changes in the store.</BulletPoint>
                    <BulletPoint>The politics app uses react-redux as our flux library</BulletPoint>
                </Slide>
                <Slide title="Questions and More Resources">
                    <BulletPoint>React For Stupid People</BulletPoint>
                    <BulletPoint>Flux For Stupid People</BulletPoint>
                    <BulletPoint>Removing User Interface Complexity, or Why React is Awesome</BulletPoint>
                    <BulletPoint>Thinking In React</BulletPoint>
                    <BulletPoint>React Lifecycle Method Documentation</BulletPoint>
                    <BulletPoint>Full Documentation</BulletPoint>
                    <BulletPoint>React Hot Boilerplate</BulletPoint>
                    <BulletPoint>The Repository For This Presentation</BulletPoint>
                </Slide>
            </Presentation>
        );
    }
}

export default App;
<commit_msg>Update lifecycle slide and communication<commit_after>import React, { Component, PropTypes } from 'react';
import Slide from '../slide';
import BulletPoint from '../bullet-point';
import Presentation from '../../containers/presentation';
import CodeBlock from '../../containers/code-block';

require('./app.scss');

class App extends Component {
    render() {
        return (
            <Presentation>
                {/* Introduction slides */}
                <Slide title="ReactJS"></Slide>
                <Slide title="What is ReactJS?">
                    <BulletPoint>A generic way to create UI build blocks -- kind of like legos.</BulletPoint>
                    <BulletPoint>Each building block (component) has exactly what it needs.</BulletPoint>
                </Slide>
                <Slide title="The V in MVC">
                    <BulletPoint>Templating language?</BulletPoint>
                    <BulletPoint>Framework vs library?</BulletPoint>
                    <BulletPoint>Hold over till web components?</BulletPoint>
                </Slide>
                <Slide title="Why Use ReactJS?">
                    <BulletPoint>Thinking in modularity.</BulletPoint>
                    <BulletPoint>Able to work with other frameworks and libraries.</BulletPoint>
                    <BulletPoint>Performance optimizations.</BulletPoint>
                    <BulletPoint>Enforces UI and workflow patterns.</BulletPoint>
                    <BulletPoint>Easy to reason about your UI code and logic.</BulletPoint>
                </Slide>
                <Slide title="Challenges in Using ReactJS">
                    <BulletPoint>ReactJS alone can not be used to create an application.</BulletPoint>
                    <BulletPoint>Learning lots of new tools.</BulletPoint>
                    <BulletPoint>Setup and structure.</BulletPoint>
                </Slide>
                <Slide title="Anatomy of a Component">
                    <CodeBlock source="/src/components/bullet-point/index.js" />
                </Slide>
                <Slide title="Usage of a Component">
                    <BulletPoint>Component Code</BulletPoint>
                    <CodeBlock source="/src/examples/bullet-point-usage.js" />
                    <BulletPoint>Rendered HTML</BulletPoint>
                    <CodeBlock source="/src/examples/bullet-point-rendered.txt" />
                </Slide>
                <Slide title="Isn't That Code Example Doing It Wrong?">
                    <BulletPoint>Why keep HTML, Javascript and CSS all together?</BulletPoint>
                    <BulletPoint>Separation of concerns is around presentation and data management.</BulletPoint>
                    <BulletPoint>Source of truth for the code.</BulletPoint>
                </Slide>
                <Slide title="JSX">
                    <BulletPoint>Is an optional HTML-like syntax to create JavaScript objects.</BulletPoint>
                    <BulletPoint>It is possible to use React's createElement to generate the HTML but JSX tends to be easier to read.</BulletPoint>
                    <BulletPoint>With out JSX:</BulletPoint>
                    <CodeBlock>
                        {`React.createElement(\n    'a',\n    {href: 'https://facebook.github.io/react/', style: {color: '#f00'}, className="red-link"},\n    'Hello!'\n)`}
                    </CodeBlock>
                    <BulletPoint>With JSX:</BulletPoint>
                    <CodeBlock>
                        {`<a className="red-link" href="https://facebook.github.io/react/" style={{color: '#f00'}}>\n    Hello!\n</a>`}
                    </CodeBlock>
                </Slide>
                <Slide title="Component Props">
                    <BulletPoint>Data passed in through parent.</BulletPoint>
                    <BulletPoint>Props can not be changed from within the component.</BulletPoint>
                    <BulletPoint>Similar to HTML attributes.</BulletPoint>
                    <BulletPoint>Default props can be set and types of the props defined</BulletPoint>
                </Slide>
                <Slide title="Props in action">
                    <CodeBlock source="/src/examples/slide.txt" />
                </Slide>
                <Slide title="Component State">
                    <BulletPoint>Private data mangaged by the component.</BulletPoint>
                    <BulletPoint>State can change over time from within the component.</BulletPoint>
                    <BulletPoint>Best practices is to use sparingly.</BulletPoint>
                </Slide>
                <Slide title="State in action">
                    <CodeBlock source="/src/examples/state.txt" />
                </Slide>
                <Slide title="Lifecycle Methods">
                    <BulletPoint>Methods called during the creation, manipulation and deletion of a component.</BulletPoint>
                    <BulletPoint>Mounting: componentWillMount, componentDidMount</BulletPoint>
                    <BulletPoint>Updating: componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate</BulletPoint>
                    <BulletPoint>Unmounting: componentWillUnmount</BulletPoint>
                    <BulletPoint>Mounting methods are useful for setting up custom event listeners.</BulletPoint>
                    <BulletPoint>Updating methods are great at having greater control of how and when the component updates.</BulletPoint>
                    <BulletPoint>Unmounting methods are useful for cleaning up after your module gets removed.</BulletPoint>
                </Slide>
                <Slide title="Render">
                    <BulletPoint>All components must have a render function</BulletPoint>
                    <BulletPoint>Re-render everything makes everything simple.</BulletPoint>
                    <BulletPoint>Virtual DOM helps keeps render fast.</BulletPoint>
                    <BulletPoint>The Virtual DOM is not the same thing as Shadow DOM.</BulletPoint>
                </Slide>
                <Slide title="Component Communication">
                    <BulletPoint>Unidirectional data flow: props flow down and events flow up.</BulletPoint>
                    <BulletPoint>Similar to a Pub/Sub model.</BulletPoint>
                </Slide>
                <Slide title="Questions and More Resources">
                    <BulletPoint>React For Stupid People</BulletPoint>
                    <BulletPoint>Flux For Stupid People</BulletPoint>
                    <BulletPoint>Removing User Interface Complexity, or Why React is Awesome</BulletPoint>
                    <BulletPoint>Thinking In React</BulletPoint>
                    <BulletPoint>React Lifecycle Method Documentation</BulletPoint>
                    <BulletPoint>Full Documentation</BulletPoint>
                    <BulletPoint>React Hot Boilerplate</BulletPoint>
                    <BulletPoint>The Repository For This Presentation</BulletPoint>
                </Slide>
            </Presentation>
        );
    }
}

export default App;
<|endoftext|>


<commit_before>import React from 'react';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import mainReducer from '../../reducers';
import './App.css';
import templateHome from '../../templates/home.js';
import templateCountry from '../../templates/country.js';

import {
    browserHistory,
    Router,
    Route,
    IndexRoute,
} from "react-router";

const store = createStore(mainReducer);

const App = () => {
    return (
        <Provider store={store}>
            <Router history={browserHistory}>
                <Route path="/">
                    <Route path=":country" component={templateCountry} />
                    <IndexRoute component={templateHome} />
                </Route>
            </Router>
        </Provider>
    )
};

export default App;
<commit_msg>Add Header and Footer<commit_after>import React from 'react';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import mainReducer from '../../reducers';
import './App.css';
import templateHome from '../../templates/home.js';
import templateCountry from '../../templates/country.js';
import Header from '../header'
import Footer from '../footer'
import {
    browserHistory,
    Router,
    Route,
    IndexRoute,
} from "react-router";

const store = createStore(mainReducer);

const App = () => {
    return (
      <div>
        <Header />
        <Provider store={store}>
            <Router history={browserHistory}>
                <Route path="/">
                    <Route path=":country" component={templateCountry} />
                    <IndexRoute component={templateHome} />
                </Route>
            </Router>
        </Provider>
        <Footer />
      </div>
    )
};

export default App;
<|endoftext|>


<commit_before>(function(){
  'use strict';
  angular.module('civic.states')
    .config(routesConfig);

  // @ngInject
  function routesConfig($stateProvider, $urlRouterProvider) {

    // 404
    $urlRouterProvider.otherwise('home');

    // abstract state redirects
    $urlRouterProvider.when('/events/genes/:geneId', '/events/genes/:geneId/summary');
    $urlRouterProvider.when('/events/genes', '/browse');
    $urlRouterProvider.when('/events', '/browse');

    // NOTE: data.titleExp in state configs are ng expressions parsed by the TitleService

    // static frontend pages
    $stateProvider
      .state('home', {
        url: '/home',
        controller: 'HomeCtrl',
        templateUrl: 'app/pages/home.tpl.html',
        data: {
          titleExp: '"Home"',
          navMode: 'home'
        }
      })
      .state('collaborate', {
        url: '/collaborate',
        controller: 'CollaborateCtrl',
        templateUrl: 'app/pages/collaborate.tpl.html',
        data: {
          titleExp: '"Collaborate"',
          navMode: 'sub'
        }
      })
      .state('help', {
        url: '/help',
        controller: 'HelpCtrl',
        templateUrl: 'app/pages/help.tpl.html',
        data: {
          titleExp: '"Help"',
          navMode: 'sub'
        }
      })
      .state('contact', {
        url: '/contact',
        controller: 'ContactCtrl',
        templateUrl: 'app/pages/contact.tpl.html',
        data: {
          titleExp: '"Contact"',
          navMode: 'sub'
        }
      });

    // browse
    $stateProvider
      .state('browse', {
        url: '/browse',
        controller: 'BrowseCtrl',
        templateUrl: 'app/views/browse/browse.tpl.html',
        data: {
          titleExp: '"Browse"',
          navMode: 'sub'
        }
      });

    // EVENT VIEWS
    // gene, variant, evidence & associated activity views
    $stateProvider
      .state('events', {
        abstract: true,
        url: '/events',
        templateUrl: 'app/views/events/eventsView.tpl.html',
        data: {
          titleExp: '"Choose Gene"',
          navMode: 'sub'
        },
        onExit: /* ngInject */ function($deepStateRedirect) {
          $deepStateRedirect.reset();
        }
      })
      .state('events.genes', {
        abstract: true,
        url: '/genes/:geneId',
        templateUrl: 'app/views/events/genes/genesView.tpl.html',
        data: {
          titleExp: '"Event"',
          navMode: 'sub'
        },
        resolve: /* ngInject */ {
          Genes: 'Genes',
          MyGene: 'MyGene',
          gene: function(Genes, $stateParams, $log) {
            return Genes.get({
              'geneId': $stateParams.geneId
            }).$promise;
          },
          geneDetails: function(MyGene, gene) {
            return MyGene.getDetails({'geneId': gene.entrez_id }).$promise;
          }
        },
        controller: 'GenesViewCtrl',
        onExit: /* ngInject */ function($deepStateRedirect) {
          $deepStateRedirect.reset();
        }
      })
      .state('events.genes.summary', {
        url: '/summary',
        controller: function($scope, gene, geneDetails) {
          $scope.geneView.gene = gene;
          $scope.geneView.geneDetails = geneDetails;
        },
        template: '<gene-summary gene="geneView.gene" gene-details="geneView.geneDetails"></gene-summary>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: true
      })
      .state('events.genes.edit', {
        url: '/edit',
        template: '<gene-edit class="col-xs-12"></gene-edit>',
        controller: 'GeneEditCtrl',
        resolve: {
          geneEdit: function(Genes, gene, $stateParams, $log) {
            $log.info('appStates: resolving geneEdit.');
            return Genes.get({'geneId': gene.entrez_id }).$promise;
          }
        },
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.talk', {
        url: '/talk',
        template: '<gene-talk class="col-xs-12"></gene-talk>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Talk"',
          navMode: 'sub'
        },
        controller: function(gene, $scope) {
          $scope.gene = gene;
        }
      })
      .state('events.genes.talk.comments', {
        url: '/comments',
        template: '<gene-talk-comments></gene-talk-comments>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Talk"',
          navMode: 'sub'
        },
        controller: function(gene, $scope) {
          $scope.gene = gene; // place resolved gene from events.genes in scope
        }
      })
      .state('events.genes.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<gene-talk-change></gene-talk-change>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Changes"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variantGroups', {
        abstract: true,
        url: '/variant-groups/:variantGroupId',
        templateUrl: 'app/views/events/variantGroups/variantGroupsView.tpl.html',
        data: {
          titleExp: '"Variant Group"',
          navMode: 'sub'
        },
        resolve: /* ngInject */ {
          VariantGroups: 'VariantGroups',
          variantGroup: function(VariantGroups, $stateParams) {
            return VariantGroups.get({ variantGroupId: $stateParams.variantGroupId }).$promise;
          }
        },
        controller: 'VariantGroupsCtrl'
      })
      .state('events.genes.summary.variantGroups.summary', {
        url: '/summary',
        template: '<variant-group-summary></variant-group-summary>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: { params: ['variantGroupId'] }
      })
      .state('events.genes.summary.variantGroups.edit',{
        url: '/edit',
        template: '<variant-group-edit></variant-group-edit>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variantGroups.talk',{
        url: '/talk',
        template: '<variant-group-talk></variant-group-talk>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(variantGroup, $scope) {
          $scope.variantGroup = variantGroup;
        }
      })
      .state('events.genes.summary.variantGroups.talk.comments',{
        url: '/comments',
        template: '<variant-group-talk-comments></variant-group-talk-comments>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Comments"',
          navMode: 'sub'
        },
        controller: function(variantGroup, $scope) {
          $scope.variantGroup = variantGroup;
        }
      })
      .state('events.genes.summary.variants', {
        abtract: true,
        url: '/variants/:variantId',
        controller: 'VariantsViewCtrl',
        templateUrl: 'app/views/events/variants/variantsView.tpl.html',
        resolve: /* ngInject */ {
          Variants: 'Variants',
          variant: function(Variants, $stateParams, $log) {
            $log.info('events.variants - resolving variant');
            return Variants.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId }).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.summary', {
        url: '/summary',
        template: '<variant-summary></variant-summary>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name  + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: { params: ['variantId'] }
      })
      .state('events.genes.summary.variants.edit', {
        url:'/edit',
        template: '<variant-edit></variant-edit>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Edit"',
          navMode: 'sub'
        },
        resolve: {
          variantEdit: function(Variants, $stateParams, $log) {
            $log.info('appStates: resolving variantEdit.');
            return Variants.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId}).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.talk', {
        url:'/talk',
        template: '<variant-talk></variant-talk>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.talk.comments', {
        url: '/comments',
        template: '<variant-talk-comments></variant-talk-comments>',
        data: {
          titleExp: '"Variant " + variant.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(variant, $scope) {
          $scope.variant = variant;
        }
      })
      .state('events.genes.summary.variants.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<variant-talk-change></variant-talk-change>',
        data: {
          titleExp: '"Variant " + variant.name + " Changes"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence', {
        abstract: true,
        url: '/evidence/:evidenceItemId',
        controller: 'EvidenceViewCtrl',
        templateUrl: 'app/views/events/evidence/evidenceView.tpl.html',
        resolve: /* ngInject */ {
          Evidence: 'Evidence',
          evidence: function(Evidence, $stateParams, $log) {
            $log.info('events.evidence- resolving evidence');
            return Evidence.get({
              'geneId': $stateParams.geneId,
              'variantId': $stateParams.variantId,
              'evidenceItemId': $stateParams.evidenceItemId
            }).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.summary.evidence.summary',{
        url: '/summary',
        template: '<evidence-summary></evidence-summary>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Summary"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.edit', {
        url: '/edit',
        template: '<evidence-edit></evidence-edit>',
        resolve: {
          evidenceEdit: function(Evidence, $stateParams, $log) {
            $log.info('appStates: resolving evidenceEdit.');
            return Evidence.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId, 'evidenceItemId': $stateParams.evidenceItemId }).$promise;
          }
        },
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " / " + evidence.id + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk', {
        url: '/talk',
        template: '<evidence-talk></evidence-talk>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk.comments', {
        url: '/comments',
        template: '<evidence-talk-comments></evidence-talk-comments>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(evidence, $scope) {
          $scope.evidence = evidence;
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<evidence-talk-change></evidence-talk-change>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Changes"',
          navMode: 'sub'
        },
        controller: function(evidence, $scope) {
          $scope.evidence = evidence;
        }
      });
  }
})();
<commit_msg>removed extraneous gene.summary state controller<commit_after>(function(){
  'use strict';
  angular.module('civic.states')
    .config(routesConfig);

  // @ngInject
  function routesConfig($stateProvider, $urlRouterProvider) {

    // 404
    $urlRouterProvider.otherwise('home');

    // abstract state redirects
    $urlRouterProvider.when('/events/genes/:geneId', '/events/genes/:geneId/summary');
    $urlRouterProvider.when('/events/genes', '/browse');
    $urlRouterProvider.when('/events', '/browse');

    // NOTE: data.titleExp in state configs are ng expressions parsed by the TitleService

    // static frontend pages
    $stateProvider
      .state('home', {
        url: '/home',
        controller: 'HomeCtrl',
        templateUrl: 'app/pages/home.tpl.html',
        data: {
          titleExp: '"Home"',
          navMode: 'home'
        }
      })
      .state('collaborate', {
        url: '/collaborate',
        controller: 'CollaborateCtrl',
        templateUrl: 'app/pages/collaborate.tpl.html',
        data: {
          titleExp: '"Collaborate"',
          navMode: 'sub'
        }
      })
      .state('help', {
        url: '/help',
        controller: 'HelpCtrl',
        templateUrl: 'app/pages/help.tpl.html',
        data: {
          titleExp: '"Help"',
          navMode: 'sub'
        }
      })
      .state('contact', {
        url: '/contact',
        controller: 'ContactCtrl',
        templateUrl: 'app/pages/contact.tpl.html',
        data: {
          titleExp: '"Contact"',
          navMode: 'sub'
        }
      });

    // browse
    $stateProvider
      .state('browse', {
        url: '/browse',
        controller: 'BrowseCtrl',
        templateUrl: 'app/views/browse/browse.tpl.html',
        data: {
          titleExp: '"Browse"',
          navMode: 'sub'
        }
      });

    // EVENT VIEWS
    // gene, variant, evidence & associated activity views
    $stateProvider
      .state('events', {
        abstract: true,
        url: '/events',
        templateUrl: 'app/views/events/eventsView.tpl.html',
        data: {
          titleExp: '"Choose Gene"',
          navMode: 'sub'
        },
        onExit: /* ngInject */ function($deepStateRedirect) {
          $deepStateRedirect.reset();
        }
      })
      .state('events.genes', {
        abstract: true,
        url: '/genes/:geneId',
        templateUrl: 'app/views/events/genes/genesView.tpl.html',
        data: {
          titleExp: '"Event"',
          navMode: 'sub'
        },
        resolve: /* ngInject */ {
          Genes: 'Genes',
          MyGene: 'MyGene',
          gene: function(Genes, $stateParams, $log) {
            return Genes.get({
              'geneId': $stateParams.geneId
            }).$promise;
          },
          geneDetails: function(MyGene, gene) {
            return MyGene.getDetails({'geneId': gene.entrez_id }).$promise;
          }
        },
        controller: 'GenesViewCtrl',
        onExit: /* ngInject */ function($deepStateRedirect) {
          $deepStateRedirect.reset();
        }
      })
      .state('events.genes.summary', {
        url: '/summary',
        template: '<gene-summary gene="geneView.gene" gene-details="geneView.geneDetails"></gene-summary>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: true
      })
      .state('events.genes.edit', {
        url: '/edit',
        template: '<gene-edit class="col-xs-12"></gene-edit>',
        controller: 'GeneEditCtrl',
        resolve: {
          geneEdit: function(Genes, gene, $stateParams, $log) {
            $log.info('appStates: resolving geneEdit.');
            return Genes.get({'geneId': gene.entrez_id }).$promise;
          }
        },
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.talk', {
        url: '/talk',
        template: '<gene-talk class="col-xs-12"></gene-talk>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Talk"',
          navMode: 'sub'
        },
        controller: function(gene, $scope) {
          $scope.gene = gene;
        }
      })
      .state('events.genes.talk.comments', {
        url: '/comments',
        template: '<gene-talk-comments></gene-talk-comments>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Talk"',
          navMode: 'sub'
        },
        controller: function(gene, $scope) {
          $scope.gene = gene; // place resolved gene from events.genes in scope
        }
      })
      .state('events.genes.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<gene-talk-change></gene-talk-change>',
        data: {
          titleExp: '"Gene " + gene.entrez_name + " Changes"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variantGroups', {
        abstract: true,
        url: '/variant-groups/:variantGroupId',
        templateUrl: 'app/views/events/variantGroups/variantGroupsView.tpl.html',
        data: {
          titleExp: '"Variant Group"',
          navMode: 'sub'
        },
        resolve: /* ngInject */ {
          VariantGroups: 'VariantGroups',
          variantGroup: function(VariantGroups, $stateParams) {
            return VariantGroups.get({ variantGroupId: $stateParams.variantGroupId }).$promise;
          }
        },
        controller: 'VariantGroupsCtrl'
      })
      .state('events.genes.summary.variantGroups.summary', {
        url: '/summary',
        template: '<variant-group-summary></variant-group-summary>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: { params: ['variantGroupId'] }
      })
      .state('events.genes.summary.variantGroups.edit',{
        url: '/edit',
        template: '<variant-group-edit></variant-group-edit>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variantGroups.talk',{
        url: '/talk',
        template: '<variant-group-talk></variant-group-talk>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(variantGroup, $scope) {
          $scope.variantGroup = variantGroup;
        }
      })
      .state('events.genes.summary.variantGroups.talk.comments',{
        url: '/comments',
        template: '<variant-group-talk-comments></variant-group-talk-comments>',
        data: {
          titleExp: '"Variant Group " + variantGroup.name + " Comments"',
          navMode: 'sub'
        },
        controller: function(variantGroup, $scope) {
          $scope.variantGroup = variantGroup;
        }
      })
      .state('events.genes.summary.variants', {
        abtract: true,
        url: '/variants/:variantId',
        controller: 'VariantsViewCtrl',
        templateUrl: 'app/views/events/variants/variantsView.tpl.html',
        resolve: /* ngInject */ {
          Variants: 'Variants',
          variant: function(Variants, $stateParams, $log) {
            $log.info('events.variants - resolving variant');
            return Variants.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId }).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.summary', {
        url: '/summary',
        template: '<variant-summary></variant-summary>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name  + " Summary"',
          navMode: 'sub'
        },
        deepStateRedirect: { params: ['variantId'] }
      })
      .state('events.genes.summary.variants.edit', {
        url:'/edit',
        template: '<variant-edit></variant-edit>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Edit"',
          navMode: 'sub'
        },
        resolve: {
          variantEdit: function(Variants, $stateParams, $log) {
            $log.info('appStates: resolving variantEdit.');
            return Variants.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId}).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.talk', {
        url:'/talk',
        template: '<variant-talk></variant-talk>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.talk.comments', {
        url: '/comments',
        template: '<variant-talk-comments></variant-talk-comments>',
        data: {
          titleExp: '"Variant " + variant.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(variant, $scope) {
          $scope.variant = variant;
        }
      })
      .state('events.genes.summary.variants.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<variant-talk-change></variant-talk-change>',
        data: {
          titleExp: '"Variant " + variant.name + " Changes"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence', {
        abstract: true,
        url: '/evidence/:evidenceItemId',
        controller: 'EvidenceViewCtrl',
        templateUrl: 'app/views/events/evidence/evidenceView.tpl.html',
        resolve: /* ngInject */ {
          Evidence: 'Evidence',
          evidence: function(Evidence, $stateParams, $log) {
            $log.info('events.evidence- resolving evidence');
            return Evidence.get({
              'geneId': $stateParams.geneId,
              'variantId': $stateParams.variantId,
              'evidenceItemId': $stateParams.evidenceItemId
            }).$promise;
          }
        }
      })
      .state('events.genes.summary.variants.summary.evidence.summary',{
        url: '/summary',
        template: '<evidence-summary></evidence-summary>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Summary"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.edit', {
        url: '/edit',
        template: '<evidence-edit></evidence-edit>',
        resolve: {
          evidenceEdit: function(Evidence, $stateParams, $log) {
            $log.info('appStates: resolving evidenceEdit.');
            return Evidence.get({'geneId': $stateParams.geneId, 'variantId': $stateParams.variantId, 'evidenceItemId': $stateParams.evidenceItemId }).$promise;
          }
        },
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " / " + evidence.id + " Edit"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk', {
        url: '/talk',
        template: '<evidence-talk></evidence-talk>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk.comments', {
        url: '/comments',
        template: '<evidence-talk-comments></evidence-talk-comments>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Talk"',
          navMode: 'sub'
        },
        controller: function(evidence, $scope) {
          $scope.evidence = evidence;
        }
      })
      .state('events.genes.summary.variants.summary.evidence.talk.changes', {
        url: '/changes/:suggestedChangeId',
        template: '<evidence-talk-change></evidence-talk-change>',
        data: {
          titleExp: '"Event " + gene.entrez_name + " / " + variant.name + " Changes"',
          navMode: 'sub'
        },
        controller: function(evidence, $scope) {
          $scope.evidence = evidence;
        }
      });
  }
})();
<|endoftext|>


<commit_before>import {
  BRICK,
  MAIN_BRICK,
  PIPE,
  PRIMITIVE,
  SELECTABLE_PIPE,
  SLOT,
  SURFACE,
  TEST_INPUT,
  TEST_OUTPUT,
  TEST_RESULT
} from '../utils/componentNames'

import { ERROR } from '../utils/evalUtils'

const colors = {
  boolean: "#8A2BE2",
  [ERROR]: '#D80000',
  false: "#E44B37",
  list: "#E9E759",
  null: "#BFBFBF",
  number: "#E96859",
  string: "#E9A559",
  true: "#358DE2",
  undefined: "#BFBFBF"
}

const testColors = {
  failing: '#d87777',
  passing: '#77d877',
  pending: '#d8d8d8'
}

const LEFT = 0

const font = '15px monospace'
const slotHeight = 15
const slotWidth = slotHeight

const TestNode = {
  font,
  slotHeight: slotHeight,
  slotWidth: slotWidth,
  textColor: 'black',
  yOffset: 60
}

const brickSlotOffset = 20
const mainBrickSlotOffset = 100

const Constants = {
  [BRICK]: {
    fillColor: '#ADD8E6',
    font: font,
    slotAndOffset: brickSlotOffset + slotWidth,
    slotHeight: slotHeight,
    slotOffset: brickSlotOffset,
    slotWidth: slotWidth,
    strokeColor: 'black',
    textColor: 'black',
    textErrorColor: colors[ERROR]
  },
  [MAIN_BRICK]: {
    fillColor: '#789',
    hoverFillColor: '#385661',
    slotAndOffset: mainBrickSlotOffset + slotWidth,
    slotHeight: slotHeight,
    slotOffset: mainBrickSlotOffset,
    slotWidth: slotWidth,
    strokeColor: 'black'
  },
  [PIPE]: {
    slotHeight: slotHeight,
    slotWidth: slotWidth
  },
  [PRIMITIVE]: {
    font: font,
    fontAlignment: 'middle',
    slotWidth: slotWidth,
    textColor: 'black'
  },
  [SELECTABLE_PIPE]: {
    font: font,
    strokeColor: 'black',
    textColor: 'black'
  },
  [SLOT]: {
    cursor: 'pointer',
    height: 15,
    width: slotWidth,
    fillColor: '#00FA9A'
  },
  [SURFACE]: {
    width: 450
  },
  [TEST_INPUT]: TestNode,
  [TEST_OUTPUT]: TestNode,
  [TEST_RESULT]: {
    slotHeight: slotHeight
  }
}

const getConstant = (componentName, key) => {
  return Constants[componentName][key]
}

export default {
  colors,
  getConstant,
  LEFT,
  testColors
}
<commit_msg>Individual exports in constants.js<commit_after>import {
  BRICK,
  MAIN_BRICK,
  PIPE,
  PRIMITIVE,
  SELECTABLE_PIPE,
  SLOT,
  SURFACE,
  TEST_INPUT,
  TEST_OUTPUT,
  TEST_RESULT
} from '../utils/componentNames'

import { ERROR } from '../utils/evalUtils'

export const colors = {
  boolean: "#8A2BE2",
  [ERROR]: '#D80000',
  false: "#E44B37",
  list: "#E9E759",
  null: "#BFBFBF",
  number: "#E96859",
  string: "#E9A559",
  true: "#358DE2",
  undefined: "#BFBFBF"
}

export const testColors = {
  failing: '#d87777',
  passing: '#77d877',
  pending: '#d8d8d8'
}

export const LEFT = 0

const font = '15px monospace'
const slotHeight = 15
const slotWidth = slotHeight

const TestNode = {
  font,
  slotHeight: slotHeight,
  slotWidth: slotWidth,
  textColor: 'black',
  yOffset: 60
}

const brickSlotOffset = 20
const mainBrickSlotOffset = 100

const Constants = {
  [BRICK]: {
    fillColor: '#ADD8E6',
    font: font,
    slotAndOffset: brickSlotOffset + slotWidth,
    slotHeight: slotHeight,
    slotOffset: brickSlotOffset,
    slotWidth: slotWidth,
    strokeColor: 'black',
    textColor: 'black',
    textErrorColor: colors[ERROR]
  },
  [MAIN_BRICK]: {
    fillColor: '#789',
    hoverFillColor: '#385661',
    slotAndOffset: mainBrickSlotOffset + slotWidth,
    slotHeight: slotHeight,
    slotOffset: mainBrickSlotOffset,
    slotWidth: slotWidth,
    strokeColor: 'black'
  },
  [PIPE]: {
    slotHeight: slotHeight,
    slotWidth: slotWidth
  },
  [PRIMITIVE]: {
    font: font,
    fontAlignment: 'middle',
    slotWidth: slotWidth,
    textColor: 'black'
  },
  [SELECTABLE_PIPE]: {
    font: font,
    strokeColor: 'black',
    textColor: 'black'
  },
  [SLOT]: {
    cursor: 'pointer',
    height: 15,
    width: slotWidth,
    fillColor: '#00FA9A'
  },
  [SURFACE]: {
    width: 450
  },
  [TEST_INPUT]: TestNode,
  [TEST_OUTPUT]: TestNode,
  [TEST_RESULT]: {
    slotHeight: slotHeight
  }
}

export const getConstant = (componentName, key) => {
  return Constants[componentName][key]
}
<|endoftext|>


<commit_before>import React from "react";
import { ReactSVGPanZoom } from "react-svg-pan-zoom";
import { updateVisibleTipsAndBranchThicknesses } from "../../actions/tree";
import Card from "../framework/card";
import Legend from "./legend/legend";
import PhyloTree from "./phyloTree/phyloTree";
import HoverInfoPanel from "./infoPanels/hover";
import TipClickedPanel from "./infoPanels/click";
import { changePhyloTreeViaPropsComparison } from "./reactD3Interface/change";
import * as callbacks from "./reactD3Interface/callbacks";
import { resetTreeButtonStyle } from "../../globalStyles";
import { renderTree } from "./reactD3Interface/initialRender";
import Tangle from "./tangle";

const postOrderIteration = function(node, callback){
    if (node.children){
        for (var i=0; i<node.children.length; i++){
            postOrderIteration(node.children[i], callback);
        }
    }
    callback(node);
}

const calculateNodeRank = function(nodes){
  let yvalue = nodes[0].fullTipCount;
  const assignNodeOrder = function(node){
    if (!node.children){
      yvalue--;
      node.yvalue = yvalue
      node.maxYvalue = yvalue;
      node.minYvalue = yvalue;
    }else{
      let s=0;
      for (let i=0;i<node.children.length; i++){
        s+=node.children[i].yvalue;
      }
      s/=node.children.length;
      node.yvalue = s;
      node.maxYvalue = node.children[node.children.length-1].yvalue;
      node.minYvalue = node.children[0].yvalue;
    }
  }
  postOrderIteration(nodes[0], assignNodeOrder);
}

const calculateOtherTreeRank = function(nodes, nameToNode){
  nodes.forEach(function(n){n.otherYvalue=0;});
  const assignNodeOrder = function(node){
    if (!node.children){
      if (nameToNode[node.strain]){
        node.otherYvalue += nameToNode[node.strain].yvalue;
      }
    }else{
      let s=0;
      for (let i=0;i<node.children.length; i++){
        if (node.children[i].otherYvalue){
          s += node.children[i].otherYvalue;
        }
      }
      node.otherYvalue = 1.0*s;
    }
  }
  postOrderIteration(nodes[0], assignNodeOrder);
  nodes.forEach(function(n){n.otherYvalue/=n.fullTipCount;});
}

class Tree extends React.Component {
  constructor(props) {
    super(props);
    this.tangleRef = undefined;
    this.Viewer = null;
    this.state = {
      hover: null,
      selectedBranch: null,
      selectedTip: null,
      tree: null,
      treeToo: null
    };
    /* bind callbacks */
    this.clearSelectedTip = callbacks.clearSelectedTip.bind(this);
    this.resetView = callbacks.resetView.bind(this);
    this.onViewerChange = callbacks.onViewerChange.bind(this);
    // this.handleIconClickHOF = callbacks.handleIconClickHOF.bind(this);
    this.redrawTree = () => {
      this.state.tree.clearSVG();
      this.Viewer.fitToViewer();
      renderTree(this, true, this.state.tree, this.props);
      if (this.props.showTreeToo) {
        this.state.treeToo.clearSVG();
        this.ViewerToo.fitToViewer();
        renderTree(this, false, this.state.treeToo, this.props);
      }
      this.setState({hover: null, selectedBranch: null, selectedTip: null});
      this.props.dispatch(updateVisibleTipsAndBranchThicknesses({root: [0, 0]}));
    };
  }
  componentDidMount() {
    if (this.props.tree.loaded) {
      calculateNodeRank(this.props.tree.nodes);
      const tree = new PhyloTree(this.props.tree.nodes, "LEFT");
      const nameToNode = {};
      for (let i=0;i<this.props.tree.nodes.length;i++){
        nameToNode[this.props.tree.nodes[i].strain] = this.props.tree.nodes[i];
      }
      renderTree(this, true, tree, this.props);
      this.Viewer.fitToViewer();
      const newState = {tree};
      if (this.props.showTreeToo) {
        calculateOtherTreeRank(this.props.treeToo.nodes, nameToNode);
        for (let i=0;i<this.props.treeToo.nodes.length;i++){
          let n=this.props.treeToo.nodes[i];
          if (n.children){
            // console.log(n.strain, n.children);
            n.children.sort(function(a,b){
              if (nameToNode[b.strain]&&nameToNode[a.strain]){
                return -(a.otherYvalue - b.otherYvalue);
              }else{
                return 0;
              }
            });
          }
        }
        calculateNodeRank(this.props.treeToo.nodes);
        const treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
        renderTree(this, false, treeToo, this.props);
        this.ViewerToo.fitToViewer();
        newState.treeToo = treeToo;
      }
      this.setState(newState);
    }
  }
  componentDidUpdate(prevProps) {
    let newState;
    let leftTreeUpdated;
    let rightTreeUpdated;
    let _; // eslint-disable-line

    if (this.state.tree) {
      [newState, leftTreeUpdated] = changePhyloTreeViaPropsComparison(true, this.state.tree, this.Viewer, prevProps, this.props);
      if (prevProps.showTreeToo !== this.props.showTreeToo) {
        this.state.tree.change({svgHasChangedDimensions: true});
        if (this.props.showTreeToo) {
          if (this.state.treeToo) { /* remove the old tree */
            this.state.treeToo.clearSVG();
          }
          const treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
          renderTree(this, false, treeToo, this.props);
          this.resetView(); // reset the position of the left tree
          if (this.tangleRef) this.tangleRef.drawLines();
          this.setState({treeToo});
        } else {
          this.setState({treeToo: null});
        }
        return;
      }
    }
    /* tree too */
    if (this.state.treeToo) {
      if (!prevProps.showTreeToo && this.props.showTreeToo) {
        newState.treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
        renderTree(this, false, newState.treeToo, this.props);
        this.ViewerToo.fitToViewer();
      } else if (!this.props.showTreeToo) {
        newState.treeToo = null;
      } else {
        [_, rightTreeUpdated] = changePhyloTreeViaPropsComparison(false, this.state.treeToo, this.ViewerToo, prevProps, this.props);
      }
    }
    /* we may need to (imperitively) tell the tangle to redraw */
    if (this.tangleRef && (leftTreeUpdated || rightTreeUpdated)) {
      this.tangleRef.drawLines();
    }
    if (newState) this.setState(newState);
  }
  renderTreeDiv({width, height, d3ref, viewerRef}) {
    return (
      <ReactSVGPanZoom
        width={width}
        height={height}
        ref={(Viewer) => {this[viewerRef] = Viewer;}}
        style={{cursor: "default"}}
        tool={"pan"}
        detectWheel={false}
        toolbarPosition={"none"}
        detectAutoPan={false}
        background={"#FFF"}
        miniaturePosition={"none"}
        onDoubleClick={this.resetView}
        onChangeValue={this.onViewerChange}
      >
        <svg style={{pointerEvents: "auto"}}
          width={width}
          height={height}
        >
          <g
            id={"d3TreeElement"}
            width={width}
            height={height}
            style={{cursor: "default"}}
            ref={(c) => {this[d3ref] = c;}}
          />
        </svg>
      </ReactSVGPanZoom>
    );
  }

  render() {
    const spaceBetweenTrees = 100;
    const widthPerTree = this.props.showTreeToo ? (this.props.width - spaceBetweenTrees) / 2 : this.props.width;
    return (
      <Card center title={"Phylogeny"}>
        <Legend width={this.props.width}/>
        <HoverInfoPanel
          mutType={this.props.mutType}
          temporalConfidence={this.props.temporalConfidence.display}
          distanceMeasure={this.props.distanceMeasure}
          hovered={this.state.hovered}
          viewer={this.Viewer}
          colorBy={this.props.colorBy}
          colorByConfidence={this.props.colorByConfidence}
          colorScale={this.props.colorScale}
          panelDims={{width: this.props.width, height: this.props.height, spaceBetweenTrees}}
        />
        <TipClickedPanel
          goAwayCallback={this.clearSelectedTip}
          tip={this.state.selectedTip}
          metadata={this.props.metadata}
        />
        {this.props.showTangle && this.state.tree && this.state.treeToo ? (
          <Tangle
            ref={(r) => {this.tangleRef = r;}}
            width={this.props.width}
            height={this.props.height}
            lookup={this.props.treeToo.tangleTipLookup}
            leftNodes={this.props.tree.nodes}
            rightNodes={this.props.treeToo.nodes}
            colors={this.props.tree.nodeColors}
            cVersion={this.props.tree.nodeColorsVersion}
            vVersion={this.props.tree.visibilityVersion}
            metric={this.props.distanceMeasure}
            spaceBetweenTrees={spaceBetweenTrees}
          />
        ) : null }
        {this.renderTreeDiv({width: widthPerTree, height: this.props.height, d3ref: "d3ref", viewerRef: "Viewer"})}
        {this.props.showTreeToo ?
 : null}
        {this.props.showTreeToo ?
          this.renderTreeDiv({width: widthPerTree, height: this.props.height, d3ref: "d3refToo", viewerRef: "ViewerToo"}) :
          null
        }
        <button
          style={resetTreeButtonStyle}
          onClick={this.redrawTree}
        >
          reset layout
        </button>
      </Card>
    );
  }
}

export default Tree;
<commit_msg>gradient ascent for rank correlation<commit_after>import React from "react";
import { ReactSVGPanZoom } from "react-svg-pan-zoom";
import { updateVisibleTipsAndBranchThicknesses } from "../../actions/tree";
import Card from "../framework/card";
import Legend from "./legend/legend";
import PhyloTree from "./phyloTree/phyloTree";
import HoverInfoPanel from "./infoPanels/hover";
import TipClickedPanel from "./infoPanels/click";
import { changePhyloTreeViaPropsComparison } from "./reactD3Interface/change";
import * as callbacks from "./reactD3Interface/callbacks";
import { resetTreeButtonStyle } from "../../globalStyles";
import { renderTree } from "./reactD3Interface/initialRender";
import Tangle from "./tangle";

const tangle_score = function(nodes1, nodes2, nameToNode){
  let sq_dev = 0, count=0;
  let my1=0, my2=0, sqy1=0,sqy2=0, y12=0;
  for (let i=0;i<nodes2.length; i++){
    let n=nodes2[i];
    if ((!n.children) && nameToNode[n.strain]){
      let y1 = n.yvalue, y2=nameToNode[n.strain].yvalue;
      sq_dev += (y1 - y2)*(y1 - y2);
      count++;
      my1+=y1;
      my2+=y2;
      sqy1+=y1**2;
      sqy2+=y2**2;
      y12 += y1*y2
    }
  }
  my1/=count;
  my2/=count;
  sqy1/=count;
  sqy2/=count;
  y12/=count
  const corr = (y12-my1*my2)/Math.sqrt((sqy1 - my1**2)*(sqy2 - my2**2))
  // console.log("tangle score:", sq_dev/count, count, corr);
  return corr;
}

const postOrderIteration = function(node, callback){
    if (node.children){
        for (var i=0; i<node.children.length; i++){
            postOrderIteration(node.children[i], callback);
        }
    }
    callback(node);
}

const calculateNodeRank = function(nodes){
  let yvalue = nodes[0].fullTipCount;
  const assignNodeOrder = function(node){
    if (!node.children){
      yvalue--;
      node.yvalue = yvalue
      node.maxYvalue = yvalue;
      node.minYvalue = yvalue;
    }else{
      let s=0;
      for (let i=0;i<node.children.length; i++){
        s+=node.children[i].yvalue;
      }
      s/=node.children.length;
      node.yvalue = s;
      node.maxYvalue = node.children[node.children.length-1].yvalue;
      node.minYvalue = node.children[0].yvalue;
    }
  }
  postOrderIteration(nodes[0], assignNodeOrder);
}

const calculateOtherTreeRank = function(nodes, nameToNode){
  nodes.forEach(function(n){n.otherYvalue=0;});
  const assignNodeOrder = function(node){
    if (!node.children){
      if (nameToNode[node.strain]){
        node.otherYvalue += nameToNode[node.strain].yvalue;
      }
    }else{
      let s=0;
      for (let i=0;i<node.children.length; i++){
        if (node.children[i].otherYvalue){
          s += node.children[i].otherYvalue;
        }
      }
      node.otherYvalue = 1.0*s;
    }
  }
  postOrderIteration(nodes[0], assignNodeOrder);
  nodes.forEach(function(n){n.otherYvalue/=n.fullTipCount;});
}

class Tree extends React.Component {
  constructor(props) {
    super(props);
    this.tangleRef = undefined;
    this.Viewer = null;
    this.state = {
      hover: null,
      selectedBranch: null,
      selectedTip: null,
      tree: null,
      treeToo: null
    };
    /* bind callbacks */
    this.clearSelectedTip = callbacks.clearSelectedTip.bind(this);
    this.resetView = callbacks.resetView.bind(this);
    this.onViewerChange = callbacks.onViewerChange.bind(this);
    // this.handleIconClickHOF = callbacks.handleIconClickHOF.bind(this);
    this.redrawTree = () => {
      this.state.tree.clearSVG();
      this.Viewer.fitToViewer();
      renderTree(this, true, this.state.tree, this.props);
      if (this.props.showTreeToo) {
        this.state.treeToo.clearSVG();
        this.ViewerToo.fitToViewer();
        renderTree(this, false, this.state.treeToo, this.props);
      }
      this.setState({hover: null, selectedBranch: null, selectedTip: null});
      this.props.dispatch(updateVisibleTipsAndBranchThicknesses({root: [0, 0]}));
    };
  }
  componentDidMount() {
    if (this.props.tree.loaded) {
      calculateNodeRank(this.props.tree.nodes);
      const tree = new PhyloTree(this.props.tree.nodes, "LEFT");
      const nameToNode = {};
      for (let i=0;i<this.props.tree.nodes.length;i++){
        nameToNode[this.props.tree.nodes[i].strain] = this.props.tree.nodes[i];
      }
      renderTree(this, true, tree, this.props);
      this.Viewer.fitToViewer();
      const newState = {tree};
      let corr=-1, new_corr=-1;
      if (this.props.showTreeToo) {
        calculateOtherTreeRank(this.props.treeToo.nodes, nameToNode);
        calculateNodeRank(this.props.treeToo.nodes);
        corr = tangle_score(this.props.tree.nodes, this.props.treeToo.nodes, nameToNode);
        console.log("Initial tangle rank correlation:",corr);
        for (let i=0;i<this.props.treeToo.nodes.length;i++){
          let n=this.props.treeToo.nodes[i];
          if (n.children){
            // console.log(n.strain, n.children);
            n.children.sort(function(a,b){
              if (nameToNode[b.strain]&&nameToNode[a.strain]){
                return -(a.otherYvalue - b.otherYvalue);
              }else{
                return 0;
              }
            });
          }
        }
        calculateNodeRank(this.props.treeToo.nodes);
        corr = tangle_score(this.props.tree.nodes, this.props.treeToo.nodes, nameToNode);
        console.log("Pre optimized tangle rank correlation:",corr);
        for (let i=0;i<this.props.treeToo.nodes.length;i++){
          let n=this.props.treeToo.nodes[i];
          if (n.children){
            n.children.reverse();
            calculateNodeRank(this.props.treeToo.nodes);
            new_corr = tangle_score(this.props.tree.nodes, this.props.treeToo.nodes, nameToNode)
            if (corr>new_corr){
              n.children.reverse();
              calculateNodeRank(this.props.treeToo.nodes);
            }else{
              corr = new_corr;
            }

          }
        }
        calculateNodeRank(this.props.treeToo.nodes);
        tangle_score(this.props.tree.nodes, this.props.treeToo.nodes, nameToNode);
        const treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
        renderTree(this, false, treeToo, this.props);
        this.ViewerToo.fitToViewer();
        newState.treeToo = treeToo;
        console.log("Optimized tangle rank correlation:",corr);
      }
      this.setState(newState);
    }
  }
  componentDidUpdate(prevProps) {
    let newState;
    let leftTreeUpdated;
    let rightTreeUpdated;
    let _; // eslint-disable-line

    if (this.state.tree) {
      [newState, leftTreeUpdated] = changePhyloTreeViaPropsComparison(true, this.state.tree, this.Viewer, prevProps, this.props);
      if (prevProps.showTreeToo !== this.props.showTreeToo) {
        this.state.tree.change({svgHasChangedDimensions: true});
        if (this.props.showTreeToo) {
          if (this.state.treeToo) { /* remove the old tree */
            this.state.treeToo.clearSVG();
          }
          const treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
          renderTree(this, false, treeToo, this.props);
          this.resetView(); // reset the position of the left tree
          if (this.tangleRef) this.tangleRef.drawLines();
          this.setState({treeToo});
        } else {
          this.setState({treeToo: null});
        }
        return;
      }
    }
    /* tree too */
    if (this.state.treeToo) {
      if (!prevProps.showTreeToo && this.props.showTreeToo) {
        newState.treeToo = new PhyloTree(this.props.treeToo.nodes, "RIGHT");
        renderTree(this, false, newState.treeToo, this.props);
        this.ViewerToo.fitToViewer();
      } else if (!this.props.showTreeToo) {
        newState.treeToo = null;
      } else {
        [_, rightTreeUpdated] = changePhyloTreeViaPropsComparison(false, this.state.treeToo, this.ViewerToo, prevProps, this.props);
      }
    }
    /* we may need to (imperitively) tell the tangle to redraw */
    if (this.tangleRef && (leftTreeUpdated || rightTreeUpdated)) {
      this.tangleRef.drawLines();
    }
    if (newState) this.setState(newState);
  }
  renderTreeDiv({width, height, d3ref, viewerRef}) {
    return (
      <ReactSVGPanZoom
        width={width}
        height={height}
        ref={(Viewer) => {this[viewerRef] = Viewer;}}
        style={{cursor: "default"}}
        tool={"pan"}
        detectWheel={false}
        toolbarPosition={"none"}
        detectAutoPan={false}
        background={"#FFF"}
        miniaturePosition={"none"}
        onDoubleClick={this.resetView}
        onChangeValue={this.onViewerChange}
      >
        <svg style={{pointerEvents: "auto"}}
          width={width}
          height={height}
        >
          <g
            id={"d3TreeElement"}
            width={width}
            height={height}
            style={{cursor: "default"}}
            ref={(c) => {this[d3ref] = c;}}
          />
        </svg>
      </ReactSVGPanZoom>
    );
  }

  render() {
    const spaceBetweenTrees = 100;
    const widthPerTree = this.props.showTreeToo ? (this.props.width - spaceBetweenTrees) / 2 : this.props.width;
    return (
      <Card center title={"Phylogeny"}>
        <Legend width={this.props.width}/>
        <HoverInfoPanel
          mutType={this.props.mutType}
          temporalConfidence={this.props.temporalConfidence.display}
          distanceMeasure={this.props.distanceMeasure}
          hovered={this.state.hovered}
          viewer={this.Viewer}
          colorBy={this.props.colorBy}
          colorByConfidence={this.props.colorByConfidence}
          colorScale={this.props.colorScale}
          panelDims={{width: this.props.width, height: this.props.height, spaceBetweenTrees}}
        />
        <TipClickedPanel
          goAwayCallback={this.clearSelectedTip}
          tip={this.state.selectedTip}
          metadata={this.props.metadata}
        />
        {this.props.showTangle && this.state.tree && this.state.treeToo ? (
          <Tangle
            ref={(r) => {this.tangleRef = r;}}
            width={this.props.width}
            height={this.props.height}
            lookup={this.props.treeToo.tangleTipLookup}
            leftNodes={this.props.tree.nodes}
            rightNodes={this.props.treeToo.nodes}
            colors={this.props.tree.nodeColors}
            cVersion={this.props.tree.nodeColorsVersion}
            vVersion={this.props.tree.visibilityVersion}
            metric={this.props.distanceMeasure}
            spaceBetweenTrees={spaceBetweenTrees}
          />
        ) : null }
        {this.renderTreeDiv({width: widthPerTree, height: this.props.height, d3ref: "d3ref", viewerRef: "Viewer"})}
        {this.props.showTreeToo ?
 : null}
        {this.props.showTreeToo ?
          this.renderTreeDiv({width: widthPerTree, height: this.props.height, d3ref: "d3refToo", viewerRef: "ViewerToo"}) :
          null
        }
        <button
          style={resetTreeButtonStyle}
          onClick={this.redrawTree}
        >
          reset layout
        </button>
      </Card>
    );
  }
}

export default Tree;
<|endoftext|>


<commit_before>var EventEmitter = require('../events/eventEmitter'),
    PluginManager = require('./pluginManager');

module.exports.EventEmitter = {
    Constructor: EventEmitter,
    name: 'emitter',
    filterKeys: 'allMethods'
};

module.exports.PluginManager = {
    name: 'plugins',
    initAfter: true,
    Constructor: PluginManager,
    create: function() {
        var manager = new this.Constructor();
        manager.init({
            instance: this.instance,
            instanceArgs: this.instanceArgs
        });

        return manager;
    },
    filterKeys: function(key) {
        return key === 'destroyPlugins';
    }
};<commit_msg>move plugin manger to seperate file<commit_after>var EventEmitter = require('../events/eventEmitter'),
    PluginManager = require('./pluginManager');

module.exports.EventEmitter = {
    Constructor: EventEmitter,
    name: 'emitter',
    filterKeys: 'allMethods'
};

module.exports.PluginManager = {
    name: 'plugins',
    initAfter: true,
    Constructor: PluginManager,
    create: function() {
        var manager = new this.Constructor();
        manager.init({
            instance: this.instance,
            instanceArgs: this.instanceArgs
        });

        return manager;
    },
    filterKeys: ['destroyPlugins']
};<|endoftext|>


<commit_before>function setAttr(node, name, val) {
    if(name === 'type' && node.tagName === 'INPUT') {
        var value = node.value; // value will be lost in IE if type is changed
        node.setAttribute(name, '' + val);
        node.value = value;
    }
    else {
        node.setAttribute(name, '' + val);
    }
}

function setProp(node, name, val) {
    node[name] = val;
}

function setObjProp(node, name, val) {
    var prop = node[name];
    for(var i in val) {
        prop[i] = val[i] == null? '' : val[i];
    }
}

function setPropWithCheck(node, name, val) {
    if(name === 'value' && node.tagName === 'SELECT') {
        setSelectValue(node, val);
    }
    else {
        node[name] !== val && (node[name] = val);
    }
}

function removeAttr(node, name) {
    node.removeAttribute(name);
}

function removeProp(node, name) {
    if(name === 'value' && node.tagName === 'SELECT') {
        removeSelectValue(node);
    }
    else {
        node[name] = getDefaultPropVal(node.tagName, name);
    }
}

function setSelectValue(node, value) {
    var i = 0,
        children = node.childNodes,
        len = children.length,
        childNode,
        isMultiple = Array.isArray(value);

    while(i < len) {
        childNode = children[i++];
        if(childNode.tagName === 'OPTION') {
            childNode.selected = value != null &&
                (isMultiple? isInArray(value, childNode.value) : childNode.value == value);
        }
        else {
            setSelectValue(childNode, value);
        }
    }
}

function removeSelectValue(node) {
    var i = 0,
        children = node.childNodes,
        len = children.length,
        childNode;

    while(i < len) {
        childNode = children[i++];
        if(childNode.tagName === 'OPTION') {
            childNode.selected = false;
        }
        else {
            setSelectValue(childNode, value);
        }
    }
}

function isInArray(arr, item) {
    var len = arr.length,
        i = 0;

    while(i < len) {
        if(arr[i++] == item) {
            return true;
        }

    }

    return false;
}

var defaultPropVals = {};
function getDefaultPropVal(tag, attrName) {
    var tagAttrs = defaultPropVals[tag] || (defaultPropVals[tag] = {});
    return attrName in tagAttrs?
        tagAttrs[attrName] :
        tagAttrs[attrName] = document.createElement(tag)[attrName];
}

var DEFAULT_ATTR_CFG = {
        set : setAttr,
        remove : removeAttr
    },
    DEFAULT_PROP_CFG = {
        set : setProp,
        remove : removeProp
    },
    attrsCfg = {
        checked : DEFAULT_PROP_CFG,
        controls : DEFAULT_PROP_CFG,
        id : DEFAULT_PROP_CFG,
        loop : DEFAULT_PROP_CFG,
        multiple : DEFAULT_PROP_CFG,
        muted : DEFAULT_PROP_CFG,
        readOnly : DEFAULT_PROP_CFG,
        selected : DEFAULT_PROP_CFG,
        srcDoc : DEFAULT_PROP_CFG,
        style : {
            set : setObjProp,
            remove : removeProp
        },
        value : {
            set : setPropWithCheck,
            remove : removeProp
        }
    };

module.exports = function(attrName) {
    return attrsCfg[attrName] || DEFAULT_ATTR_CFG;
};
<commit_msg>optimize options traversing<commit_after>function setAttr(node, name, val) {
    if(name === 'type' && node.tagName === 'INPUT') {
        var value = node.value; // value will be lost in IE if type is changed
        node.setAttribute(name, '' + val);
        node.value = value;
    }
    else {
        node.setAttribute(name, '' + val);
    }
}

function setProp(node, name, val) {
    node[name] = val;
}

function setObjProp(node, name, val) {
    var prop = node[name];
    for(var i in val) {
        prop[i] = val[i] == null? '' : val[i];
    }
}

function setPropWithCheck(node, name, val) {
    if(name === 'value' && node.tagName === 'SELECT') {
        setSelectValue(node, val);
    }
    else {
        node[name] !== val && (node[name] = val);
    }
}

function removeAttr(node, name) {
    node.removeAttribute(name);
}

function removeProp(node, name) {
    if(name === 'value' && node.tagName === 'SELECT') {
        removeSelectValue(node);
    }
    else {
        node[name] = getDefaultPropVal(node.tagName, name);
    }
}

function setSelectValue(node, value) {
    var isMultiple = Array.isArray(value),
        options = node.options,
        i = 0,
        len = options.length,
        optionNode;

    while(i < len) {
        optionNode = options[i++];
        optionNode.selected = value != null &&
            (isMultiple? isInArray(value, optionNode.value) : optionNode.value == value);
    }
}

function removeSelectValue(node) {
    var options = node.options,
        i = 0,
        len = options.length;

    while(i < len) {
        options[i++].selected = false;
    }
}

function isInArray(arr, item) {
    var len = arr.length,
        i = 0;

    while(i < len) {
        if(arr[i++] == item) {
            return true;
        }

    }

    return false;
}

var defaultPropVals = {};
function getDefaultPropVal(tag, attrName) {
    var tagAttrs = defaultPropVals[tag] || (defaultPropVals[tag] = {});
    return attrName in tagAttrs?
        tagAttrs[attrName] :
        tagAttrs[attrName] = document.createElement(tag)[attrName];
}

var DEFAULT_ATTR_CFG = {
        set : setAttr,
        remove : removeAttr
    },
    DEFAULT_PROP_CFG = {
        set : setProp,
        remove : removeProp
    },
    attrsCfg = {
        checked : DEFAULT_PROP_CFG,
        controls : DEFAULT_PROP_CFG,
        id : DEFAULT_PROP_CFG,
        loop : DEFAULT_PROP_CFG,
        multiple : DEFAULT_PROP_CFG,
        muted : DEFAULT_PROP_CFG,
        readOnly : DEFAULT_PROP_CFG,
        selected : DEFAULT_PROP_CFG,
        srcDoc : DEFAULT_PROP_CFG,
        style : {
            set : setObjProp,
            remove : removeProp
        },
        value : {
            set : setPropWithCheck,
            remove : removeProp
        }
    };

module.exports = function(attrName) {
    return attrsCfg[attrName] || DEFAULT_ATTR_CFG;
};
<|endoftext|>


<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

function createPhysicsFor(iconGrid) {
  return new DefaultPhysics(iconGrid);
}

function DefaultPhysics(iconGrid) {
  this.iconGrid = iconGrid;
  this.moved = false;
  this.touchState = { active: false, startX: 0, startY: 0 };
}

DefaultPhysics.prototype = {
  onTouchStart: function(e) {
    var touchState = this.touchState;
    this.moved = false;
    touchState.active = true;
    touchState.startX = e.pageX;
    touchState.startY = e.pageY;
    touchState.startTime = e.timeStamp;
  },
  onTouchMove: function(e) {
    var iconGrid = this.iconGrid;
    var touchState = this.touchState;
    if (touchState.active) {
      var dx = touchState.startX - e.pageX;
      if (dx !== 0) {
        iconGrid.sceneGraph.setViewportTopLeft(
          iconGrid.currentPage * iconGrid.containerWidth + dx, 0, 100);
        this.moved = true;
      }
    }
  },
  onTouchEnd: function(e) {
    var touchState = this.touchState;
    if (!touchState.active)
      return;
    touchState.active = false;

    var startX = touchState.startX;
    var endX = e.pageX;
    var diffX = endX - startX;
    var dir = (diffX > 0) ? -1 : 1;

    var quick = (e.timeStamp - touchState.startTime < 200);
    var small = Math.abs(diffX) < 10;

    var flick = quick && !small;
    var tap = !this.moved && small;
    var drag = !quick;

    var iconGrid = this.iconGrid;
    var currentPage = iconGrid.currentPage
    if (tap) {
      iconGrid.tap(currentPage * iconGrid.containerWidth + startX,
                   touchState.startY);
    } else if (flick) {
      iconGrid.setPage(currentPage + dir, 200);
    } else {
      if (Math.abs(diffX) < this.containerWidth/2)
        iconGrid.setPage(currentPage, 200);
      else
        iconGrid.setPage(currentPage + dir, 200);
    }
  }
};

function Icon(iconGrid, index) {
  this.iconGrid = iconGrid;
  this.index = index;
  this.label = '';
  this.url = '';
}

Icon.prototype = {
update: function(img, label, url) {
    this.label = label;
    this.url = url;
    var iconGrid = this.iconGrid;
    var iconWidth = iconGrid.iconWidth;
    var iconHeight = iconGrid.iconHeight;
    var border = iconGrid.border;
    var sprite = this.sprite;
    var createSprite = !sprite;
    if (createSprite) {
      var sceneGraph = iconGrid.sceneGraph;
      sprite = new Sprite(iconWidth, iconHeight);
      sprite.icon = this;
      this.sprite = sprite;
    }
    var ctx = sprite.getContext2D();
    ctx.drawImage(img, iconWidth * border, iconHeight * border,
                  iconWidth * (1 - border * 2),
                  iconHeight * (1 - border * 2));
    ctx.font = Math.floor(iconHeight * border * 0.6) + "pt Arial, sans-serif";
    ctx.textAlign = "center";
    ctx.fillStyle = "white";
    ctx.textBaseline = "top";
    ctx.fillText(label, iconWidth/2, iconHeight - iconHeight*border, iconWidth*0.9);
    if (createSprite)
      sceneGraph.add(sprite);
    this.reflow();
  },
  // return the X coordinate of the top left corner of a slot
  slotLeft: function() {
    var iconGrid = this.iconGrid;
    return iconGrid.itemBoxWidth * (this.index % iconGrid.columns);
  },
  // return the Y coordinate of the top left corner of a slot
  slotTop: function() {
    var iconGrid = this.iconGrid;
    var slot = this.index % iconGrid.itemsPerPage;
    return Math.floor(slot / iconGrid.columns) * iconGrid.itemBoxHeight;
  },
  reflow: function(duration) {
    var sprite = this.sprite;
    if (!sprite)
      return;
    var iconGrid = this.iconGrid;
    var index = this.index;
    var itemsPerPage = iconGrid.itemsPerPage;
    var page = Math.floor(index / iconGrid.itemsPerPage);
    sprite.setPosition(page * iconGrid.containerWidth + this.slotLeft(),
                       this.slotTop(),
                       duration);
    sprite.setScale(1, duration);
  }
}

function IconGrid(canvas, background, iconWidth, iconHeight, border) {
  canvas.mozOpaque = true;

  this.iconWidth = iconWidth;
  this.iconHeight = iconHeight;
  this.sceneGraph = new SceneGraph(canvas);
  this.border = border || 0.1;
  this.icons = [];
  this.currentPage = 0;
  this.physics = createPhysicsFor(this);

  // add the background image
//  this.sceneGraph.setBackground('images/background.png');

  // update the layout state
  this.reflow(canvas.width, canvas.height, 0);

  // install event handlers
  document.addEventListener("touchstart", this, true);
  document.addEventListener("mousedown", this, true);
  document.addEventListener("touchmove", this, true);
  document.addEventListener("mousemove", this, true);
  document.addEventListener("touchend", this, true);
  document.addEventListener("mouseup", this, true);
}

IconGrid.prototype = {
  add: function(src, label, url) {
    // Create the icon in the icon grid
    var icons = this.icons;
    var icon = new Icon(this, this.icons.length);
    icon.index = icons.length;
    icons.push(icon);
    // Load the image, sprite will be created when image load is complete
    var img = new Image();
    img.src = src;
    img.label = label;
    img.url = url;
    img.icon = icon;
    img.onload = function() {
      // Update the icon (this will trigger a reflow and a repaint)
      var icon = this.icon;
      icon.update(this, this.label, this.url);
    }
    return icon;
  },
  remove: function(icon) {
    this.icons.splice(icon.index);
    if (icon.sprite)
      sceneGraph.remove(icon.sprite);
  },
  // reflow the icon grid
  reflow: function(width, height, duration) {
    // first recalculate all the layout information
    this.containerWidth = width;
    this.containerHeight = height;
    this.panelWidth = this.containerWidth;
    this.pageIndicatorWidth = this.containerWidth;
    this.pageIndicatorHeight = Math.min(Math.max(this.containerHeight * 0.7, 14), 20);
    this.panelHeight = this.containerHeight - this.pageIndicatorHeight;
    this.columns = Math.floor(this.panelWidth / this.iconWidth);
    this.rows = Math.floor(this.panelHeight / this.iconHeight);
    this.itemsPerPage = this.rows * this.columns;
    this.itemBoxWidth = Math.floor(this.panelWidth / this.columns);
    this.itemBoxHeight = Math.floor(this.panelHeight / this.rows);

    // switch to the right page
    this.setPage(this.currentPage, duration);

    // now reflow all the icons
    var icons = this.icons;
    for (var n = 0; n < icons.length; ++n)
      icons[n].reflow(duration);
  },
  // get last page with an icon
  getLastPage: function() {
    var itemsPerPage = this.itemsPerPage;
    var lastPage = Math.floor((this.icons.length + (itemsPerPage - 1)) / itemsPerPage);
    if (lastPage > 0)
      --lastPage;
    return lastPage;
  },
  // switch to a different page
  setPage: function(page, duration) {
    page = Math.max(0, page);
    page = Math.min(page, this.getLastPage());
    this.sceneGraph.setViewportTopLeft(this.containerWidth * page, 0, duration);
    this.currentPage = page;
  },
  // process a computed tap at the given scene-graph coordinates
  tap: function(x, y) {
    this.sceneGraph.forHit(
      x, y,
      function(sprite) { openApplication(sprite.icon.url); });
  },
  handleEvent: function(e) {
    var physics = this.physics;
    switch (e.type) {
    case 'touchstart':
    case 'mousedown':
      physics.onTouchStart(e.touches ? e.touches[0] : e);
      break;
    case 'touchmove':
    case 'mousemove':
      physics.onTouchMove(e.touches ? e.touches[0] : e);
      break;
    case 'touchend':
    case 'mouseup':
      physics.onTouchEnd(e.touches ? e.touches[0] : e);
      break;
    }
  }
}

function OnLoad() {
  var fruits = [
    { label: 'Phone', src: 'images/Phone.png',
      url: 'dialer/dialer.html' },
    { label: 'Messages', src: 'images/Messages.png',
      url: 'data:text/html,Hello' },
    { label: 'Calendar', src: 'images/Calendar.png',
      url: 'data:text/html,Hello' },
    { label: 'Gallery', src: 'images/Gallery.png',
      url: 'data:text/html,Hello' },
    { label: 'Camera', src: 'images/Camera.png',
      url: 'data:text/html,Hello' },
    { label: 'Maps', src: 'images/Maps.png',
      url: 'data:text/html,Hello' },
    { label: 'YouTube', src: 'images/YouTube.png',
      url: 'data:text/html,Hello' },
    { label: 'Calculator', src: 'images/Calculator.png',
      url: 'data:text/html,Hello' },
    { label: 'Books', src: 'images/Books.png',
      url: 'data:text/html,Hello' },
    { label: 'Browser', src: 'images/Browser.png',
      url: 'data:text/html,Hello' },
    { label: 'Music', src: 'images/Music.png',
      url: 'data:text/html,Hello' }
  ];

  var icons = [];
  for (var n = 0; n < fruits.length; ++n)
    icons.push(fruits[n]);
  for (var n = 0; n < fruits.length; ++n)
    icons.push(fruits[n]);
  for (var n = 0; n < fruits.length; ++n)
    icons.push(fruits[n]);
  for (var n = 0; n < fruits.length; ++n)
    icons.push(fruits[n]);

  var iconGrid = new IconGrid(document.getElementById("homeCanvas"),
                              "images/background.png",
                              120, 120, 0.2);
  for (var n = 0; n < icons.length; ++n)
    iconGrid.add(icons[n].src, icons[n].label, icons[n].url);

  window.setInterval(updateClock, 60000);
  updateClock();

  document.getElementById('statusPadding').innerHTML =
    kUseGL ? '(WebGL)' : '(2D canvas)';
}

// open the application referred to by |url| into a new window, or
// bring its window to front if already open.
function openApplication(url) {
  // TODO
  //var existingWindow = document.querySelector('#windows > ...');

  var newWindow = document.createElement('iframe');
  newWindow.className = 'appWindow';
  newWindow.style.display = 'none';
  // XXX need to decide whether to try to load this during animation
  newWindow.src = url;

  var windows = document.getElementById('windows');
  windows.appendChild(newWindow);

  var loadScreen = document.getElementById('loadAnimationScreen');
  loadScreen.className = 'animateOpening';
  loadScreen.style.display = 'block';

  window.addEventListener(
    'animationend',
    function listener() {
      loadScreen.style.display = 'none';
      newWindow.style.display = 'block';
      window.removeEventListener('animationend', listener, false);
    },
    false);
}

function updateClock() {
  var now = new Date();
  var str = now.getHours();
  str += ':';
  var mins = now.getMinutes();
  if (mins < 10) str += "0";
  str += mins;
  document.getElementById('statusClock').innerHTML = str;
}
<commit_msg>Fix small indentations nits and prevent the homescreen to receive events when there is an application over it<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

function createPhysicsFor(iconGrid) {
  return new DefaultPhysics(iconGrid);
}

function DefaultPhysics(iconGrid) {
  this.iconGrid = iconGrid;
  this.moved = false;
  this.touchState = { active: false, startX: 0, startY: 0 };
}

DefaultPhysics.prototype = {
  onTouchStart: function(e) {
    var touchState = this.touchState;
    this.moved = false;
    touchState.active = true;
    touchState.startX = e.pageX;
    touchState.startY = e.pageY;
    touchState.startTime = e.timeStamp;
  },
  onTouchMove: function(e) {
    var iconGrid = this.iconGrid;
    var touchState = this.touchState;
    if (touchState.active) {
      var dx = touchState.startX - e.pageX;
      if (dx !== 0) {
        iconGrid.sceneGraph.setViewportTopLeft(
          iconGrid.currentPage * iconGrid.containerWidth + dx, 0, 100);
        this.moved = true;
      }
    }
  },
  onTouchEnd: function(e) {
    var touchState = this.touchState;
    if (!touchState.active)
      return;
    touchState.active = false;

    var startX = touchState.startX;
    var endX = e.pageX;
    var diffX = endX - startX;
    var dir = (diffX > 0) ? -1 : 1;

    var quick = (e.timeStamp - touchState.startTime < 200);
    var small = Math.abs(diffX) < 10;

    var flick = quick && !small;
    var tap = !this.moved && small;
    var drag = !quick;

    var iconGrid = this.iconGrid;
    var currentPage = iconGrid.currentPage
    if (tap) {
      iconGrid.tap(currentPage * iconGrid.containerWidth + startX,
                   touchState.startY);
    } else if (flick) {
      iconGrid.setPage(currentPage + dir, 200);
    } else {
      if (Math.abs(diffX) < this.containerWidth/2)
        iconGrid.setPage(currentPage, 200);
      else
        iconGrid.setPage(currentPage + dir, 200);
    }
  }
};

function Icon(iconGrid, index) {
  this.iconGrid = iconGrid;
  this.index = index;
  this.label = '';
  this.url = '';
}

Icon.prototype = {
  update: function(img, label, url) {
    this.label = label;
    this.url = url;
    var iconGrid = this.iconGrid;
    var iconWidth = iconGrid.iconWidth;
    var iconHeight = iconGrid.iconHeight;
    var border = iconGrid.border;
    var sprite = this.sprite;
    var createSprite = !sprite;
    if (createSprite) {
      var sceneGraph = iconGrid.sceneGraph;
      sprite = new Sprite(iconWidth, iconHeight);
      sprite.icon = this;
      this.sprite = sprite;
    }
    var ctx = sprite.getContext2D();
    ctx.drawImage(img, iconWidth * border, iconHeight * border,
                  iconWidth * (1 - border * 2),
                  iconHeight * (1 - border * 2));
    ctx.font = Math.floor(iconHeight * border * 0.6) + "pt Arial, sans-serif";
    ctx.textAlign = "center";
    ctx.fillStyle = "white";
    ctx.textBaseline = "top";
    ctx.fillText(label, iconWidth/2, iconHeight - iconHeight*border, iconWidth*0.9);
    if (createSprite)
      sceneGraph.add(sprite);
    this.reflow();
  },
  // return the X coordinate of the top left corner of a slot
  slotLeft: function() {
    var iconGrid = this.iconGrid;
    return iconGrid.itemBoxWidth * (this.index % iconGrid.columns);
  },
  // return the Y coordinate of the top left corner of a slot
  slotTop: function() {
    var iconGrid = this.iconGrid;
    var slot = this.index % iconGrid.itemsPerPage;
    return Math.floor(slot / iconGrid.columns) * iconGrid.itemBoxHeight;
  },
  reflow: function(duration) {
    var sprite = this.sprite;
    if (!sprite)
      return;
    var iconGrid = this.iconGrid;
    var index = this.index;
    var itemsPerPage = iconGrid.itemsPerPage;
    var page = Math.floor(index / iconGrid.itemsPerPage);
    sprite.setPosition(page * iconGrid.containerWidth + this.slotLeft(),
                       this.slotTop(),
                       duration);
    sprite.setScale(1, duration);
  }
}

function IconGrid(canvas, background, iconWidth, iconHeight, border) {
  canvas.mozOpaque = true;

  this.iconWidth = iconWidth;
  this.iconHeight = iconHeight;
  this.sceneGraph = new SceneGraph(canvas);
  this.border = border || 0.1;
  this.icons = [];
  this.currentPage = 0;
  this.physics = createPhysicsFor(this);

  // add the background image
  // this.sceneGraph.setBackground('images/background.png');

  // update the layout state
  this.reflow(canvas.width, canvas.height, 0);

  // install event handlers
  document.addEventListener("touchstart", this, true);
  document.addEventListener("mousedown", this, true);
  document.addEventListener("touchmove", this, true);
  document.addEventListener("mousemove", this, true);
  document.addEventListener("touchend", this, true);
  document.addEventListener("mouseup", this, true);
}

IconGrid.prototype = {
  add: function(src, label, url) {
    // Create the icon in the icon grid
    var icons = this.icons;
    var icon = new Icon(this, this.icons.length);
    icon.index = icons.length;
    icons.push(icon);
    // Load the image, sprite will be created when image load is complete
    var img = new Image();
    img.src = src;
    img.label = label;
    img.url = url;
    img.icon = icon;
    img.onload = function() {
      // Update the icon (this will trigger a reflow and a repaint)
      var icon = this.icon;
      icon.update(this, this.label, this.url);
    }
    return icon;
  },
  remove: function(icon) {
    this.icons.splice(icon.index);
    if (icon.sprite)
      sceneGraph.remove(icon.sprite);
  },
  // reflow the icon grid
  reflow: function(width, height, duration) {
    // first recalculate all the layout information
    this.containerWidth = width;
    this.containerHeight = height;
    this.panelWidth = this.containerWidth;
    this.pageIndicatorWidth = this.containerWidth;
    this.pageIndicatorHeight = Math.min(Math.max(this.containerHeight * 0.7, 14), 20);
    this.panelHeight = this.containerHeight - this.pageIndicatorHeight;
    this.columns = Math.floor(this.panelWidth / this.iconWidth);
    this.rows = Math.floor(this.panelHeight / this.iconHeight);
    this.itemsPerPage = this.rows * this.columns;
    this.itemBoxWidth = Math.floor(this.panelWidth / this.columns);
    this.itemBoxHeight = Math.floor(this.panelHeight / this.rows);

    // switch to the right page
    this.setPage(this.currentPage, duration);

    // now reflow all the icons
    var icons = this.icons;
    for (var n = 0; n < icons.length; ++n)
      icons[n].reflow(duration);
  },
  // get last page with an icon
  getLastPage: function() {
    var itemsPerPage = this.itemsPerPage;
    var lastPage = Math.floor((this.icons.length + (itemsPerPage - 1)) / itemsPerPage);
    if (lastPage > 0)
      --lastPage;
    return lastPage;
  },
  // switch to a different page
  setPage: function(page, duration) {
    page = Math.max(0, page);
    page = Math.min(page, this.getLastPage());
    this.sceneGraph.setViewportTopLeft(this.containerWidth * page, 0, duration);
    this.currentPage = page;
  },
  // process a computed tap at the given scene-graph coordinates
  tap: function(x, y) {
    this.sceneGraph.forHit(
      x, y,
      function(sprite) { openApplication(sprite.icon.url); });
  },
  handleEvent: function(e) {
    // If the focus is over another window, ignore events over the homescreen
    if (document.getElementById("windows").childElementCount > 1)
      return;

    var physics = this.physics;
    switch (e.type) {
    case 'touchstart':
    case 'mousedown':
      physics.onTouchStart(e.touches ? e.touches[0] : e);
      break;
    case 'touchmove':
    case 'mousemove':
      physics.onTouchMove(e.touches ? e.touches[0] : e);
      break;
    case 'touchend':
    case 'mouseup':
      physics.onTouchEnd(e.touches ? e.touches[0] : e);
      break;
    }
  }
}

function OnLoad() {
  var fruits = [
    { label: 'Phone', src: 'images/Phone.png',
      url: 'dialer/dialer.html' },
    { label: 'Messages', src: 'images/Messages.png',
      url: 'data:text/html,Hello' },
    { label: 'Calendar', src: 'images/Calendar.png',
      url: 'data:text/html,Hello' },
    { label: 'Gallery', src: 'images/Gallery.png',
      url: 'data:text/html,Hello' },
    { label: 'Camera', src: 'images/Camera.png',
      url: 'data:text/html,Hello' },
    { label: 'Maps', src: 'images/Maps.png',
      url: 'data:text/html,Hello' },
    { label: 'YouTube', src: 'images/YouTube.png',
      url: 'data:text/html,Hello' },
    { label: 'Calculator', src: 'images/Calculator.png',
      url: 'data:text/html,Hello' },
    { label: 'Books', src: 'images/Books.png',
      url: 'data:text/html,Hello' },
    { label: 'Browser', src: 'images/Browser.png',
      url: 'data:text/html,Hello' },
    { label: 'Music', src: 'images/Music.png',
      url: 'data:text/html,Hello' }
  ];

  var icons = [];
  for (var n = 0; n < fruits.length; ++n)
    icons.push(fruits[n]);

  var iconGrid = new IconGrid(document.getElementById("homeCanvas"),
                              "images/background.png",
                              120, 120, 0.2);
  for (var n = 0; n < icons.length; ++n)
    iconGrid.add(icons[n].src, icons[n].label, icons[n].url);

  window.setInterval(updateClock, 60000);
  updateClock();

  document.getElementById('statusPadding').innerHTML =
    kUseGL ? '(WebGL)' : '(2D canvas)';
}

// open the application referred to by |url| into a new window, or
// bring its window to front if already open.
function openApplication(url) {
  // TODO
  //var existingWindow = document.querySelector('#windows > ...');

  var newWindow = document.createElement('iframe');
  newWindow.className = 'appWindow';
  newWindow.style.display = 'none';
  // XXX need to decide whether to try to load this during animation
  newWindow.src = url;

  var windows = document.getElementById('windows');
  windows.appendChild(newWindow);

  var loadScreen = document.getElementById('loadAnimationScreen');
  loadScreen.className = 'animateOpening';
  loadScreen.style.display = 'block';

  window.addEventListener(
    'animationend',
    function listener() {
      loadScreen.className = '';
      loadScreen.style.display = 'none';
      newWindow.style.display = 'block';
      window.removeEventListener('animationend', listener, false);
    },
    false);
}

function updateClock() {
  var now = new Date();
  var str = now.getHours();
  str += ':';
  var mins = now.getMinutes();
  if (mins < 10)
    str += "0";
  str += mins;
  document.getElementById('statusClock').innerHTML = str;
}
<|endoftext|>


<commit_before>/**
 *
 * Wait for an element (selected by css selector) for the provided amount of
 * milliseconds to be (in)visible. If multiple elements get queryied by given
 * selector, it returns true (or false if reverse flag is set) if at least one
 * element is visible.
 *
 * This function checks for visibility using window.getComputedStyle. An
 * element will be considered invisible if its visibility is 'none', its
 * display is 'hidden', its opacity is 0 or its x/y coordinates are not
 * within the viewport.
 *
 * @param {String}   selector element to wait for
 * @param {Number=}  ms       time in ms (default: 500)
 * @param {Boolean=} reverse  if true it waits for the opposite (default: false)
 *
 * @uses protocol/selectorExecuteAsync, protocol/timeoutsAsyncScript
 * @type utility
 *
 */

module.exports = function waitForVisible(selector, ms, reverse) {

    /*!
     * ensure that ms is set properly
     */
    if (typeof ms !== 'number') {
        ms = this.options.waitforTimeout;
    }

    if (typeof reverse !== 'boolean') {
        reverse = false;
    }

    return this.waitUntil(function() {
        return this.isVisible(selector).then(function(isVisible) {

            if(Array.isArray(isVisible)) {
                var result = reverse;
                for(var i = 0; i < isVisible.length; ++i) {
                    if(!reverse) {
                        result = result || isVisible[i];
                    } else {
                        result = result && isVisible[i];
                    }
                }

                return result !== reverse;
            }

            return isVisible !== reverse;
        });
    }, ms).catch(function() {
        throw new Error('element (' + selector + ') still ' + (reverse ? '' : 'not') + ' visible after ' + ms + 'ms');
    });

};
<commit_msg>waitForVisible bugfix for nonexisting element<commit_after>/**
 *
 * Wait for an element (selected by css selector) for the provided amount of
 * milliseconds to be (in)visible. If multiple elements get queryied by given
 * selector, it returns true (or false if reverse flag is set) if at least one
 * element is visible.
 *
 * This function checks for visibility using window.getComputedStyle. An
 * element will be considered invisible if its visibility is 'none', its
 * display is 'hidden', its opacity is 0 or its x/y coordinates are not
 * within the viewport.
 *
 * @param {String}   selector element to wait for
 * @param {Number=}  ms       time in ms (default: 500)
 * @param {Boolean=} reverse  if true it waits for the opposite (default: false)
 *
 * @uses protocol/selectorExecuteAsync, protocol/timeoutsAsyncScript
 * @type utility
 *
 */

var ErrorHandler = require('../utils/ErrorHandler.js');

module.exports = function waitForVisible(selector, ms, reverse) {

    /*!
     * ensure that ms is set properly
     */
    if (typeof ms !== 'number') {
        ms = this.options.waitforTimeout;
    }

    if (typeof reverse !== 'boolean') {
        reverse = false;
    }

    var start = Date.now();

    return this.waitUntil(function() {
        if (Date.now() > start + ms) {
            // throw NoSuchElement error if no element was found before timeout
            throw new ErrorHandler(7);
        }
        return this.isVisible(selector).then(function(isVisible) {

            if(Array.isArray(isVisible)) {
                var result = reverse;
                for(var i = 0; i < isVisible.length; ++i) {
                    if(!reverse) {
                        result = result || isVisible[i];
                    } else {
                        result = result && isVisible[i];
                    }
                }

                return result !== reverse;
            }

            return isVisible !== reverse;
        });
    }, ms).catch(function() {
        throw new Error('element (' + selector + ') still ' + (reverse ? '' : 'not') + ' visible after ' + ms + 'ms');
    });

};
<|endoftext|>