<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/*
 * A bucket that can be used to store spherical objects.  Manages the addition
 * and removal of the spheres, and stacks them as the are added, and manages
 * the stack as spheres are removed.
 *
 * This expects the spheres to have certain properties, please inspect the
 * code to understand the 'contract' between the bucket and the spheres.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // Includes
  var Vector2 = require( 'DOT/Vector2' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Bucket = require( 'PHETCOMMON/model/Bucket' );

  function SphereBucket( options ) {
    Bucket.call( this, options );
    this._sphereRadius = options.sphereRadius || 10;
    this._usableWidthProportion = options.usableWidthProportion || 1.0;
    this._verticalParticleOffset = -this._sphereRadius * 0.4; // Empirically determined, for positioning particles inside the bucket.
    this._particles = [];
  }

  // Inherit from base type.
  inherit( Bucket, SphereBucket );

  SphereBucket.prototype.addParticleFirstOpen = function( particle, animate ) {
    particle.destination = this._getFirstOpenLocation();
    if ( !animate ) {
      particle.position = particle.destination;
    }
    this._particles.push( particle );
    var thisBucket = this;
    particle.userControlledProperty.once( function( userControlled ) {
      if ( userControlled ) {
        thisBucket.removeParticle( particle );
      }
    } );
  };

  SphereBucket.prototype.addParticleNearestOpen = function( particle, animate ) {
    particle.destination = this.getNearestOpenLocation( particle.destination );
    if ( !animate ) {
      particle.position = particle.destination;
    }
    this._particles.push( particle );
    var thisBucket = this;
    particle.userControlledProperty.once( function( userControlled ) {
      if ( userControlled ) {
        thisBucket.removeParticle( particle );
      }
    } );
  };

  SphereBucket.prototype.removeParticle = function( particle ) {
    if ( this._particles.indexOf( particle ) === -1 ) {
      console.log( 'Error: Attempt to remove particle not contained in bucket, ignoring.' );
      return;
    }
    this._particles = _.without( this._particles, particle );
    this.relayoutBucketParticles();
  };

  SphereBucket.prototype.containsParticle = function( particle ) {
    return this._particles.indexOf( particle ) !== -1;
  };

  SphereBucket.prototype.extractClosestParticle = function( location ) {
    var closestParticle = null;
    this._particles.forEach( function( particle ) {
      if ( closestParticle === null || closestParticle.position.distance( location ) > particle.position.distance( location ) ) {
        closestParticle = particle;
      }
    } );
    if ( closestParticle !== null ) {
      // The particle is removed by setting 'userControlled' to true.  This
      // relies on the listener that was added when the particle was placed
      // into the bucket.
      closestParticle.userControlled = true;
    }
    return closestParticle;
  };

  SphereBucket.prototype._isPositionOpen = function( position ) {
    var positionOpen = true;
    for ( var i = 0; i < this._particles.length; i++ ) {
      var particle = this._particles[ i ];
      if ( particle.destination.equals( position ) ) {
        positionOpen = false;
        break;
      }
    }
    return positionOpen;
  };

  SphereBucket.prototype._getFirstOpenLocation = function() {
    var openLocation = Vector2.ZERO;
    var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
    var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
    var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );
    var row = 0;
    var positionInLayer = 0;
    var found = false;
    while ( !found ) {
      var testLocation = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
        this._getYPositionForLayer( row ) );
      if ( this._isPositionOpen( testLocation ) ) {
        // We found a location that is open.
        openLocation = testLocation;
        found = true;
        continue;
      }
      else {
        positionInLayer++;
        if ( positionInLayer >= numParticlesInLayer ) {
          // Move to the next layer.
          row++;
          positionInLayer = 0;
          numParticlesInLayer--;
          offsetFromBucketEdge += this._sphereRadius;
          if ( numParticlesInLayer === 0 ) {
            // This algorithm doesn't handle the situation where
            // more particles are added than can be stacked into
            // a pyramid of the needed size, but so far it hasn't
            // needed to.  If this requirement changes, the
            // algorithm will need to change too.
            numParticlesInLayer = 1;
            offsetFromBucketEdge -= this._sphereRadius;
          }
        }
      }
    }
    return openLocation;
  };

  SphereBucket.prototype._getLayerForYPosition = function( yPosition ) {
    return Math.abs( Math.round( ( yPosition - ( this.position.y + this._verticalParticleOffset ) ) / ( this._sphereRadius * 2 * 0.866 ) ) );
  };

  /*
   * Get the nearest open location to the provided current location.  This
   * is used for particle stacking.
   *
   * @param location
   * @return
   */
  SphereBucket.prototype.getNearestOpenLocation = function( position ) {
    // Determine the highest occupied layer.  The bottom layer is 0.
    var highestOccupiedLayer = 0;
    var self = this;
    _.each( this._particles, function( particle ) {
      var layer = self._getLayerForYPosition( particle.destination.y );
      if ( layer > highestOccupiedLayer ) {
        highestOccupiedLayer = layer;
      }
    } );

    // Make a list of all open locations in the occupied layers.
    var openLocations = [];
    var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
    var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
    var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );

    // Loop, searching for open positions in the particle stack.
    for ( var layer = 0; layer <= highestOccupiedLayer + 1; layer++ ) {

      // Add all open locations in the current layer.
      for ( var positionInLayer = 0; positionInLayer < numParticlesInLayer; positionInLayer++ ) {
        var testPosition = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
          this._getYPositionForLayer( layer ) );
        if ( this._isPositionOpen( testPosition ) ) {

          // We found a location that is unoccupied.
          if ( layer === 0 || this.countSupportingParticles( testPosition ) === 2 ) {
            // This is a valid open location.
            openLocations.push( testPosition );
          }
        }
      }

      // Adjust variables for the next layer.
      numParticlesInLayer--;
      offsetFromBucketEdge += this._sphereRadius;
      if ( numParticlesInLayer === 0 ) {
        // If the stacking pyramid is full, meaning that there are
        // no locations that are open within it, this algorithm
        // classifies the locations directly above the top of the
        // pyramid as being open.  This would result in a stack
        // of particles with a pyramid base.  So far, this hasn't
        // been a problem, but this limitation may limit
        // reusability of this algorithm.
        numParticlesInLayer = 1;
        offsetFromBucketEdge -= this._sphereRadius;
      }
    }

    // Find the closest open location to the provided current location.
    // Only the X-component is used for this determination, because if
    // the Y-component is used the particles often appear to fall sideways
    // when released above the bucket, which just looks weird.
    var closestOpenLocation = openLocations[0] || Vector2.ZERO;

    _.each( openLocations, function( location ) {
      if ( location.distance( position ) < closestOpenLocation.distance( position ) ) {
        // This location is closer.
        closestOpenLocation = location;
      }
    } );
    return closestOpenLocation;
  };

  SphereBucket.prototype._getYPositionForLayer = function( layer ) {
    return this.position.y + this._verticalParticleOffset + layer * this._sphereRadius * 2 * 0.866;
  };

  /*
   * Determine whether a particle is 'dangling', i.e. hanging above an open
   * space in the stack of particles.  Dangling particles should fall.
   */
  SphereBucket.prototype._isDangling = function( particle ) {
    var onBottomRow = particle.destination.y === this.position.y + this._verticalParticleOffset;
    return !onBottomRow && this.countSupportingParticles( particle.destination ) < 2;
  };

  SphereBucket.prototype.countSupportingParticles = function( position ) {
    var count = 0;
    for ( var i = 0; i < this._particles.length; i++ ) {
      var p = this._particles[i];
      if ( p.destination.y < position.y && // Must be in a lower layer
           p.destination.distance( position ) < this._sphereRadius * 3 ) {
        // Must be a supporting particle.
        count++;
      }
    }
    return count;
  };

  SphereBucket.prototype.relayoutBucketParticles = function() {
    var particleMoved;
    do {
      for ( var i = 0; i < this._particles.length; i++ ) {
        particleMoved = false;
        var particle = this._particles[i];
        if ( this._isDangling( particle ) ) {
          particle.destination = this.getNearestOpenLocation( particle.destination );
          particleMoved = true;
          break;
        }
      }
    } while ( particleMoved );
  };

  return SphereBucket;
} );
<commit_msg>Minor cleanup.<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/*
 * A bucket that can be used to store spherical objects.  Manages the addition
 * and removal of the spheres, and stacks them as the are added, and manages
 * the stack as spheres are removed.
 *
 * This expects the spheres to have certain properties, please inspect the
 * code to understand the 'contract' between the bucket and the spheres.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // Includes
  var Vector2 = require( 'DOT/Vector2' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Bucket = require( 'PHETCOMMON/model/Bucket' );

  function SphereBucket( options ) {
    Bucket.call( this, options );
    this._sphereRadius = options.sphereRadius || 10;
    this._usableWidthProportion = options.usableWidthProportion || 1.0;
    this._verticalParticleOffset = -this._sphereRadius * 0.4; // Empirically determined, for positioning particles inside the bucket.
    this._particles = [];
  }

  // Inherit from base type.
  inherit( Bucket, SphereBucket );

  SphereBucket.prototype.addParticleFirstOpen = function( particle, animate ) {
    particle.destination = this._getFirstOpenLocation();
    if ( !animate ) {
      particle.position = particle.destination;
    }
    this._particles.push( particle );
    var thisBucket = this;
    particle.userControlledProperty.once( function( userControlled ) {
      if ( userControlled ) {
        thisBucket.removeParticle( particle );
      }
    } );
  };

  SphereBucket.prototype.addParticleNearestOpen = function( particle, animate ) {
    particle.destination = this.getNearestOpenLocation( particle.destination );
    if ( !animate ) {
      particle.position = particle.destination;
    }
    this._particles.push( particle );
    var thisBucket = this;
    particle.userControlledProperty.once( function( userControlled ) {
      if ( userControlled ) {
        thisBucket.removeParticle( particle );
      }
    } );
  };

  SphereBucket.prototype.removeParticle = function( particle ) {
    if ( this._particles.indexOf( particle ) === -1 ) {
      console.log( 'Error: Attempt to remove particle not contained in bucket, ignoring.' );
      return;
    }
    this._particles = _.without( this._particles, particle );
    this.relayoutBucketParticles();
  };

  SphereBucket.prototype.containsParticle = function( particle ) {
    return this._particles.indexOf( particle ) !== -1;
  };

  SphereBucket.prototype.extractClosestParticle = function( location ) {
    var closestParticle = null;
    this._particles.forEach( function( particle ) {
      if ( closestParticle === null || closestParticle.position.distance( location ) > particle.position.distance( location ) ) {
        closestParticle = particle;
      }
    } );
    if ( closestParticle !== null ) {
      // The particle is removed by setting 'userControlled' to true.  This
      // relies on the listener that was added when the particle was placed
      // into the bucket.
      closestParticle.userControlled = true;
    }
    return closestParticle;
  };

  SphereBucket.prototype._isPositionOpen = function( position ) {
    var positionOpen = true;
    for ( var i = 0; i < this._particles.length; i++ ) {
      var particle = this._particles[ i ];
      if ( particle.destination.equals( position ) ) {
        positionOpen = false;
        break;
      }
    }
    return positionOpen;
  };

  SphereBucket.prototype._getFirstOpenLocation = function() {
    var openLocation = Vector2.ZERO;
    var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
    var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
    var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );
    var row = 0;
    var positionInLayer = 0;
    var found = false;
    while ( !found ) {
      var testLocation = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
        this._getYPositionForLayer( row ) );
      if ( this._isPositionOpen( testLocation ) ) {
        // We found a location that is open.
        openLocation = testLocation;
        found = true;
        continue;
      }
      else {
        positionInLayer++;
        if ( positionInLayer >= numParticlesInLayer ) {
          // Move to the next layer.
          row++;
          positionInLayer = 0;
          numParticlesInLayer--;
          offsetFromBucketEdge += this._sphereRadius;
          if ( numParticlesInLayer === 0 ) {
            // This algorithm doesn't handle the situation where
            // more particles are added than can be stacked into
            // a pyramid of the needed size, but so far it hasn't
            // needed to.  If this requirement changes, the
            // algorithm will need to change too.
            numParticlesInLayer = 1;
            offsetFromBucketEdge -= this._sphereRadius;
          }
        }
      }
    }
    return openLocation;
  };

  SphereBucket.prototype._getLayerForYPosition = function( yPosition ) {
    return Math.abs( Math.round( ( yPosition - ( this.position.y + this._verticalParticleOffset ) ) / ( this._sphereRadius * 2 * 0.866 ) ) );
  };

  /*
   * Get the nearest open location to the provided current location.  This
   * is used for particle stacking.
   *
   * @param location
   * @return
   */
  SphereBucket.prototype.getNearestOpenLocation = function( position ) {
    // Determine the highest occupied layer.  The bottom layer is 0.
    var highestOccupiedLayer = 0;
    var self = this;
    _.each( this._particles, function( particle ) {
      var layer = self._getLayerForYPosition( particle.destination.y );
      if ( layer > highestOccupiedLayer ) {
        highestOccupiedLayer = layer;
      }
    } );

    // Make a list of all open locations in the occupied layers.
    var openLocations = [];
    var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
    var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
    var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );

    // Loop, searching for open positions in the particle stack.
    for ( var layer = 0; layer <= highestOccupiedLayer + 1; layer++ ) {

      // Add all open locations in the current layer.
      for ( var positionInLayer = 0; positionInLayer < numParticlesInLayer; positionInLayer++ ) {
        var testPosition = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
          this._getYPositionForLayer( layer ) );
        if ( this._isPositionOpen( testPosition ) ) {

          // We found a location that is unoccupied.
          if ( layer === 0 || this.countSupportingParticles( testPosition ) === 2 ) {
            // This is a valid open location.
            openLocations.push( testPosition );
          }
        }
      }

      // Adjust variables for the next layer.
      numParticlesInLayer--;
      offsetFromBucketEdge += this._sphereRadius;
      if ( numParticlesInLayer === 0 ) {
        // If the stacking pyramid is full, meaning that there are
        // no locations that are open within it, this algorithm
        // classifies the locations directly above the top of the
        // pyramid as being open.  This would result in a stack
        // of particles with a pyramid base.  So far, this hasn't
        // been a problem, but this limitation may limit
        // reusability of this algorithm.
        numParticlesInLayer = 1;
        offsetFromBucketEdge -= this._sphereRadius;
      }
    }

    // Find the closest open location to the provided current location.
    // Only the X-component is used for this determination, because if
    // the Y-component is used the particles often appear to fall sideways
    // when released above the bucket, which just looks weird.
    var closestOpenLocation = openLocations[0] || Vector2.ZERO;

    _.each( openLocations, function( location ) {
      if ( location.distance( position ) < closestOpenLocation.distance( position ) ) {
        // This location is closer.
        closestOpenLocation = location;
      }
    } );
    return closestOpenLocation;
  };

  SphereBucket.prototype._getYPositionForLayer = function( layer ) {
    return this.position.y + this._verticalParticleOffset + layer * this._sphereRadius * 2 * 0.866;
  };

  /*
   * Determine whether a particle is 'dangling', i.e. hanging above an open
   * space in the stack of particles.  Dangling particles should fall.
   */
  SphereBucket.prototype._isDangling = function( particle ) {
    var onBottomRow = particle.destination.y === this.position.y + this._verticalParticleOffset;
    return !onBottomRow && this.countSupportingParticles( particle.destination ) < 2;
  };

  SphereBucket.prototype.countSupportingParticles = function( position ) {
    var count = 0;
    for ( var i = 0; i < this._particles.length; i++ ) {
      var p = this._particles[i];
      if ( p.destination.y < position.y && // Must be in a lower layer
           p.destination.distance( position ) < this._sphereRadius * 3 ) {
        // Must be a supporting particle.
        count++;
      }
    }
    return count;
  };

  SphereBucket.prototype.relayoutBucketParticles = function() {
    var particleMoved;
    do {
      for ( var i = 0; i < this._particles.length; i++ ) {
        particleMoved = false;
        var particle = this._particles[i];
        if ( this._isDangling( particle ) ) {
          particle.destination = this.getNearestOpenLocation( particle.destination );
          particleMoved = true;
          break;
        }
      }
    } while ( particleMoved );
  };

  return SphereBucket;
} );
<|endoftext|>


<commit_before>/**
 * Enrich a 'job' channel event with some blueocean specific
 * data useful for the event processing.
 *
 * @param event The event object.
 * @param activePipelineName The pipeline name that's active on
 * the blueocean page, if any.
 * @returns The new enriched event instance.
 */
exports.enrichJobEvent = function (event, activePipelineName) {
    const eventCopy = Object.assign({}, event);

    // For blueocean, we split apart the Job name and URL to get the
    // parts needed for looking up the correct pipeline, branch
    // and run etc.
    // TODO: what about nested folders ?
    const jobURLTokens = event.jenkins_object_url.split('/');
    const jobNameTokens = event.job_name.split('/');
    if (jobURLTokens[jobURLTokens.length - 1] === '') {
        // last token can be an empty string if the url has a trailing slash
        jobURLTokens.pop();
    }
    if (!isNaN(jobURLTokens[jobURLTokens.length - 1])) {
        // last/next-last token is a number (a build/run number)
        jobURLTokens.pop();
    }
    if (jobURLTokens.length > 3
        && jobURLTokens[jobURLTokens.length - 2] === 'branch') {
        // So it's a multibranch. The URL looks something like
        // "job/CloudBeers/job/PR-demo/branch/quicker/".
        // But we extract the job and branch name from event.job_name.
        eventCopy.blueocean_branch_name = jobNameTokens.pop();
        eventCopy.blueocean_is_multi_branch = true;
        eventCopy.blueocean_job_name = jobNameTokens.pop();
    } else {
        // It's not multibranch ... 1st token is the pipeline (job) name.
        // But we extract the job name from event.job_name.
        eventCopy.blueocean_job_name = jobNameTokens.pop();
        eventCopy.blueocean_is_multi_branch = false;
    }

    debugger;

    // Is this even associated with the currently active pipeline job?
    eventCopy.blueocean_is_for_current_job =
        (eventCopy.blueocean_job_name === activePipelineName);

    return eventCopy;
};
<commit_msg>Removed debugger statement<commit_after>/**
 * Enrich a 'job' channel event with some blueocean specific
 * data useful for the event processing.
 *
 * @param event The event object.
 * @param activePipelineName The pipeline name that's active on
 * the blueocean page, if any.
 * @returns The new enriched event instance.
 */
exports.enrichJobEvent = function (event, activePipelineName) {
    const eventCopy = Object.assign({}, event);

    // For blueocean, we split apart the Job name and URL to get the
    // parts needed for looking up the correct pipeline, branch
    // and run etc.
    // TODO: what about nested folders ?
    const jobURLTokens = event.jenkins_object_url.split('/');
    const jobNameTokens = event.job_name.split('/');
    if (jobURLTokens[jobURLTokens.length - 1] === '') {
        // last token can be an empty string if the url has a trailing slash
        jobURLTokens.pop();
    }
    if (!isNaN(jobURLTokens[jobURLTokens.length - 1])) {
        // last/next-last token is a number (a build/run number)
        jobURLTokens.pop();
    }
    if (jobURLTokens.length > 3
        && jobURLTokens[jobURLTokens.length - 2] === 'branch') {
        // So it's a multibranch. The URL looks something like
        // "job/CloudBeers/job/PR-demo/branch/quicker/".
        // But we extract the job and branch name from event.job_name.
        eventCopy.blueocean_branch_name = jobNameTokens.pop();
        eventCopy.blueocean_is_multi_branch = true;
        eventCopy.blueocean_job_name = jobNameTokens.pop();
    } else {
        // It's not multibranch ... 1st token is the pipeline (job) name.
        // But we extract the job name from event.job_name.
        eventCopy.blueocean_job_name = jobNameTokens.pop();
        eventCopy.blueocean_is_multi_branch = false;
    }

    // Is this even associated with the currently active pipeline job?
    eventCopy.blueocean_is_for_current_job =
        (eventCopy.blueocean_job_name === activePipelineName);

    return eventCopy;
};
<|endoftext|>


<commit_before>define(['jquery', 'plugins/typeahead'], function($) {

    !function($) {

        "use strict";

        var Typeselect = function(element, datasets, options) {
            if (typeof options === "undefined")
                options = {};

            this.options = $.extend({}, $.fn.typeselect.defaults, options);

            this.selectedDatums = {};
            this.selectedItems = {};
            this.datasetsByName = {};

            var createFetch = function(name, valueKey, fetch) {
                return $.proxy(function(parsedResponse){
                    var datums = fetch ? fetch(parsedResponse) : JSON.parse(parsedResponse);
                    var filtered = $.map(datums, function(index, datum){
                         if (this.selectedDatums[datum[valueKey]]) return null;
                         else return datum;
                    });
                }, this);
            };

            // Support multiple targets based on dataset
            if (!$.isArray(datasets)) datasets = [datasets];

            // Setup stores for selected item targets
            this.$targetsMap = {};
            if (this.options.target)
                this.$defaultTarget = $(this.options.target);

            // Save datasets off for our use later
            this.dataset = datasets;

            // Find all targets for each dataset and modify
            // modify filter attributes so we can remove
            // selected items from future suggestions
            $.each(datasets, $.proxy(function(index, dataset) {
                var valueKey = dataset.valueKey || 'value';
                if (dataset.target) this.$targetsMap[dataset.name] = $(dataset.target);
                if (typeof dataset.remote === 'string' || dataset.remote instanceof String)
                    dataset.remote = {url: dataset.remote};
                if (dataset.remote)
                    dateset.remote.fetch = createFetch(dataset.name, valueKey, dataset.remote.fetch);
                this.selectedDatums[dataset.name] = {};
                this.selectedItems[dataset.name] = {};
                this.datasetsByName[dataset.name] = dataset;
            }, this));

            // Initialize with twitter (not bootstrap) typeahead
            this.$element = $(element).typeahead(datasets);

            this.$element.on('typeahead:selected', $.proxy(function(event, datum, dataset_name){
                 this.add(datum, dataset_name);
                 // Clear out the textbox
                 this.$element.val('');
            }, this));

            // Populate pre-selected values
            var preselected = this.options.selected;
            for (var i = 0; i < preselected.length; i++) {
                if ($.isArray(preselected[i]))
                    this.add.apply(preselected[i]);
                else
                    this.add(preselected[i]);
            }

            this.listen();
        };

        Typeselect.prototype = {

            constructor: Typeselect,

            listen: function() {
                var targets = [];
                $.each(this.$targetsMap, $.proxy(function(name, $target){
                    if ($.inArray(targets, $target)) return true;
                    $target.on('click', '.close', $.proxy(this.click, this));
                    targets.append($target);
                }, this));

                if (this.$defaultTarget && !$.inArray(targets, this.$defaultTarget))
                    $defautlTarget.on('click', '.close', $.proxy(this.click, this));
            },

            add: function(value, dataset_name) {
                // dataset_name parameter is optional
                // Use first supplied dataset by default
                if (typeof dataset_name === "undefined")
                    dataset_name = this.options.dataset || this.datasets[0].name;

                var template, item, $target;
                var dataset = this.datasetsByName[dataset_name];
                var valueKey = data.valueKey;
                // Do not add redundant values
                if (this.selectedDatums[dataset_name][valueKey]) return;
                this.selectedDatums[dataset_name][valueKey] = value;

                // Render
                if (dataset.selectedTemplate){
                    if (!$.isFunction(dataset.selectedTemplate))
                        template = dataset.engine.compile(dataset.selectedTemplate);
                    else
                        template = dataset.selectedTemplate;
                    item = $(template.render(value))
                        .attr('data-value', value[valueKey])
                        .attr('data-dataset', dataset_name);
                } else {
                    // default list item with remove icon
                    item = $(this.options.selectedItem)
                        .text(value[valueKey])
                        .attr('data-value', value[valueKey])
                        .attr('data-dataset', dataset_name)
                        .append('×');
                }

                this.selectedItems[dataset_name][valueKey] = item;

                // Add to the target container
                if ($target = this.$targetsMap[dataset_name]){
                    $target.append(item);
                } else {
                    // Use default target
                    this.$defaultTarget.append(item);
                }
            },

            remove: function(value, dataset_name) {
                // dataset_name parameter is optional
                // Use first supplied dataset by default
                if (typeof dataset_name === "undefined")
                    dataset_name = this.options.dataset || this.datasets[0].name;

                var valueKey = this.datasetsByName[dataset_name],
                    item;

                // Remove from the selected cache
                if (this.selectedDatums[dataset-name][valueKey])
                    delete this.selectedDatums[dataset-name][valueKey];

                // Remove element from DOM element cache
                if (item = this.selectedItems[dataset-name][valueKey]){
                   delete this.selectedItem[dataset-name][valueKey];
                   item.remove();
                }
            },

            click: function(event) {
                event.preventDefault();
                var $parent = $(event.target).parent();
                this.remove($parent.attr('data-value'), $parent.attr('data-dataset'));
            },

            selected: function(groupByDataset){
                if (groupByDataset)
                    return this.selectedDatums;
                // Flatten
                return $.map(this.selectedDatums, function(key, dataset){
                    return $.map(dataset, function(key, datum){
                        return datum;
                    });
                });
            }

        };

        $.fn.typeselect = function(option, defaults) {
            return this.each(function() {
                var $this = $(this),
                   data = $this.data('typeselect'),
                   datasets = typeof option == 'object' && option;
                if (!data) $this.data('typeselect', (data = new Typeselect(this, datasets, defaults)));
                if (typeof option == 'string') data[option]();
            });
        };

        $.fn.typeselect.defaults = {
            selected: [],
            selectedItem: '

'
        };

        $.fn.typeselect.Constructor = Typeselect;

        /* TYPESELECT DATA-API
         * =================== */
        $(document).on('focus.typeselect.data-api', '[data-provide="typeselect"]', function(e) {
            var $this = $(this);
            if ($this.data('typeselect')) return;
            e.preventDefault();
            $this.typeselect($this.data());
        });

    }($);

});
<commit_msg>Typeselect.<commit_after>define(['jquery', 'plugins/typeahead'], function($) {

    !function($) {

        "use strict";

        var Typeselect = function(element, datasets, options) {
            if (typeof options === "undefined")
                options = {};

            this.options = $.extend({}, $.fn.typeselect.defaults, options);

            this.selectedDatums = {};
            this.selectedItems = {};
            this.datasetsByName = {};

            var createFetch = function(name, valueKey, fetch) {
                return $.proxy(function(parsedResponse){
                    var datums = fetch ? fetch(parsedResponse) : JSON.parse(parsedResponse);
                    var filtered = $.map(datums, function(index, datum){
                         if (this.selectedDatums[datum[valueKey]]) return null;
                         else return datum;
                    });
                }, this);
            };

            // Support multiple targets based on dataset
            if (!$.isArray(datasets)) datasets = [datasets];

            // Setup stores for selected item targets
            this.$targetsMap = {};
            if (this.options.target)
                this.$defaultTarget = $(this.options.target);

            // Save datasets off for our use later
            this.dataset = datasets;

            // Find all targets for each dataset and modify
            // modify filter attributes so we can remove
            // selected items from future suggestions
            $.each(datasets, $.proxy(function(index, dataset) {
                var valueKey = dataset.valueKey || 'value';
                if (dataset.target) this.$targetsMap[dataset.name] = $(dataset.target);
                if (typeof dataset.remote === 'string' || dataset.remote instanceof String)
                    dataset.remote = {url: dataset.remote};
                if (dataset.remote)
                    dateset.remote.fetch = createFetch(dataset.name, valueKey, dataset.remote.fetch);
                this.selectedDatums[dataset.name] = {};
                this.selectedItems[dataset.name] = {};
                this.datasetsByName[dataset.name] = dataset;
            }, this));

            // Initialize with twitter (not bootstrap) typeahead
            this.$element = $(element).typeahead(datasets);

            this.$element.on('typeahead:selected', $.proxy(function(event, datum, dataset_name){
                 this.add(datum, dataset_name);
                 // Clear out the textbox
                 this.$element.blur();
                 this.$element.val('');
            }, this));

            // Populate pre-selected values
            var preselected = this.options.selected;
            for (var i = 0; i < preselected.length; i++) {
                if ($.isArray(preselected[i]))
                    this.add.apply(preselected[i]);
                else
                    this.add(preselected[i]);
            }

            this.listen();
        };

        Typeselect.prototype = {

            constructor: Typeselect,

            listen: function() {
                var targets = [];
                $.each(this.$targetsMap, $.proxy(function(name, $target){
                    if (~$.inArray($target, targets)) return true;
                    $target.on('click', '.close', $.proxy(this.click, this));
                    targets.append($target);
                }, this));

                if (this.$defaultTarget && !$.inArray(targets, this.$defaultTarget))
                    $defaultTarget.on('click', '.close', $.proxy(this.click, this));
            },

            add: function(value, dataset_name) {
                // dataset_name parameter is optional
                // Use first supplied dataset by default
                if (typeof dataset_name === "undefined")
                    dataset_name = this.options.dataset || this.datasets[0].name;

                var template, item, $target;
                var dataset = this.datasetsByName[dataset_name];
                var valueKey = dataset.valueKey || "value";
                // Do not add redundant values
                if (this.selectedDatums[dataset_name][value[valueKey]]) return;
                this.selectedDatums[dataset_name][value[valueKey]] = value;

                // Render
                if (dataset.selectedTemplate){
                    if (!$.isFunction(dataset.selectedTemplate))
                        template = dataset.engine.compile(dataset.selectedTemplate);
                    else
                        template = dataset.selectedTemplate;
                    item = $(template.render(value))
                        .attr('data-value', value[valueKey])
                        .attr('data-dataset', dataset_name);
                } else {
                    // default list item with remove icon
                    item = $(this.options.selectedItem)
                        .text(value[valueKey])
                        .attr('data-value', value[valueKey])
                        .attr('data-dataset', dataset_name)
                        .append('×');
                }

                this.selectedItems[dataset_name][value[valueKey]] = item;

                // Add to the target container
                if ($target = this.$targetsMap[dataset_name]){
                    $target.append(item);
                } else {
                    // Use default target
                    this.$defaultTarget.append(item);
                }
            },

            remove: function(value, dataset_name) {
                // dataset_name parameter is optional
                // Use first supplied dataset by default
                if (typeof dataset_name === "undefined")
                    dataset_name = this.options.dataset || this.datasets[0].name;

                var valueKey = this.datasetsByName[dataset_name].valueKey || 'value',
                    item;

                // Remove from the selected cache
                if (this.selectedDatums[dataset_name][value])
                    delete this.selectedDatums[dataset_name][value];

                // Remove element from DOM element cache
                if (item = this.selectedItems[dataset_name][value]){
                   delete this.selectedItems[dataset_name][value];
                   item.remove();
                }
            },

            click: function(event) {
                event.preventDefault();
                var $parent = $(event.target).parent();
                this.remove($parent.attr('data-value'), $parent.attr('data-dataset'));
            },

            selected: function(groupByDataset){
                if (groupByDataset)
                    return this.selectedDatums;
                // Flatten
                return $.map(this.selectedDatums, function(key, dataset){
                    return $.map(dataset, function(key, datum){
                        return datum;
                    });
                });
            }

        };

        $.fn.typeselect = function(option, defaults) {
            return this.each(function() {
                var $this = $(this),
                   data = $this.data('typeselect'),
                   datasets = typeof option == 'object' && option;
                if (!data) $this.data('typeselect', (data = new Typeselect(this, datasets, defaults)));
                if (typeof option == 'string') data[option]();
            });
        };

        $.fn.typeselect.defaults = {
            selected: [],
            selectedItem: '

'
        };

        $.fn.typeselect.Constructor = Typeselect;

        /* TYPESELECT DATA-API
         * =================== */
        $(document).on('focus.typeselect.data-api', '[data-provide="typeselect"]', function(e) {
            var $this = $(this);
            if ($this.data('typeselect')) return;
            e.preventDefault();
            $this.typeselect($this.data());
        });

    }($);

});
<|endoftext|>


<commit_before>var LucasScript = {

	init : function( tw )
	{

	},

	update : function ( tw , deltaTime )
	{

	},

    inputs : {

    '5': function(me,tw)
    {
        tw.cameras.main = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );
        tw.cameras.main.position.x = 0;
        tw.cameras.main.position.y = 10;
        tw.cameras.main.position.z = 0;
        tw.cameras.main.rotation.x = -90 * Math.PI / 180;

    },

    //Camera front face
    '2' : function(me,tw)
    {
        tw.cameras.main = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );
        tw.cameras.main.position.x = 0;
        tw.cameras.main.position.y = 0;
        tw.cameras.main.position.z = 10;

    },

    //Camera back face
    '8' : function(me,tw)
    {
       tw.cameras.main = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );
        tw.cameras.main.position.x = 0;
        tw.cameras.main.position.y = 0;
        tw.cameras.main.position.z = -10;
        //NOT GOOD
        tw.cameras.main.rotation.y = 180 * Math.PI / 180;

    },

    //Camera left face
    '4' : function(me,tw)
    {
       tw.cameras.main = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );
        tw.cameras.main.position.x = -10;
        tw.cameras.main.position.y = 0;
        tw.cameras.main.position.z = 0;
        tw.cameras.main.rotation.y = -90 * Math.PI / 180;

    },

        //Camera right face
    '6' : function(me,tw)
    {
       tw.cameras.main = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );
        tw.cameras.main.position.x = 10;
        tw.cameras.main.position.y = 0;
        tw.cameras.main.position.z = 0;
        tw.cameras.main.rotation.y = 90 * Math.PI / 180;

    },

        //Perspective camera
    'c' : function(me,tw)
    {
            tw.cameras.main = new THREE.PerspectiveCamera(
			tw.VIEW_ANGLE,
			tw.aspect,
			tw.NEAR,
			tw.FAR
		);

        tw.cameras.main.position.z = tw.CAMERA_Z;
    },

    }
}<commit_msg>Camera added<commit_after>var LucasScript = {

	init : function( tw )
	{

        this.myCamera = new THREE.OrthographicCamera(-20, 20, 20/tw.aspect, -20/tw.aspect, 0, 1000 );

	},

	update : function ( tw , deltaTime )
	{

	},

    inputs : {

    '5': function(me,tw)
    {
        tw.changeCamera(me.myCamera);
       console.log("t");
        me.myCamera.position.x = 0;
        me.myCamera.position.y = 10;
        me.myCamera.position.z = 0;

        me.myCamera.rotation.x = -90 * Math.PI / 180;
        me.myCamera.rotation.y = 0 * Math.PI / 180;

    },

    //Camera front face
    '2' : function(me,tw)
    {
        tw.changeCamera(me.myCamera);
        me.myCamera.position.x = 0;
        me.myCamera.position.y = 0;
        me.myCamera.position.z = 10;

        me.myCamera.rotation.x = 0 * Math.PI / 180;
        me.myCamera.rotation.y = 0 * Math.PI / 180;

    },

    //Camera back face
    '8' : function(me,tw)
    {
        tw.changeCamera(me.myCamera);
        me.myCamera.position.x = 0;
        me.myCamera.position.y = 0;
        me.myCamera.position.z = -10;
        //NOT GOOD

        me.myCamera.rotation.x = -0 * Math.PI / 180;
        me.myCamera.rotation.y = 180 * Math.PI / 180;

    },

    //Camera left face
    '4' : function(me,tw)
    {
        tw.changeCamera(me.myCamera);
        me.myCamera.position.x = -10;
        me.myCamera.position.y = 0;
        me.myCamera.position.z = 0;

        me.myCamera.rotation.x = 0 * Math.PI / 180;
        me.myCamera.rotation.y = -90 * Math.PI / 180;

    },

        //Camera right face
    '6' : function(me,tw)
    {
       tw.changeCamera(me.myCamera);
        me.myCamera.position.x = 10;
       me.myCamera.position.y = 0;
        me.myCamera.position.z = 0;

        me.myCamera.rotation.x = 0 * Math.PI / 180;
        me.myCamera.rotation.y = 90 * Math.PI / 180;

    },

        //Perspective camera
    'c' : function(me,tw)
    {
        tw.changeCamera(tw.cameras.main);

    },

    }
}<|endoftext|>


<commit_before><commit_msg>Delete scriptMulti - Kopi.js<commit_after><|endoftext|>


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

/**
 * The controller of the prompt dialog.
 */
export class PromptDialogController {

    /**
     * Constructor.
     *
     * @param $uibModalInstance
     * @param modalData
     */
    // @ngInject
    constructor($uibModalInstance, modalData) {
        this.$uibModalInstance = $uibModalInstance;

        /**
         * The model for the input field for the user input.
         */
        this.userInput = null;

        /**
         * The text to display.
         */
        this.text = modalData.text;

        /**
         * The regex the user input has to match.
         */
        this.inputPattern = /^[a-zA-Z0-9\.\-,_]+$/;
    }

    /**
     * Close the modal dialog and pass the user input.
     */
    ok() {
        this.$uibModalInstance.close(this.userInput);
    }

    /**
     * Close the modal dialog.
     */
    close() {
        this.$uibModalInstance.dismiss();
    }
}

/**
 * The controller that handles the confirm modal dialog.
 */
export class ConfirmDialogController {

    /**
     * Constructor.
     *
     * @param $uibModalInstance
     * @param modalData
     */
    // @ngInject
    constructor($uibModalInstance, modalData) {
        this.$uibModalInstance = $uibModalInstance;

        /**
         * The text to display.
         * @type {string}
         */
        this.text = modalData.text || null;
    }

    /**
     * Close the modal dialog.
     */
    ok() {
        this.$uibModalInstance.close();
    }

    /**
     * Close the modal dialog.
     */
    close() {
        this.$uibModalInstance.dismiss();
    }
}

/**
 * The service for handling promt and confirm dialogs.
 */
export class PromptService {

    /**
     * Constructor.
     *
     * @param $uibModal
     */
    // @ngInject
    constructor($uibModal) {
        this.$uibModal = $uibModal;
    }

    /**
     * Opens the prompt dialog.
     *
     * @param {string} text - The text to display.
     * @return {*} - The modal result promise.
     */
    prompt(text) {
        return this.$uibModal.open({
            templateUrl: 'html/modals/prompt-dialog.html',
            controller: PromptDialogController,
            controllerAs: 'vm',
            resolve: {
                modalData: function () {
                    return {
                        text: text
                    };
                }
            }
        }).result;
    }

    /**
     * Opens the confirm dialog.
     *
     * @param {string} text - The text to be displayed in the confirm dialog.
     * @returns {*} - The modal result promise.
     */
    confirm(text) {
        return this.$uibModal.open({
            templateUrl: 'html/modals/confirm-dialog.html',
            controller: ConfirmDialogController,
            controllerAs: 'vm',
            resolve: {
                modalData: function () {
                    return {text: text};
                }
            }
        }).result;
    }
}<commit_msg>fix template paths<commit_after>/*
 * Copyright 2016 TU Dortmund
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The controller of the prompt dialog.
 */
export class PromptDialogController {

    /**
     * Constructor.
     *
     * @param $uibModalInstance
     * @param modalData
     */
    // @ngInject
    constructor($uibModalInstance, modalData) {
        this.$uibModalInstance = $uibModalInstance;

        /**
         * The model for the input field for the user input.
         */
        this.userInput = null;

        /**
         * The text to display.
         */
        this.text = modalData.text;

        /**
         * The regex the user input has to match.
         */
        this.inputPattern = /^[a-zA-Z0-9\.\-,_]+$/;
    }

    /**
     * Close the modal dialog and pass the user input.
     */
    ok() {
        this.$uibModalInstance.close(this.userInput);
    }

    /**
     * Close the modal dialog.
     */
    close() {
        this.$uibModalInstance.dismiss();
    }
}

/**
 * The controller that handles the confirm modal dialog.
 */
export class ConfirmDialogController {

    /**
     * Constructor.
     *
     * @param $uibModalInstance
     * @param modalData
     */
    // @ngInject
    constructor($uibModalInstance, modalData) {
        this.$uibModalInstance = $uibModalInstance;

        /**
         * The text to display.
         * @type {string}
         */
        this.text = modalData.text || null;
    }

    /**
     * Close the modal dialog.
     */
    ok() {
        this.$uibModalInstance.close();
    }

    /**
     * Close the modal dialog.
     */
    close() {
        this.$uibModalInstance.dismiss();
    }
}

/**
 * The service for handling promt and confirm dialogs.
 */
export class PromptService {

    /**
     * Constructor.
     *
     * @param $uibModal
     */
    // @ngInject
    constructor($uibModal) {
        this.$uibModal = $uibModal;
    }

    /**
     * Opens the prompt dialog.
     *
     * @param {string} text - The text to display.
     * @return {*} - The modal result promise.
     */
    prompt(text) {
        return this.$uibModal.open({
            templateUrl: 'html/directives/modals/prompt-dialog.html',
            controller: PromptDialogController,
            controllerAs: 'vm',
            resolve: {
                modalData: function () {
                    return {
                        text: text
                    };
                }
            }
        }).result;
    }

    /**
     * Opens the confirm dialog.
     *
     * @param {string} text - The text to be displayed in the confirm dialog.
     * @returns {*} - The modal result promise.
     */
    confirm(text) {
        return this.$uibModal.open({
            templateUrl: 'html/directives/modals/confirm-dialog.html',
            controller: ConfirmDialogController,
            controllerAs: 'vm',
            resolve: {
                modalData: function () {
                    return {text: text};
                }
            }
        }).result;
    }
}<|endoftext|>


<commit_before>'use strict';

var _ = require('../underscore_ext');
var React = require('react');
var Input = require('react-bootstrap/lib/Input');
var Button = require('react-bootstrap/lib/Button');
var SplitButton = require('react-bootstrap/lib/SplitButton');
var MenuItem = require('react-bootstrap/lib/MenuItem');
var Tooltip = require('react-bootstrap/lib/Tooltip');
var OverlayTrigger = require('react-bootstrap/lib/OverlayTrigger');
var Modal = require('react-bootstrap/lib/Modal');
var {deepPureRenderMixin} = require('../react-utils');

var SampleIDInput = React.createClass({
	getInitialState() {
		return {
			show: false,
			value: undefined
		};
	},
	onChange (ev) {
		var value = ev.target.value;
		this.setState({value});
	},
	close () {
		this.setState({ show: false});
	},
	submit () {
		var samplesList = this.state.value.split(/\s+/),
			{onSearchIDAndFilterColumn, onSamplesSubmit} = this.props;
		this.close();
		this.state.value = '';
		onSearchIDAndFilterColumn(samplesList);
		onSamplesSubmit("A:true"); // since the new column is always column A
	},
	render() {
		var tooltipButton = <Tooltip>Search by sample IDs</Tooltip>,
			tooltipModalString = 'New binary column will be made using the your list:\
				matched samples vs. the rest of the samples',
			tooltipModal = <Tooltip>{tooltipModalString}</Tooltip>,
			{cohortSamples, disabled} = this.props,
			help = 'e.g.\n' + Object.values(cohortSamples)[0].slice(0, 5).join('\n') + '\n...';

		return (

				<OverlayTrigger trigger={['hover']} placement="top" overlay={tooltipButton}>
					<Button
						bsSize = "small"
						onClick = {() => this.setState({ show: true})}
						disabled={disabled}>
						Sample list -> New Column
					</Button>
				</OverlayTrigger>
				<Modal
					show={this.state.show}
					onHide={this.close}
					container={this}
					aria-labelledby="contained-modal-title">
					<Modal.Header closeButton>
						<Modal.Title id="contained-modal-title">
							Enter a list of samaple IDs
							<OverlayTrigger trigger={['hover']} placement="right" overlay={tooltipModal}>

							</OverlayTrigger>
						</Modal.Title>
					</Modal.Header>
					<Modal.Body>
						<Input style={{width: 550, height: 200}}
							value={this.state.value}
							type ="textarea"
							placeholder={help}
							onChange={this.onChange}/>
					</Modal.Body>
					<Modal.Footer>
						<Button bsStyle="primary" onClick={this.submit} disabled={!this.state.value}>Submit</Button>
						<Button onClick={this.close}>Cancel</Button>
					</Modal.Footer>
				</Modal>

		);
	}
});

var SampleSearch = React.createClass({
	mixins: [deepPureRenderMixin],
	componentWillReceiveProps: function (newProps) {
		if (this.state.value === this.props.value) {
			this.setState({value: newProps.value});
		}
		// otherwise we have buffered changes to state, and
		// updating from props would revert the user input
		// and move the carat to the end.
	},
	getInitialState: function () {
		return {value: this.props.value};
	},
	onChange: function (ev) {
		var {onChange} = this.props,
			value = ev.target.value;
		this.setState({value});
		onChange(value);
	},
	onSamplesSubmit: function (value) {
		var {onChange} = this.props;
		this.setState({value});
		onChange(value);
	},
	render: function () {
		var {matches, help, onFilter, onZoom, onCreateColumn, onSearchIDAndFilterColumn, cohortSamples, mode} = this.props,
			{value} = this.state,
			noshow = (mode !== "heatmap"),
			filterButton = onFilter ?
					() : null;
		return (
			!_.isEmpty(cohortSamples) ?
				<form className='form-inline' onSubmit={ev => ev.preventDefault()}>
					<Input style={{width: '26em'}}
						type='text'
						value={value}
						title={value}
						placeholder={'Samples to highlight. e.g. TCGA-DB-A4XH-01, missense'}
						onChange={this.onChange}
						disabled={noshow}/>
					{` Matching samples: ${matches}`}
					{filterButton ?
						(<SplitButton onClick={onFilter} bsSize='sm' title={filterButton} disabled={noshow}>
							<MenuItem title='Apply to filter' onClick={onFilter}>Filter</MenuItem>
							<MenuItem title='Apply to zoom' onClick={onZoom}>Zoom</MenuItem>
							<MenuItem title='Create column from' onClick={onCreateColumn}>New Column</MenuItem>
						</SplitButton>) : null}
					{help ? <Button bsStyle='link' target='_blank' href={help}>Help with search</Button> : null}
					<SampleIDInput
						onSearchIDAndFilterColumn={onSearchIDAndFilterColumn}
						onSamplesSubmit={this.onSamplesSubmit}
						cohortSamples={cohortSamples}
						disabled={noshow}/>
				</form> : null
		);
	}
});

module.exports = SampleSearch;
<commit_msg>Custom Sample List button wording change back<commit_after>'use strict';

var _ = require('../underscore_ext');
var React = require('react');
var Input = require('react-bootstrap/lib/Input');
var Button = require('react-bootstrap/lib/Button');
var SplitButton = require('react-bootstrap/lib/SplitButton');
var MenuItem = require('react-bootstrap/lib/MenuItem');
var Tooltip = require('react-bootstrap/lib/Tooltip');
var OverlayTrigger = require('react-bootstrap/lib/OverlayTrigger');
var Modal = require('react-bootstrap/lib/Modal');
var {deepPureRenderMixin} = require('../react-utils');

var SampleIDInput = React.createClass({
	getInitialState() {
		return {
			show: false,
			value: undefined
		};
	},
	onChange (ev) {
		var value = ev.target.value;
		this.setState({value});
	},
	close () {
		this.setState({ show: false});
	},
	submit () {
		var samplesList = this.state.value.split(/\s+/),
			{onSearchIDAndFilterColumn, onSamplesSubmit} = this.props;
		this.close();
		this.state.value = '';
		onSearchIDAndFilterColumn(samplesList);
		onSamplesSubmit("A:true"); // since the new column is always column A
	},
	render() {
		var tooltipButton = <Tooltip>Search by sample IDs</Tooltip>,
			tooltipModalString = 'New binary column will be made using your list: \
				matched samples vs. the rest.',
			tooltipModal = <Tooltip>{tooltipModalString}</Tooltip>,
			{cohortSamples, disabled} = this.props,
			help = 'e.g.\n' + Object.values(cohortSamples)[0].slice(0, 5).join('\n') + '\n...';

		return (

				<OverlayTrigger trigger={['hover']} placement="top" overlay={tooltipButton}>
					<Button
						bsSize = "small"
						onClick = {() => this.setState({ show: true})}
						disabled={disabled}>
						Custom Sample List
					</Button>
				</OverlayTrigger>
				<Modal
					show={this.state.show}
					onHide={this.close}
					container={this}
					aria-labelledby="contained-modal-title">
					<Modal.Header closeButton>
						<Modal.Title id="contained-modal-title">
							Enter a list of samaple IDs to highlight
							<OverlayTrigger trigger={['hover']} placement="right" overlay={tooltipModal}>

							</OverlayTrigger>
						</Modal.Title>
					</Modal.Header>
					<Modal.Body>
						<Input style={{width: 550, height: 200}}
							value={this.state.value}
							type ="textarea"
							placeholder={help}
							onChange={this.onChange}/>
					</Modal.Body>
					<Modal.Footer>
						<Button bsStyle="primary" onClick={this.submit} disabled={!this.state.value}>Submit</Button>
						<Button onClick={this.close}>Cancel</Button>
					</Modal.Footer>
				</Modal>

		);
	}
});

var SampleSearch = React.createClass({
	mixins: [deepPureRenderMixin],
	componentWillReceiveProps: function (newProps) {
		if (this.state.value === this.props.value) {
			this.setState({value: newProps.value});
		}
		// otherwise we have buffered changes to state, and
		// updating from props would revert the user input
		// and move the carat to the end.
	},
	getInitialState: function () {
		return {value: this.props.value};
	},
	onChange: function (ev) {
		var {onChange} = this.props,
			value = ev.target.value;
		this.setState({value});
		onChange(value);
	},
	onSamplesSubmit: function (value) {
		var {onChange} = this.props;
		this.setState({value});
		onChange(value);
	},
	render: function () {
		var {matches, help, onFilter, onZoom, onCreateColumn, onSearchIDAndFilterColumn, cohortSamples, mode} = this.props,
			{value} = this.state,
			noshow = (mode !== "heatmap"),
			filterButton = onFilter ?
					() : null;
		return (
			!_.isEmpty(cohortSamples) ?
				<form className='form-inline' onSubmit={ev => ev.preventDefault()}>
					<Input style={{width: '26em'}}
						type='text'
						value={value}
						title={value}
						placeholder={'Samples to highlight. e.g. TCGA-DB-A4XH-01, missense'}
						onChange={this.onChange}
						disabled={noshow}/>
					{` Matching samples: ${matches}`}
					{filterButton ?
						(<SplitButton onClick={onFilter} bsSize='sm' title={filterButton} disabled={noshow}>
							<MenuItem title='Apply to filter' onClick={onFilter}>Filter</MenuItem>
							<MenuItem title='Apply to zoom' onClick={onZoom}>Zoom</MenuItem>
							<MenuItem title='Create column from' onClick={onCreateColumn}>New Column</MenuItem>
						</SplitButton>) : null}
					{help ? <Button bsStyle='link' target='_blank' href={help}>Help with search</Button> : null}
					<SampleIDInput
						onSearchIDAndFilterColumn={onSearchIDAndFilterColumn}
						onSamplesSubmit={this.onSamplesSubmit}
						cohortSamples={cohortSamples}
						disabled={noshow}/>
				</form> : null
		);
	}
});

module.exports = SampleSearch;
<|endoftext|>


<commit_before>var autosize = require("autosize");
var constants = require("../util/constants");
var CurrentUserModel = require("../stores/currentUser");
var View = require("handlebones").View;
var template = require("../tmpl/comment-form");
var CommentModel = require("../models/comment");
var CommentView = require("../views/commentView");
var eb = require("../eventBus");
var Handlebones = require("handlebones");
var PolisFacebookUtils = require('../util/facebookButton');
var ProfilePicView = require('../views/profilePicView');
var serialize = require("../util/serialize");
var Utils = require("../util/utils");

var CHARACTER_LIMIT = constants.CHARACTER_LIMIT;

var CommentsByMeView = Handlebones.CollectionView.extend({
  modelView: CommentView
});

function reject() {
  return $.Deferred().reject();
}
function resolve() {
  return $.Deferred().resolve();
}

module.exports = Handlebones.ModelView.extend({
  name: "comment-form",
  template: template,

  // needed to prevent double submissions, which are annoying because they trigger a duplicate alert
  buttonActive: true,

  context: function() {
    var ctx = Handlebones.ModelView.prototype.context.apply(this, arguments);
    ctx = _.extend(ctx, this, this.model&&this.model.attributes);
    ctx.is_active = this.parent.model.get("is_active");
    ctx.shouldAutofocusOnTextarea = this.shouldAutofocusOnTextarea || Utils.shouldFocusOnTextareaWhenWritePaneShown();
    ctx.hasTwitter = userObject.hasTwitter;
    ctx.hasFacebook = userObject.hasFacebook;
    return ctx;
  },
  hideMessage: function(id) {
    this.$(id).hide();
    // if there are no other warnings/tips showing, show the default one
    if (this.$(".protip:visible").length === 0) {
      this.$("#not_a_reply_message").show();
    }
  },
  showMessage: function(id) {
    // since there are now other warnings/tips showing, hide the default one
    this.$("#not_a_reply_message").hide();
    this.$(id).show();
  },
  updateOneIdeaPerCommentMessage: function(formText) {
    // TODO I18N
    // Tests to see if there is non-punctuation that follows the end of a sentence.
    if ((formText||"").match(/[\?\.\!].*[a-zA-Z0-9]+/)) {
      this.showMessage("#one_idea_per_comment_message");
    } else {
      this.hideMessage("#one_idea_per_comment_message");
    }
  },
  updateCommentNotQuestionAlert: function(formText) {
    if (formText.indexOf("?") >= 0) {
      this.showMessage("#commentNotQuestionAlert");
    } else {
      this.hideMessage("#commentNotQuestionAlert");
    }
  },
  textChange: function() {
    var formText = $(arguments[0].target).val();
    var len = formText.length;
    var remaining = CHARACTER_LIMIT - len;
    var txt;
    if (remaining < 0) {
      // txt = "- " + remaining;
      txt = remaining;
      this.$("#commentCharCount").css("color", "red");
      this.$("#comment_button").attr("disabled", "disabled");
      this.$("#comment_button").css("opacity", 0.3);
      this.showMessage("#commentTooLongAlert");
      this.buttonActive = false;
    } else if (remaining > 0) {
      txt = /*"+ " +*/ remaining;
      this.$("#commentCharCount").css("color", "gray");
      this.$("#comment_button").attr("disabled", null);
      this.$("#comment_button").css("opacity", 1);
      this.hideMessage("#commentTooLongAlert");
      this.buttonActive = true;
    } else {
      txt = remaining;
      this.$("#commentCharCount").css("color", "gray");
      this.$("#comment_button").attr("disabled", null);
      this.$("#comment_button").css("opacity", 1);
      this.hideMessage("#commentTooLongAlert");
      this.buttonActive = true;
    }
    this.$("#commentCharCount").text(txt);
    this.updateOneIdeaPerCommentMessage(formText);
    this.updateCommentNotQuestionAlert(formText);
    eb.trigger(eb.interacted);
  },
  showFormControls: function() {
    // this.$(".alert").hide();
    this.$(".comment_form_control_hideable").show();
  },
  hideFormControls: function() {
    this.$(".comment_form_control_hideable").hide();
    this.$("#commentCharCount").text("");
  },
  reloadPagePreservingCommentText: function() {
    var wipCommentFormText = $("#comment_form_textarea").val();
    var params = {};
    if (wipCommentFormText.length) {
      params.wipCommentFormText = wipCommentFormText;
    }
    eb.trigger(eb.reloadWithMoreParams, params);
  },
  events: {
    "focus #comment_form_textarea": function(e) { // maybe on keyup ?
      this.showFormControls();
    },
    "blur #comment_form_textarea": function(e) {
      var txt = this.$("#comment_form_textarea").val();
      if (!txt || !txt.length) {
        this.hideFormControls();
      }
    },
    "change #comment_form_textarea": "textChange",
    "keyup #comment_form_textarea": "textChange",
    "paste #comment_form_textarea": "textChange",
    "click #facebookButtonCommentForm" : "facebookClicked",
    "click #twitterButtonCommentForm" : "twitterClicked",
    "click #comment_button": function(e){
      var that = this;
      e.preventDefault();

      function doSubmitComment() {
        if (that.buttonActive) {
          that.buttonActive = false;
          serialize(that, function(attrs){
            that.participantCommented(attrs).then(function() {
              that.$("#comment_form_textarea").val("");
              that.hideFormControls();
            }).always(function() {
              that.buttonActive = true;
            });
          });
        }
      }

      var hasSocial = window.userObject.hasFacebook || window.userObject.hasTwitter;
      if (hasSocial) {
        doSubmitComment();
      } else {
        this.showSocialAuthChoices();
      }
    }
  },
  onAuthSuccess: function() {
    this.reloadPagePreservingCommentText();
    // $("#socialButtonsCommentForm").hide();
    // $("#comment_form_controls").show();
  },
  facebookClicked: function(e) {
    e.preventDefault();
    var that = this;
    PolisFacebookUtils.connect().then(function() {
      // wait a bit for new cookies to be ready, or something, then submit comment.
      setTimeout(function() {
        that.onAuthSuccess();
        // CurrentUserModel.update();
      }, 100);
    }, function(err) {
      // alert("facebook error");
    });
  },
  twitterClicked: function(e) {
    var that = this;
    e.preventDefault();

    eb.on(eb.twitterConnected, function() {
      // wait a bit for new cookies to be ready, or something, then submit comment.
      setTimeout(function() {
        that.onAuthSuccess();
        // CurrentUserModel.update();
      }, 100);
    });
    // open a new window where the twitter auth screen will show.
    // that window will redirect back to a simple page that calls window.opener.twitterStatus("ok")
    var params = 'location=0,status=0,width=800,height=400';
    window.open(document.location.origin + "/api/v3/twitterBtn?dest=/twitterAuthReturn", 'twitterWindow', params);
  },
  showSocialAuthChoices: function() {
    $("#comment_form_controls").hide();
    $("#socialButtonsCommentForm").show();
  },
  participantCommented: function(attrs) {
    var that = this; //that = the view
    attrs.pid = this.pid;
    attrs.conversation_id = this.conversation_id;
    attrs.vote = constants.REACTIONS.AGREE; // participants' comments are automatically agreed to. Needed for now since math assumes every comment has at least one vote.

    if (/^\s*$/.exec(attrs.txt)) {
      alert("Comment is empty");
      return reject();
    }
    if (attrs.txt.length > 997) {
      alert("Comment is too long");
      return reject();
    }

    // DEMO_MODE
    if (this.pid < 0) {
      that.showMessage("#commentSentDemoAlert");
      that.trigger("commentSubmitted");
      that.updateCollection();
      return resolve();
    }

    var comment = new CommentModel(attrs);
    var promise = comment.save();
    if (!promise) {
      return reject();
    } else {
      promise.then(function() {
        that.trigger("commentSubmitted"); // view.trigger
        that.updateCollection();
        $("#comment_form_textarea").hide();
        $("#commentSentAlert").fadeIn(300);
        setTimeout(function() {
          $("#commentSentAlert").fadeOut(500, function() {
            $("#comment_form_textarea").fadeIn(400);
          });
        }, 1500);
      }, function(args) {
        if (!args || !args.length || !args[0].length) {
          alert("failed to send");
          return;
        }
        var err = args[0][0];
        if (err.status === 409) {

          // that.model.set({
          //   error: "Duplicate!",
          //   errorExtra: "That comment already exists.",
          // });
          alert("Duplicate! That comment already exists.");
        } else if (err.responseText === "polis_err_conversation_is_closed"){

          // that.model.set({
          //   error: "This conversation is closed.",
          //   errorExtra: "No further commenting is allowed.",
          // });
          alert("This conversation is closed. No further commenting is allowed.");
        } else {

          // that.model.set({
          //   error: "Error sending comment.",
          //   errorExtra: "Please try again later.",
          // });
          alert("Error sending comment, please try again later.");
        }
      });
      return promise;
    }
  },
  updateCollection: function() {
    this.collection.fetch({
      data: $.param({
        conversation_id: this.conversation_id,
        pid: this.pid
      })
    });
  },
  initialize: function(options) {
    Handlebones.ModelView.prototype.initialize.apply(this, arguments);
    this.pid = options.pid;
    this.model = options.model;
    this.conversation_id = options.conversation_id;
    this.collection = options.collection;
    this.commentsByMeView = this.addChild(new CommentsByMeView({
      collection: options.collection
    }));

    this.profilePicView = this.addChild(new ProfilePicView({
      model: CurrentUserModel,
    }));

    if (options.wipCommentFormText) {
      this.shouldAutofocusOnTextarea = true;
    }

    this.listenTo(this, "render", function(){
      setTimeout(function() {
        if (!_.isUndefined(options.wipCommentFormText)) {
          $("#comment_form_textarea").val(options.wipCommentFormText);
          eb.trigger(eb.doneUsingWipCommentFormText);
        }
        autosize($("#comment_form_textarea"));
      },100);
    });

  },
});<commit_msg>remove newlines from form<commit_after>var autosize = require("autosize");
var constants = require("../util/constants");
var CurrentUserModel = require("../stores/currentUser");
var View = require("handlebones").View;
var template = require("../tmpl/comment-form");
var CommentModel = require("../models/comment");
var CommentView = require("../views/commentView");
var eb = require("../eventBus");
var Handlebones = require("handlebones");
var PolisFacebookUtils = require('../util/facebookButton');
var ProfilePicView = require('../views/profilePicView');
var serialize = require("../util/serialize");
var Utils = require("../util/utils");

var CHARACTER_LIMIT = constants.CHARACTER_LIMIT;

var CommentsByMeView = Handlebones.CollectionView.extend({
  modelView: CommentView
});

function reject() {
  return $.Deferred().reject();
}
function resolve() {
  return $.Deferred().resolve();
}

module.exports = Handlebones.ModelView.extend({
  name: "comment-form",
  template: template,

  // needed to prevent double submissions, which are annoying because they trigger a duplicate alert
  buttonActive: true,

  context: function() {
    var ctx = Handlebones.ModelView.prototype.context.apply(this, arguments);
    ctx = _.extend(ctx, this, this.model&&this.model.attributes);
    ctx.is_active = this.parent.model.get("is_active");
    ctx.shouldAutofocusOnTextarea = this.shouldAutofocusOnTextarea || Utils.shouldFocusOnTextareaWhenWritePaneShown();
    ctx.hasTwitter = userObject.hasTwitter;
    ctx.hasFacebook = userObject.hasFacebook;
    return ctx;
  },
  hideMessage: function(id) {
    this.$(id).hide();
    // if there are no other warnings/tips showing, show the default one
    if (this.$(".protip:visible").length === 0) {
      this.$("#not_a_reply_message").show();
    }
  },
  showMessage: function(id) {
    // since there are now other warnings/tips showing, hide the default one
    this.$("#not_a_reply_message").hide();
    this.$(id).show();
  },
  updateOneIdeaPerCommentMessage: function(formText) {
    // TODO I18N
    // Tests to see if there is non-punctuation that follows the end of a sentence.
    if ((formText||"").match(/[\?\.\!].*[a-zA-Z0-9]+/)) {
      this.showMessage("#one_idea_per_comment_message");
    } else {
      this.hideMessage("#one_idea_per_comment_message");
    }
  },
  updateCommentNotQuestionAlert: function(formText) {
    if (formText.indexOf("?") >= 0) {
      this.showMessage("#commentNotQuestionAlert");
    } else {
      this.hideMessage("#commentNotQuestionAlert");
    }
  },
  textChange: function() {
    var form =  $(arguments[0].target);
    var formText = form.val();
    // remove any newlines
    formText = formText.replace(/\n/g, "");
    form.val(formText);
    var len = formText.length;
    var remaining = CHARACTER_LIMIT - len;
    var txt;
    if (remaining < 0) {
      // txt = "- " + remaining;
      txt = remaining;
      this.$("#commentCharCount").css("color", "red");
      this.$("#comment_button").attr("disabled", "disabled");
      this.$("#comment_button").css("opacity", 0.3);
      this.showMessage("#commentTooLongAlert");
      this.buttonActive = false;
    } else if (remaining > 0) {
      txt = /*"+ " +*/ remaining;
      this.$("#commentCharCount").css("color", "gray");
      this.$("#comment_button").attr("disabled", null);
      this.$("#comment_button").css("opacity", 1);
      this.hideMessage("#commentTooLongAlert");
      this.buttonActive = true;
    } else {
      txt = remaining;
      this.$("#commentCharCount").css("color", "gray");
      this.$("#comment_button").attr("disabled", null);
      this.$("#comment_button").css("opacity", 1);
      this.hideMessage("#commentTooLongAlert");
      this.buttonActive = true;
    }
    this.$("#commentCharCount").text(txt);
    this.updateOneIdeaPerCommentMessage(formText);
    this.updateCommentNotQuestionAlert(formText);
    eb.trigger(eb.interacted);
  },
  showFormControls: function() {
    // this.$(".alert").hide();
    this.$(".comment_form_control_hideable").show();
  },
  hideFormControls: function() {
    this.$(".comment_form_control_hideable").hide();
    this.$("#commentCharCount").text("");
  },
  reloadPagePreservingCommentText: function() {
    var wipCommentFormText = $("#comment_form_textarea").val();
    var params = {};
    if (wipCommentFormText.length) {
      params.wipCommentFormText = wipCommentFormText;
    }
    eb.trigger(eb.reloadWithMoreParams, params);
  },
  events: {
    "focus #comment_form_textarea": function(e) { // maybe on keyup ?
      this.showFormControls();
    },
    "blur #comment_form_textarea": function(e) {
      var txt = this.$("#comment_form_textarea").val();
      if (!txt || !txt.length) {
        this.hideFormControls();
      }
    },
    "change #comment_form_textarea": "textChange",
    "keyup #comment_form_textarea": "textChange",
    "paste #comment_form_textarea": "textChange",
    "click #facebookButtonCommentForm" : "facebookClicked",
    "click #twitterButtonCommentForm" : "twitterClicked",
    "click #comment_button": function(e){
      var that = this;
      e.preventDefault();

      function doSubmitComment() {
        if (that.buttonActive) {
          that.buttonActive = false;
          serialize(that, function(attrs){
            that.participantCommented(attrs).then(function() {
              that.$("#comment_form_textarea").val("");
              that.hideFormControls();
            }).always(function() {
              that.buttonActive = true;
            });
          });
        }
      }

      var hasSocial = window.userObject.hasFacebook || window.userObject.hasTwitter;
      if (hasSocial) {
        doSubmitComment();
      } else {
        this.showSocialAuthChoices();
      }
    }
  },
  onAuthSuccess: function() {
    this.reloadPagePreservingCommentText();
    // $("#socialButtonsCommentForm").hide();
    // $("#comment_form_controls").show();
  },
  facebookClicked: function(e) {
    e.preventDefault();
    var that = this;
    PolisFacebookUtils.connect().then(function() {
      // wait a bit for new cookies to be ready, or something, then submit comment.
      setTimeout(function() {
        that.onAuthSuccess();
        // CurrentUserModel.update();
      }, 100);
    }, function(err) {
      // alert("facebook error");
    });
  },
  twitterClicked: function(e) {
    var that = this;
    e.preventDefault();

    eb.on(eb.twitterConnected, function() {
      // wait a bit for new cookies to be ready, or something, then submit comment.
      setTimeout(function() {
        that.onAuthSuccess();
        // CurrentUserModel.update();
      }, 100);
    });
    // open a new window where the twitter auth screen will show.
    // that window will redirect back to a simple page that calls window.opener.twitterStatus("ok")
    var params = 'location=0,status=0,width=800,height=400';
    window.open(document.location.origin + "/api/v3/twitterBtn?dest=/twitterAuthReturn", 'twitterWindow', params);
  },
  showSocialAuthChoices: function() {
    $("#comment_form_controls").hide();
    $("#socialButtonsCommentForm").show();
  },
  participantCommented: function(attrs) {
    var that = this; //that = the view
    attrs.pid = this.pid;
    attrs.conversation_id = this.conversation_id;
    attrs.vote = constants.REACTIONS.AGREE; // participants' comments are automatically agreed to. Needed for now since math assumes every comment has at least one vote.

    if (/^\s*$/.exec(attrs.txt)) {
      alert("Comment is empty");
      return reject();
    }
    if (attrs.txt.length > 997) {
      alert("Comment is too long");
      return reject();
    }

    // DEMO_MODE
    if (this.pid < 0) {
      that.showMessage("#commentSentDemoAlert");
      that.trigger("commentSubmitted");
      that.updateCollection();
      return resolve();
    }

    var comment = new CommentModel(attrs);
    var promise = comment.save();
    if (!promise) {
      return reject();
    } else {
      promise.then(function() {
        that.trigger("commentSubmitted"); // view.trigger
        that.updateCollection();
        $("#comment_form_textarea").hide();
        $("#commentSentAlert").fadeIn(300);
        setTimeout(function() {
          $("#commentSentAlert").fadeOut(500, function() {
            $("#comment_form_textarea").fadeIn(400);
          });
        }, 1500);
      }, function(args) {
        if (!args || !args.length || !args[0].length) {
          alert("failed to send");
          return;
        }
        var err = args[0][0];
        if (err.status === 409) {

          // that.model.set({
          //   error: "Duplicate!",
          //   errorExtra: "That comment already exists.",
          // });
          alert("Duplicate! That comment already exists.");
        } else if (err.responseText === "polis_err_conversation_is_closed"){

          // that.model.set({
          //   error: "This conversation is closed.",
          //   errorExtra: "No further commenting is allowed.",
          // });
          alert("This conversation is closed. No further commenting is allowed.");
        } else {

          // that.model.set({
          //   error: "Error sending comment.",
          //   errorExtra: "Please try again later.",
          // });
          alert("Error sending comment, please try again later.");
        }
      });
      return promise;
    }
  },
  updateCollection: function() {
    this.collection.fetch({
      data: $.param({
        conversation_id: this.conversation_id,
        pid: this.pid
      })
    });
  },
  initialize: function(options) {
    Handlebones.ModelView.prototype.initialize.apply(this, arguments);
    this.pid = options.pid;
    this.model = options.model;
    this.conversation_id = options.conversation_id;
    this.collection = options.collection;
    this.commentsByMeView = this.addChild(new CommentsByMeView({
      collection: options.collection
    }));

    this.profilePicView = this.addChild(new ProfilePicView({
      model: CurrentUserModel,
    }));

    if (options.wipCommentFormText) {
      this.shouldAutofocusOnTextarea = true;
    }

    this.listenTo(this, "render", function(){
      setTimeout(function() {
        if (!_.isUndefined(options.wipCommentFormText)) {
          $("#comment_form_textarea").val(options.wipCommentFormText);
          eb.trigger(eb.doneUsingWipCommentFormText);
        }
        autosize($("#comment_form_textarea"));
      },100);
    });

  },
});<|endoftext|>