<commit_before>define([
  'marionette',
  '#qt_core/controllers/all',
  '#navigation_core/baseviews/base_qeopaview',
  'd3'
],

function (Marionette,A,BaseQeopaView,d3) {
  'use strict';

  /**
    Annotations track
      Méthodes à exposer :
        init(typeData)
          va récupérer les global datas, générer et afficher

      D3 :
        La data va être mappée en x selon le temps (avec durée)
        et en y, nous allons la mapper de 0 à n, l'index de la data

        En affichage, nous allons juste modifier le scale x pour le temps et le scale y de sorte que
        toute la hauteur soit prise par les barres visibles.

    intern vars
      isModeCreation : false/true
      selectedElement : null / object
  **/

  var DataProvider = Marionette.Controller.extend({
      init : function(annotationTrackObject) {

        this.data = [];

        if (annotationTrackObject) {
          _.each(annotationTrackObject.get('annotations'),function(annotation,index) {
              var dataOk = {
                start : annotation.start_time,
                end : annotation.stop_time,
                index : index,
                uuid : annotation.uuid,
                label : annotation.description,
                clicked : false,
                color :"#cf8e2a"
              }
              this.lastIndex = index;
              this.data.push(dataOk);
          },this);

          //console.error('TODO on annotation track object');
          return;
        }

       /* this.data = [];
        var numItem = 50;
        var stepPerItem = 200;
        for (var i=0; i<numItem;i++) {
          //toutes les secondes on met un truc de taille variable
          var size = 0.2+Math.random()*0.7;
          this.data.push({
            start:i*stepPerItem,
            end : i*stepPerItem+size*stepPerItem,
            index : i, label : "Annot_"+i,
            clicked : (i%3==0 ? true : false),
            color :"#cf8e2a"
          });
        }*/
      },

      //after create/edit/delete
      updateFromServer:function(view,model) {
        var self=this;
        A._i.getOnCfg('annotationControlller').udpateTrackDataFromServer(model,function(modelUpdated) {
          view.resultAnalysis = modelUpdated;
          self.init(modelUpdated);
          (_.bind(view.onNavigatorNewWindow,view))();
        });
      },

  });

  return BaseQeopaView.extend({

    template: templates['visu/sub_track_annotations'],
    className: 'track-annotations',

    ui: {
      btnCreateNewAnnotation : '[data-layout="create_new_annotation"]',
      confirmAnnotationCreationForm : '[data-layout="create_annotation_form"]',
      lblConfirmAnnotationCreation : '[data-layout="create_annotation_label"]',
      inputContentAnnotation : '[data-layout="annotation_content"]',
      lblEditAnnotationMode : '[data-layout="edit_annotation_mode"]',

      container : '.container_track_annotations'
    },
    events: {
      'click @ui.btnCreateNewAnnotation' : 'onClickCreateNewAnnotation',
      'click [data-layout="confirm_annotation_creation"]' : 'onClickConfirmCreateAnnotation',
      'mousemove .container_track_annotations' : 'onMouseMove'
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Definition //un peu con car sur les autres tracks, c'est au niveau du loader qu'on décide ça.
    isTrueDataServer : false,

    ////////////////////////////////////////////////////////////////////////////////////
    //Define
    /*input obj is {type : _type, width : width, height : height, trueData : true/false}*/
    defineTrack:function(o) {
      this.width = o.width;
      this.height = o.height;
      this.isTrueDataServer = o.trueData!==undefined ? o.trueData : false;

      this.resultAnalysis = o.resultAnalysis; //will be the annotation track object

      this.dataProvider = new DataProvider();
    },

    /**
      Init function : va récupérer les data globales et le specific data
    **/
    init:function() {
      this.dataProvider.init(this.resultAnalysis);
      this.createGraphicBase();
      this.createBrush();
      this.onNavigatorNewWindow();
      //this.generateGraphFromData();
      this.hadFirstData=true;
    },

     ////////////////////////////////////////////////////////////////////////////////////
    //Brush listener

    brushed:function(e1,e2,e3) {

      //console.log('new times : '+time1+','+time2);

      //var a = this.xScale.
      if (!this.isModeCreation)
        return;

      var a = (this.viewport.extent()[0]);
      var b = (this.viewport.extent()[1]);
      this.lastBrushData = this.viewport.extent();
      this.ui.lblConfirmAnnotationCreation.empty().append('From '+a.getTime()+" to "+b.getTime());
      this.selectedDatesForAnnotation = [a.getTime(),b.getTime()]
      console.log('brushed annot track : '+JSON.stringify(a)+" -> "+JSON.stringify(b));

    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Click listener
    onClickElement:function(d,i) {
      console.log('click ELEMENT!');

      _.each(this.dataProvider.data,function(obj) {obj.clicked=false});

      d.clicked = true;//!d.clicked;
      this.selectedElement = d;
      this.updateViewEditAnnotation();
      this.onNavigatorNewWindow();
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Listen for mouse over - always on, but used only when we have a selected element
    onMouseMove:function(ev) {
      console.log('Mouse over...'+ev.pageX);
      var timeForMouse = this.xScale.invert(ev.pageX);
      if (!this.selectedElement)
        return;

      var lowerBound = this.selectedElement.start+0.1*(this.selectedElement.end - this.selectedElement.start);
      var upperBound = this.selectedElement.end - 0.1*(this.selectedElement.end - this.selectedElement.start);
      var inBounds=false, isMovingLowerBound = false;
      if (timeForMouse<lowerBound && timeForMouse > this.selectedElement.start) {
        inBounds=true;isMovingLowerBound=true;
        this.ui.container.css('cursor','row-resize');
      }
      else if (timeForMouse>upperBound && timeForMouse < this.selectedElement.end) {
        inBounds=true;isMovingLowerBound=false;
        this.ui.container.css('cursor','row-resize');
      }
      else {
        this.ui.container.css('cursor','default');
      }
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Mode to edit an annotation
    updateViewEditAnnotation:function() {
      if (this.isModeCreation) {
        this.updateViewOnNewModeCreation(false);
      }
      var element = this.selectedElement;
      if (!element) {
        return console.error('ERROR : no selected element on updateViewEditAnnotation')
      }
      this.ui.lblEditAnnotationMode.empty()
      this.ui.lblEditAnnotationMode.append('Edit '+element.uuid);
      this.ui.confirmAnnotationCreationForm.removeClass('hidden');
      this.ui.lblConfirmAnnotationCreation.empty().append('From '+element.start+" to "+element.end);
      this.ui.inputContentAnnotation.val(element.label);
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Button to toggle creation mode
    onClickCreateNewAnnotation:function() {
      var newModeIsCreation = ! this.isModeCreation;
      this.updateViewOnNewModeCreation(newModeIsCreation);
      if (newModeIsCreation)
        _.each(this.dataProvider.data,function(obj) {obj.clicked=false});
      this.selectedElement=null;
    },

    updateViewOnNewModeCreation:function(newModeIsCreation) {
      this.selectedElement = null;
      this.ui.lblEditAnnotationMode.empty().val('Creating new annotation....');

      var brush = this.$el.find('rect.extent');
      if (newModeIsCreation) {
        this.ui.btnCreateNewAnnotation.addClass('active');
        brush.attr('class','extent creation-mode');
        this.$el.find('.viewport').css('display','auto');
        this.ui.confirmAnnotationCreationForm.removeClass('hidden');
      }
      else {
        this.ui.btnCreateNewAnnotation.removeClass('active');
        brush.attr('class','extent');
        this.$el.find('.viewport').css('display','none');
        this.ui.confirmAnnotationCreationForm.addClass('hidden');
      }
      this.isModeCreation = newModeIsCreation;
    },

    onClickConfirmCreateAnnotation:function() {

        if (!this.selectedDatesForAnnotation || this.selectedDatesForAnnotation.length!=2)
          return;
        var self=this,
            txt = this.ui.inputContentAnnotation.val(),
            timeStart = this.selectedDatesForAnnotation[0],
            timeEnd = this.selectedDatesForAnnotation[1];

        if (txt.length<1)
            return;
        if (this.isModeCreation) {
          A._i.getOnCfg('annotationControlller').postAnnotation(this.resultAnalysis,timeStart,timeEnd,
            txt,function() {
              self.dataProvider.updateFromServer(self,self.resultAnalysis);

              (_.bind(self.updateViewOnNewModeCreation,self))();
            });
        }

    },

      ////////////////////////////////////////////////////////////////////////////////////
    //Function to check the data clicked and compute heights / y
    computeHeightElementsOnData:function(data) {
      if(!data)
        data = this.dataProvider.data;
      var numTotalData = data.length;
      var numClickedData = 0;
      _.each(data,function(_data) {if (_data.clicked) numClickedData++});
      //Clicked  elements weight twice more than non clicked
      var numDivision = numClickedData*2 + (numTotalData-numClickedData );

      var heightPerDivision = Math.floor(this.height/numDivision);

      var currentY = 0;
      _.each(data,function(_data) {
        _data.computed_height = _data.clicked ? 2*heightPerDivision : heightPerDivision;
        _data.computed_y = currentY;
        currentY+=_data.computed_height;

      });
      console.log(numClickedData, numTotalData,numDivision,data);
      return data;
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Generate graph
    /*Base chart creation*/
    createGraphicBase:function() {
      var height = this.height;
      var width = this.width;

      var node = d3.select(this.$el.find('.container_track_annotations > .svg')[0]).append("svg")
        .attr("class","chart")
        .attr("width", width)
        .attr("height", height);

      var chart = node.attr("width", width).attr("height", height);
      this.d3chart = chart;

      this.yScale = d3.scale.linear().domain([0,this.dataProvider.data.length]).range([0, height]);
      this.xScale = d3.time.scale().domain([0,this.item.get('audio_duration')*1000]).range([0,width]);

      var chart = node.attr("width", width).attr("height", height);
      this.d3chart = chart;

      /*var xAxis = d3.svg.axis()
          .scale(this.xScale)
          .orient('bottom')
          .ticks(5);

      this.axis = xAxis;

      this.d3chart.call(xAxis);*/
    },

    createBrush:function() {
      var height = this.height, width = this.width, chart = this.d3chart;

      this.viewport = d3.svg.brush()
        .x(this.xScale)
        /*.y(this.yScale)*/
        .on("brush", _.bind(this.brushed,this));

      chart.append("g")
        .attr("class", "viewport")
        .call(this.viewport)
        .selectAll("rect")
        .attr("height", this.height-50)
        .attr('transform', 'translate(0,'+25+')');

      //we do not start in creation mode
      this.$el.find('.viewport').css('display','none');
    },

    /////////////////////////////////////////////////////////////////////////////////////
    //new window navigator

    //here : trackinfo is already updated
    onNavigatorNewWindow:function() {
      //new window selected!
      //if (! this.hadFirstData)
      //  return;

      //UPDATE BRUSH
      /**
          brush.extent([new Date(2000),new Date(3000)]); &&
          chart.call(brush);
              font quelque chose mais wtf?
      **/

      console.log('onNavigatorNewWindow');
      var time0 =  A._i.getOnCfg('trackInfoController').currentStartTime;
      var time1 =  A._i.getOnCfg('trackInfoController').currentEndTime;

      this.xScale = d3.time.scale().domain([time0,time1]).range([0,this.width]);
      this.viewport.x(this.xScale);

      //update brush scale
      if (this.lastBrushData) {
        this.viewport.extent(this.lastBrushData);
        this.d3chart.call(this.viewport);
      }

      //console.log('Duration is : '+(time1-time0));
      //this.zoom.scale()

      //this.axis.scale(this.xScale);
      //this.d3chart.call(this.axis);
      var data = this.dataProvider.data;
      //B : REMOVING

      //1 8 FILTER DATA TO HAVE THOSE IN THE TIME RAHGE
      var filtered = data.filter(function(d){
        if(
          (d.start <= time0 && d.end>=time0)    // end of annotation is inside
          || (d.start >= time0 && d.end<=time1) // all anotation inside
          || (d.start < time1 && d.end>=time1)  // start of annotation is inside
        ) {
          return true;
        }
        return false;
      });

      //2 MAGIC HEIGHT FROM ERIC
      filtered = this.computeHeightElementsOnData(filtered);

      //BIND DATA TO ELEMENTS
      var self=this;
      var g = this.d3chart.selectAll("g.annotation").data(filtered, function(d) { return d.start; });
      //REMOVE OUT OF SCOPE
      g.exit().remove();
      //ADD NEW
      var newG = g.enter()
        .append("g")
        .attr('class','annotation')
        .attr("style", function(d) {
           return "clip-path: url(#"+("mettre-id-unique-ici"+d.start)+");";
        })
        .on('click',_.bind(self.onClickElement,self));

      //Add the clip path on this annotation
      newG.append("defs").append("clipPath")
        .attr("id", function(d) {
          return "mettre-id-unique-ici"+d.start;
        }).append("rect");

      //the visible rectangle
      newG.append('rect')
        .attr("fill", function(d){
          return d.color;
        });

      //and the text
      newG.append('text')
        .attr('x',10)
        .text(function(d) {return d.label;})

      //UPDATE ALL REMAINING
      g.attr("class", function(d, i) {
          if(d.clicked) {
            return "annotation active";
          }
          return "annotation";

        })
        .attr("transform", function(d, i) {
          var translateX = self.xScale(d.start);
          var translateY = d.computed_y;// self.yScale(d.index);
          return "translate(" + translateX + ","+translateY+")";
        })
        .selectAll("rect")
         .attr("height", function(d) {
            console.log(d);
            return d.computed_height;
          })
          .attr("width", function(d) {
            var duration = d.end - d.start;
            var xScale = self.xScale(d.end) - self.xScale(d.start);
            return xScale;
          } );
          g.selectAll("text")
            .attr('y',function(d){
              return d.computed_height/2;
            })
    },

    ////////////////////////////////////////////////////////////////////////////////////
    initialize: function () {
      A._v.onCfg('navigator.newWindow','',this.onNavigatorNewWindow,this);
      this.item = A._i.getOnCfg('currentItem');
    },

    onRender:function() {
    },

    onDestroy: function () {
      A._v.offCfg('navigator.newWindow','',this.onNavigatorNewWindow,this);
    },

    serializeData: function () {
      var title = this.resultAnalysis ? this.resultAnalysis.get('title') : 'New Annotation track'

      return {
          title : title
      }
    }
  });
});
<commit_msg>(player/annotation) can resize existing annotation<commit_after>define([
  'marionette',
  '#qt_core/controllers/all',
  '#navigation_core/baseviews/base_qeopaview',
  'd3'
],

function (Marionette,A,BaseQeopaView,d3) {
  'use strict';

  /**
    Annotations track
      Méthodes à exposer :
        init(typeData)
          va récupérer les global datas, générer et afficher

      D3 :
        La data va être mappée en x selon le temps (avec durée)
        et en y, nous allons la mapper de 0 à n, l'index de la data

        En affichage, nous allons juste modifier le scale x pour le temps et le scale y de sorte que
        toute la hauteur soit prise par les barres visibles.

    intern vars
      isModeCreation : false/true
      selectedElement : null / object
  **/

  var DataProvider = Marionette.Controller.extend({
      init : function(annotationTrackObject) {

        this.data = [];

        if (annotationTrackObject) {
          _.each(annotationTrackObject.get('annotations'),function(annotation,index) {
              var dataOk = {
                start : annotation.start_time,
                end : annotation.stop_time,
                index : index,
                uuid : annotation.uuid,
                label : annotation.description,
                clicked : false,
                color :"#cf8e2a"
              }
              this.lastIndex = index;
              this.data.push(dataOk);
          },this);

          //console.error('TODO on annotation track object');
          return;
        }

       /* this.data = [];
        var numItem = 50;
        var stepPerItem = 200;
        for (var i=0; i<numItem;i++) {
          //toutes les secondes on met un truc de taille variable
          var size = 0.2+Math.random()*0.7;
          this.data.push({
            start:i*stepPerItem,
            end : i*stepPerItem+size*stepPerItem,
            index : i, label : "Annot_"+i,
            clicked : (i%3==0 ? true : false),
            color :"#cf8e2a"
          });
        }*/
      },

      //after create/edit/delete
      updateFromServer:function(view,model) {
        var self=this;
        A._i.getOnCfg('annotationControlller').udpateTrackDataFromServer(model,function(modelUpdated) {
          view.resultAnalysis = modelUpdated;
          self.init(modelUpdated);
          (_.bind(view.onNavigatorNewWindow,view))();
        });
      },

  });

  return BaseQeopaView.extend({

    template: templates['visu/sub_track_annotations'],
    className: 'track-annotations',

    ui: {
      btnCreateNewAnnotation : '[data-layout="create_new_annotation"]',
      confirmAnnotationCreationForm : '[data-layout="create_annotation_form"]',
      lblConfirmAnnotationCreation : '[data-layout="create_annotation_label"]',
      inputContentAnnotation : '[data-layout="annotation_content"]',
      lblEditAnnotationMode : '[data-layout="edit_annotation_mode"]',

      container : '.container_track_annotations'
    },
    events: {
      'click @ui.btnCreateNewAnnotation' : 'onClickCreateNewAnnotation',
      'click [data-layout="confirm_annotation_creation"]' : 'onClickConfirmCreateAnnotation',
      'mousemove .container_track_annotations' : 'onMouseMove',
       'mousedown .container_track_annotations' : 'onMouseDown',
      'mouseup .container_track_annotations' : 'onMouseUp',
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Definition //un peu con car sur les autres tracks, c'est au niveau du loader qu'on décide ça.
    isTrueDataServer : false,

    ////////////////////////////////////////////////////////////////////////////////////
    //Define
    /*input obj is {type : _type, width : width, height : height, trueData : true/false}*/
    defineTrack:function(o) {
      this.width = o.width;
      this.height = o.height;
      this.isTrueDataServer = o.trueData!==undefined ? o.trueData : false;

      this.resultAnalysis = o.resultAnalysis; //will be the annotation track object

      this.dataProvider = new DataProvider();
    },

    /**
      Init function : va récupérer les data globales et le specific data
    **/
    init:function() {
      this.dataProvider.init(this.resultAnalysis);
      this.createGraphicBase();
      this.createBrush();
      this.onNavigatorNewWindow();
      //this.generateGraphFromData();
      this.hadFirstData=true;
    },

     ////////////////////////////////////////////////////////////////////////////////////
    //Brush listener

    brushed:function(e1,e2,e3) {

      //console.log('new times : '+time1+','+time2);

      //var a = this.xScale.
      if (!this.isModeCreation)
        return;

      var a = (this.viewport.extent()[0]);
      var b = (this.viewport.extent()[1]);
      this.lastBrushData = this.viewport.extent();
      this.ui.lblConfirmAnnotationCreation.empty().append('From '+a.getTime()+" to "+b.getTime());
      this.selectedDatesForAnnotation = [a.getTime(),b.getTime()]
      console.log('brushed annot track : '+JSON.stringify(a)+" -> "+JSON.stringify(b));

    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Click listener
    onClickElement:function(d,i) {
      console.log('click ELEMENT!');

      _.each(this.dataProvider.data,function(obj) {obj.clicked=false});

      d.clicked = true;//!d.clicked;
      this.selectedElement = d;
      this.updateViewEditAnnotation();
      this.onNavigatorNewWindow();
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Listen for mouse over - always on, but used only when we have a selected element
    onMouseMove:function(ev) {
      console.log('Mouse over...'+ev.pageX);
      var timeForMouse = this.xScale.invert(ev.pageX);
      if (!this.selectedElement)
        return;

      if (this.isMouseDownForResizingAnnotation) {
        //resizing an annotation
        var newTime = this.xScale.invert(ev.pageX);
        if (this.isResizingLowerBound)
          this.selectedElement.start = newTime.getTime();
        else
          this.selectedElement.end = newTime.getTime();

        console.log(' new time while selecting : '+newTime.getTime());
        this.ui.lblConfirmAnnotationCreation.empty().append('From '+this.selectedElement.start+" to "+this.selectedElement.end);

        this.onNavigatorNewWindow();
        return;
      }

      var lowerBound = this.selectedElement.start+0.1*(this.selectedElement.end - this.selectedElement.start);
      var upperBound = this.selectedElement.end - 0.1*(this.selectedElement.end - this.selectedElement.start);
      var inBounds=false, isMovingLowerBound = false;
      if (timeForMouse<lowerBound && timeForMouse > this.selectedElement.start) {
        inBounds=true;isMovingLowerBound=true;
        this.ui.container.css('cursor','row-resize');
      }
      else if (timeForMouse>upperBound && timeForMouse < this.selectedElement.end) {
        inBounds=true;isMovingLowerBound=false;
        this.ui.container.css('cursor','row-resize');
      }
      else {
        this.ui.container.css('cursor','default');
      }

      console.log('   comps : ['+this.selectedElement.start+","+lowerBound+" -> "+upperBound+","+this.selectedElement.end);

      this.canResizeAnnotation = inBounds;
      this.isResizingLowerBound = isMovingLowerBound;

    },

    onMouseDown:function(ev) {
      if (!this.selectedElement)
        return;
      if (!this.canResizeAnnotation)
        return;

      this.timeBaseForResize = this.xScale.invert(ev.pageX);
      this.isMouseDownForResizingAnnotation=true;
    },

    onMouseUp:function(ev) {
      this.isMouseDownForResizingAnnotation=false;
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Mode to edit an annotation
    updateViewEditAnnotation:function() {
      if (this.isModeCreation) {
        this.updateViewOnNewModeCreation(false);
      }
      var element = this.selectedElement;
      if (!element) {
        return console.error('ERROR : no selected element on updateViewEditAnnotation')
      }
      this.ui.lblEditAnnotationMode.empty()
      this.ui.lblEditAnnotationMode.append('Edit '+element.uuid);
      this.ui.confirmAnnotationCreationForm.removeClass('hidden');
      this.ui.lblConfirmAnnotationCreation.empty().append('From '+element.start+" to "+element.end);
      this.ui.inputContentAnnotation.val(element.label);
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Button to toggle creation mode
    onClickCreateNewAnnotation:function() {
      var newModeIsCreation = ! this.isModeCreation;
      this.updateViewOnNewModeCreation(newModeIsCreation);
      if (newModeIsCreation)
        _.each(this.dataProvider.data,function(obj) {obj.clicked=false});
      this.selectedElement=null;
    },

    updateViewOnNewModeCreation:function(newModeIsCreation) {
      this.selectedElement = null;
      this.ui.lblEditAnnotationMode.empty().val('Creating new annotation....');

      var brush = this.$el.find('rect.extent');
      if (newModeIsCreation) {
        this.ui.btnCreateNewAnnotation.addClass('active');
        brush.attr('class','extent creation-mode');
        this.$el.find('.viewport').css('display','auto');
        this.ui.confirmAnnotationCreationForm.removeClass('hidden');
      }
      else {
        this.ui.btnCreateNewAnnotation.removeClass('active');
        brush.attr('class','extent');
        this.$el.find('.viewport').css('display','none');
        this.ui.confirmAnnotationCreationForm.addClass('hidden');
      }
      this.isModeCreation = newModeIsCreation;
    },

    onClickConfirmCreateAnnotation:function() {

        if (!this.selectedDatesForAnnotation || this.selectedDatesForAnnotation.length!=2)
          return;
        var self=this,
            txt = this.ui.inputContentAnnotation.val(),
            timeStart = this.selectedDatesForAnnotation[0],
            timeEnd = this.selectedDatesForAnnotation[1];

        if (txt.length<1)
            return;
        if (this.isModeCreation) {
          A._i.getOnCfg('annotationControlller').postAnnotation(this.resultAnalysis,timeStart,timeEnd,
            txt,function() {
              self.dataProvider.updateFromServer(self,self.resultAnalysis);

              (_.bind(self.updateViewOnNewModeCreation,self))();
            });
        }

    },

      ////////////////////////////////////////////////////////////////////////////////////
    //Function to check the data clicked and compute heights / y
    computeHeightElementsOnData:function(data) {
      if(!data)
        data = this.dataProvider.data;
      var numTotalData = data.length;
      var numClickedData = 0;
      _.each(data,function(_data) {if (_data.clicked) numClickedData++});
      //Clicked  elements weight twice more than non clicked
      var numDivision = numClickedData*2 + (numTotalData-numClickedData );

      var heightPerDivision = Math.floor(this.height/numDivision);

      var currentY = 0;
      _.each(data,function(_data) {
        _data.computed_height = _data.clicked ? 2*heightPerDivision : heightPerDivision;
        _data.computed_y = currentY;
        currentY+=_data.computed_height;

      });
      //console.log(numClickedData, numTotalData,numDivision,data);
      return data;
    },

    ////////////////////////////////////////////////////////////////////////////////////
    //Generate graph
    /*Base chart creation*/
    createGraphicBase:function() {
      var height = this.height;
      var width = this.width;

      var node = d3.select(this.$el.find('.container_track_annotations > .svg')[0]).append("svg")
        .attr("class","chart")
        .attr("width", width)
        .attr("height", height);

      var chart = node.attr("width", width).attr("height", height);
      this.d3chart = chart;

      this.yScale = d3.scale.linear().domain([0,this.dataProvider.data.length]).range([0, height]);
      this.xScale = d3.time.scale().domain([0,this.item.get('audio_duration')*1000]).range([0,width]);

      var chart = node.attr("width", width).attr("height", height);
      this.d3chart = chart;

      /*var xAxis = d3.svg.axis()
          .scale(this.xScale)
          .orient('bottom')
          .ticks(5);

      this.axis = xAxis;

      this.d3chart.call(xAxis);*/
    },

    createBrush:function() {
      var height = this.height, width = this.width, chart = this.d3chart;

      this.viewport = d3.svg.brush()
        .x(this.xScale)
        /*.y(this.yScale)*/
        .on("brush", _.bind(this.brushed,this));

      chart.append("g")
        .attr("class", "viewport")
        .call(this.viewport)
        .selectAll("rect")
        .attr("height", this.height-50)
        .attr('transform', 'translate(0,'+25+')');

      //we do not start in creation mode
      this.$el.find('.viewport').css('display','none');
    },

    /////////////////////////////////////////////////////////////////////////////////////
    //new window navigator

    //here : trackinfo is already updated
    onNavigatorNewWindow:function() {
      //new window selected!
      //if (! this.hadFirstData)
      //  return;

      //UPDATE BRUSH
      /**
          brush.extent([new Date(2000),new Date(3000)]); &&
          chart.call(brush);
              font quelque chose mais wtf?
      **/

      console.log('onNavigatorNewWindow');
      var time0 =  A._i.getOnCfg('trackInfoController').currentStartTime;
      var time1 =  A._i.getOnCfg('trackInfoController').currentEndTime;

      this.xScale = d3.time.scale().domain([time0,time1]).range([0,this.width]);
      this.viewport.x(this.xScale);

      //update brush scale
      if (this.lastBrushData) {
        this.viewport.extent(this.lastBrushData);
        this.d3chart.call(this.viewport);
      }

      //console.log('Duration is : '+(time1-time0));
      //this.zoom.scale()

      //this.axis.scale(this.xScale);
      //this.d3chart.call(this.axis);
      var data = this.dataProvider.data;
      //B : REMOVING

      //1 8 FILTER DATA TO HAVE THOSE IN THE TIME RAHGE
      var filtered = data.filter(function(d){
        if(
          (d.start <= time0 && d.end>=time0)    // end of annotation is inside
          || (d.start >= time0 && d.end<=time1) // all anotation inside
          || (d.start < time1 && d.end>=time1)  // start of annotation is inside
        ) {
          return true;
        }
        return false;
      });

      //2 MAGIC HEIGHT FROM ERIC
      filtered = this.computeHeightElementsOnData(filtered);

      //BIND DATA TO ELEMENTS
      var self=this;
      var g = this.d3chart.selectAll("g.annotation").data(filtered, function(d) { return d.start; });
      //REMOVE OUT OF SCOPE
      g.exit().remove();
      //ADD NEW
      var newG = g.enter()
        .append("g")
        .attr('class','annotation')
        .attr("style", function(d) {
           return "clip-path: url(#"+("mettre-id-unique-ici"+d.start)+");";
        })
        .on('click',_.bind(self.onClickElement,self));

      //Add the clip path on this annotation
      newG.append("defs").append("clipPath")
        .attr("id", function(d) {
          return "mettre-id-unique-ici"+d.start;
        }).append("rect");

      //the visible rectangle
      newG.append('rect')
        .attr("fill", function(d){
          return d.color;
        });

      //and the text
      newG.append('text')
        .attr('x',10)
        .text(function(d) {return d.label;})

      //UPDATE ALL REMAINING
      g.attr("class", function(d, i) {
          if(d.clicked) {
            return "annotation active";
          }
          return "annotation";

        })
        .attr("transform", function(d, i) {
          var translateX = self.xScale(d.start);
          var translateY = d.computed_y;// self.yScale(d.index);
          return "translate(" + translateX + ","+translateY+")";
        })
        .selectAll("rect")
         .attr("height", function(d) {
            //console.log(d);
            return d.computed_height;
          })
          .attr("width", function(d) {
            var duration = d.end - d.start;
            var xScale = self.xScale(d.end) - self.xScale(d.start);
            return xScale;
          } );
          g.selectAll("text")
            .attr('y',function(d){
              return d.computed_height/2;
            })
    },

    ////////////////////////////////////////////////////////////////////////////////////
    initialize: function () {
      A._v.onCfg('navigator.newWindow','',this.onNavigatorNewWindow,this);
      this.item = A._i.getOnCfg('currentItem');
    },

    onRender:function() {
    },

    onDestroy: function () {
      A._v.offCfg('navigator.newWindow','',this.onNavigatorNewWindow,this);
    },

    serializeData: function () {
      var title = this.resultAnalysis ? this.resultAnalysis.get('title') : 'New Annotation track'

      return {
          title : title
      }
    }
  });
});
<|endoftext|>


<commit_before>// Find the element where the commit timeline should be drawn
var commits = d3.select("#commits");

var orgName = commits.attr("orgName") || "JavaPosseRoundup";
var startDate = commits.attr("startDate") || "";
var width = commits.attr("width") || 1200;
var height = commits.attr("height") || 600;
var leftMargin = commits.attr("leftMargin") || 180;
var rightMargin = commits.attr("rightMargin") || 0;
var topMargin = commits.attr("topMargin") || 20;
var bottomMargin = commits.attr("bottomMargin") || 50;

var w = width - leftMargin - rightMargin,
    h = height - topMargin - bottomMargin;

// Scales. Note the inverted domain for the y-scale: bigger is up!
var x = d3.time.scale().rangeRound([0, w]),
    y = d3.scale.ordinal().rangePoints([0, h], .5),
    colors = d3.scale.category20();

// Axes.
var xAxis = d3.svg.axis().scale(x).tickSubdivide(true);
var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left");

// Add an SVG element with the desired dimensions and margin.
var svg = commits.append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + leftMargin + "," + topMargin + ")");

// Add the clip path.
svg.append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", w)
    .attr("height", h + 20);

// Need something in the background absorb the mouse events!
svg.append("rect")
    .attr("width", w)
    .attr("height", h)
    .style("fill", "#fff");

$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) {
  var allCommits = [];
  var timelines = [];
  response.data.forEach(function(repo, i, array) {
    function gitSource(repo) {
      return repo.url + "/commits?callback=?";
    }
    $.getJSON(gitSource(repo), function(response) {
      var commits = response.data.map(function(r) {
        return {
          repo: repo.name,
          message: r.commit.message,
          authorDate: d3.time.format.iso.parse(r.commit.author.date),
          committerEmail: r.commit.committer.email,
          committerName: r.commit.committer.name,
          commitDate: d3.time.format.iso.parse(r.commit.committer.date),
          sha: r.sha
        }
      });
      var timeline = {
        repo: repo.name,
        earliest: commits[commits.length - 1].commitDate,
        latest: commits[0].commitDate
      };
      allCommits.push.apply(allCommits, commits);
      timelines.push(timeline);
      if (timelines.length == array.length) drawChart(allCommits, timelines);
    });
  });
});

function drawChart(allCommits, timelines) {

  var tickHeight = height / (timelines.length * 4 + 1);

  var earliestCommitDate = d3.min(timelines, function(d) { return d.earliest; });

  var start = d3.time.format("%Y-%m-%d").parse(startDate) || earliestCommitDate;

  x.domain([d3.time.day.floor(start), d3.time.day.ceil(new Date())]);

  y.domain(timelines.map(function(t) { return t.repo; }));

  // Add the x-axis.
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h + 20) + ")")
    .call(xAxis);

  // Add the y-axis.
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

  svg.selectAll(".commit")
      .data(allCommits)
    .enter().append("line")
      .attr("class", "commit")
      .attr("clip-path", "url(#clip)")
      .attr("x1", function(d) { return x(d.commitDate); })
      .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; })
      .attr("x2", function(d) { return x(d.commitDate); })
      .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; })
      .style("stroke", function(d) { return colors(d.committerEmail); })
      .on("mouseover", showCommitInfo);

  svg.selectAll(".timeline")
      .data(timelines)
    .enter().append("line")
      .attr("class", "timeline")
      .attr("clip-path", "url(#clip)")
      .attr("x1", function(d) { return x(d.earliest); })
      .attr("y1", function(d) { return Math.floor(y(d.repo)); })
      .attr("x2", function(d) { return x(d.latest); })
      .attr("y2", function(d) { return Math.floor(y(d.repo)); });

  svg.call(d3.behavior.zoom().x(x).on("zoom", zoom));

  function zoom() {
    svg.select(".x.axis").call(xAxis);
    svg.selectAll(".commit")
      .data(allCommits)
      .attr("x1", function(d) { return x(d.commitDate); })
      .attr("x2", function(d) { return x(d.commitDate); });
    svg.selectAll(".timeline")
      .data(timelines)
      .attr("x1", function(d) { return x(d.earliest); })
      .attr("x2", function(d) { return x(d.latest); });
    svg.selectAll(".committer, .message")
      .attr("x", function(d) { return x(d.commitDate); });
  }

  function showCommitInfo(d, i) {

    var committer = svg.selectAll(".committer")
      .data([d], function(d) { return d.sha; });

    committer.enter().append("text")
      .attr("class", "committer")
      .attr("x", x(d.commitDate))
      .attr("y", y(d.repo))
      .attr("dx", -2)
      .attr("dy", 2 * tickHeight + 5)
      .attr("text-anchor", "end")
      .style("fill", colors(d.committerEmail))
      .text(d.committerName);

    committer.exit().remove();

    var message = svg.selectAll(".message")
      .data([d], function(d) { return d.sha; });

    message.enter().append("text")
      .attr("class", "message")
      .attr("x", x(d.commitDate))
      .attr("y", y(d.repo))
      .attr("dx", 2)
      .attr("dy", 2 * tickHeight + 5)
      .text(d.message);

    message.exit().remove();
  }

}
<commit_msg>Make the background, which is only there to catch mouse events, transparent<commit_after>// Find the element where the commit timeline should be drawn
var commits = d3.select("#commits");

var orgName = commits.attr("orgName") || "JavaPosseRoundup";
var startDate = commits.attr("startDate") || "";
var width = commits.attr("width") || 1200;
var height = commits.attr("height") || 600;
var leftMargin = commits.attr("leftMargin") || 180;
var rightMargin = commits.attr("rightMargin") || 0;
var topMargin = commits.attr("topMargin") || 20;
var bottomMargin = commits.attr("bottomMargin") || 50;

var w = width - leftMargin - rightMargin,
    h = height - topMargin - bottomMargin;

// Scales. Note the inverted domain for the y-scale: bigger is up!
var x = d3.time.scale().rangeRound([0, w]),
    y = d3.scale.ordinal().rangePoints([0, h], .5),
    colors = d3.scale.category20();

// Axes.
var xAxis = d3.svg.axis().scale(x).tickSubdivide(true);
var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left");

// Add an SVG element with the desired dimensions and margin.
var svg = commits.append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + leftMargin + "," + topMargin + ")");

// Add the clip path.
svg.append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", w)
    .attr("height", h + 20);

// Need something in the background absorb the mouse events!
svg.append("rect")
    .attr("width", w)
    .attr("height", h)
    .style("fill-opacity", ".0");

$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) {
  var allCommits = [];
  var timelines = [];
  response.data.forEach(function(repo, i, array) {
    function gitSource(repo) {
      return repo.url + "/commits?callback=?";
    }
    $.getJSON(gitSource(repo), function(response) {
      var commits = response.data.map(function(r) {
        return {
          repo: repo.name,
          message: r.commit.message,
          authorDate: d3.time.format.iso.parse(r.commit.author.date),
          committerEmail: r.commit.committer.email,
          committerName: r.commit.committer.name,
          commitDate: d3.time.format.iso.parse(r.commit.committer.date),
          sha: r.sha
        }
      });
      var timeline = {
        repo: repo.name,
        earliest: commits[commits.length - 1].commitDate,
        latest: commits[0].commitDate
      };
      allCommits.push.apply(allCommits, commits);
      timelines.push(timeline);
      if (timelines.length == array.length) drawChart(allCommits, timelines);
    });
  });
});

function drawChart(allCommits, timelines) {

  var tickHeight = height / (timelines.length * 4 + 1);

  var earliestCommitDate = d3.min(timelines, function(d) { return d.earliest; });

  var start = d3.time.format("%Y-%m-%d").parse(startDate) || earliestCommitDate;

  x.domain([d3.time.day.floor(start), d3.time.day.ceil(new Date())]);

  y.domain(timelines.map(function(t) { return t.repo; }));

  // Add the x-axis.
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h + 20) + ")")
    .call(xAxis);

  // Add the y-axis.
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

  svg.selectAll(".commit")
      .data(allCommits)
    .enter().append("line")
      .attr("class", "commit")
      .attr("clip-path", "url(#clip)")
      .attr("x1", function(d) { return x(d.commitDate); })
      .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; })
      .attr("x2", function(d) { return x(d.commitDate); })
      .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; })
      .style("stroke", function(d) { return colors(d.committerEmail); })
      .on("mouseover", showCommitInfo);

  svg.selectAll(".timeline")
      .data(timelines)
    .enter().append("line")
      .attr("class", "timeline")
      .attr("clip-path", "url(#clip)")
      .attr("x1", function(d) { return x(d.earliest); })
      .attr("y1", function(d) { return Math.floor(y(d.repo)); })
      .attr("x2", function(d) { return x(d.latest); })
      .attr("y2", function(d) { return Math.floor(y(d.repo)); });

  svg.call(d3.behavior.zoom().x(x).on("zoom", zoom));

  function zoom() {
    svg.select(".x.axis").call(xAxis);
    svg.selectAll(".commit")
      .data(allCommits)
      .attr("x1", function(d) { return x(d.commitDate); })
      .attr("x2", function(d) { return x(d.commitDate); });
    svg.selectAll(".timeline")
      .data(timelines)
      .attr("x1", function(d) { return x(d.earliest); })
      .attr("x2", function(d) { return x(d.latest); });
    svg.selectAll(".committer, .message")
      .attr("x", function(d) { return x(d.commitDate); });
  }

  function showCommitInfo(d, i) {

    var committer = svg.selectAll(".committer")
      .data([d], function(d) { return d.sha; });

    committer.enter().append("text")
      .attr("class", "committer")
      .attr("x", x(d.commitDate))
      .attr("y", y(d.repo))
      .attr("dx", -2)
      .attr("dy", 2 * tickHeight + 5)
      .attr("text-anchor", "end")
      .style("fill", colors(d.committerEmail))
      .text(d.committerName);

    committer.exit().remove();

    var message = svg.selectAll(".message")
      .data([d], function(d) { return d.sha; });

    message.enter().append("text")
      .attr("class", "message")
      .attr("x", x(d.commitDate))
      .attr("y", y(d.repo))
      .attr("dx", 2)
      .attr("dy", 2 * tickHeight + 5)
      .text(d.message);

    message.exit().remove();
  }

}
<|endoftext|>


<commit_before>var rest = require('./rest');

var company = function (id, cb) {

    var companyId = id;

    //if a callback is provided...
    if (typeof cb === 'function') {
        rest.fetch(process.env.API_URL, 'people/' + companyId, process.env.API_KEY, cb);
        return;
    }

    var user = function (userId, cb) {
        //if a callback is provided...
        if (typeof cb === 'function') {
            var endpoint = 'people/' + companyId + '/users/' + userId;
            rest.fetch(process.env.API_URL, endpoint, process.env.API_KEY, cb);
            return;
        }
        //otherwise, return a chaining ob;ect
        return {
            'edit': function (data, cb) {
                var endpoint = 'people/' + companyId + '/users/' + userId + '/edit-profile';
                rest.edit(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
            }
        };
    };

    user.add = function (data, cb) {
        var endpoint = 'people/' + companyId + '/add-user';
        rest.create(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
    };

    //otherwise, return a chaining ob;ect
    return {
        'user': user,
        'edit': function (data, cb) {
            var endpoint = 'people/' + companyId + '/edit';
            rest.edit(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
        }
    };
};

company.add = function (data, cb) {
    var endpoint = 'people/add-company';
    rest.create(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
};

module.exports = company;<commit_msg>Spelling mistake fix<commit_after>var rest = require('./rest');

var company = function (id, cb) {

    var companyId = id;

    //if a callback is provided...
    if (typeof cb === 'function') {
        rest.fetch(process.env.API_URL, 'people/' + companyId, process.env.API_KEY, cb);
        return;
    }

    var user = function (userId, cb) {
        //if a callback is provided...
        if (typeof cb === 'function') {
            var endpoint = 'people/' + companyId + '/users/' + userId;
            rest.fetch(process.env.API_URL, endpoint, process.env.API_KEY, cb);
            return;
        }
        //otherwise, return a chaining object
        return {
            'edit': function (data, cb) {
                var endpoint = 'people/' + companyId + '/users/' + userId + '/edit-profile';
                rest.edit(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
            }
        };
    };

    user.add = function (data, cb) {
        var endpoint = 'people/' + companyId + '/add-user';
        rest.create(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
    };

    //otherwise, return a chaining ob;ect
    return {
        'user': user,
        'edit': function (data, cb) {
            var endpoint = 'people/' + companyId + '/edit';
            rest.edit(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
        }
    };
};

company.add = function (data, cb) {
    var endpoint = 'people/add-company';
    rest.create(process.env.API_URL, endpoint, process.env.API_KEY, data, cb);
};

module.exports = company;<|endoftext|>


<commit_before>angular.module('materialscommons').factory("processEdit", processEdit);

function processEdit() {
    /**
     * fillSetUp: will read all the setup values from process
     * and place inside template.
     *
     */
    function setUp(template, process) {
        process.setup[0].properties.forEach(function(property) {
            var i = _.indexOf(template.setup[0].properties, function(template_property) {
                return template_property.property.attribute === property.attribute
            });
            if (i > -1) {
                template.setup[0].properties[i].property.value = property.value;
                template.setup[0].properties[i].property.name = property.name;
                template.setup[0].properties[i].property.description = property.description;
                template.setup[0].properties[i].property.unit = property.unit;
                template.setup[0].properties[i].property.id = property.id;
                template.setup[0].properties[i].property.setup_id = property.setup_id;
                template.setup[0].properties[i].property.otype = property.otype;
                template.setup[0].properties[i].property.attribute = property.attribute;

                // If selection type then modify the choices when Other is selected, since the
                // user may have modified the value of other. We need to do this otherwise the
                // default other in the choices will update the value and the user will lose what
                // they set.
                if (property.otype === 'selection') {
                    if (property.value.name === 'Other') {
                        let otherChoicesIndex = _.indexOf(template.setup[0].properties[i].property.choices,
                            (c) => c.name === 'Other');
                        if (otherChoicesIndex !== -1) {
                            template.setup[0].properties[i].property.choices[otherChoicesIndex].value = property.value.value;
                        }
                    }
                }
            }
        });
        process.setup = template.setup;
        return process;
    }

    function samples(process) {
        //process.input_samples = process.input_samples;
        return process;
    }

    function files(process) {
        //process['input_files'] = process.input_files.map(function(file) {
        //    return {id: file.id, name: file.name}
        //});
        //process['output_files'] = process.output_files.map(function(file) {
        //    return {id: file.id, name: file.name}
        //});
        return process;
    }

    function addCompositionToMeasurements(prop, measurements) {
        for (let i = 0; i < measurements.length; i++) {
            let measurement = measurements[i];
            if (measurement.property.attribute === 'composition') {
                measurement.property.unit = prop.unit;
                measurement.property.value = prop.value;
                break;
            }
        }
    }

    function setupMeasurements(process, templateMeasurements, template) {
        if (template.category === 'create_samples') {
            // Hack, just extract the composition from one of the samples to display as the measurements.
            let foundComposition = false;
            for (let i = 0; i < process.output_samples.length; i++) {
                let sample = process.output_samples[i];
                for (let k = 0; k < sample.properties.length; k++) {
                    let prop = sample.properties[k];
                    if (prop.attribute === 'composition') {
                        addCompositionToMeasurements(prop.best_measure[0], templateMeasurements);
                        foundComposition = true;
                    }
                }
                if (foundComposition) {
                    break;
                }
            }
        }
        process.measurements = templateMeasurements;
    }

    return {
        fillProcess: function(template, process) {
            console.log('fillProcess', template, process.plain());
            process.measurements = [];
            return process;
            process = setUp(template, process);
            process = samples(process);
            process = files(process);
            setupMeasurements(process, template.measurements, template);
            if (!('output_samples' in process)) {
                process.output_samples = [];
            }
            if (!('transformed_samples' in process)) {
                process.transformed_samples = [];
            }
            return process;
        },

        addToSamplesFiles: function(files, process) {
            files.forEach(function(f) {
                var i = _.indexOf(process.samples_files, function(item) {
                    return f.id === item.id && f.sample_id == item.sample_id;
                });
                if (i !== -1) {
                    process.samples_files.splice(i, 1);
                    process.samples_files.push({
                        id: f.id,
                        command: f.command,
                        name: f.name,
                        sample_id: f.sample_id
                    });
                } else {
                    if (f.command) {
                        process.samples_files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id
                        });
                    }
                }
            });
            return process;
        },

        refreshSample: function(files, sample) {
            files.forEach(function(f) {
                if (f.command) {
                    var i = _.indexOf(sample.files, function(item) {
                        return f.id === item.id && f.sample_id == sample.id;
                    });
                    if (i !== -1) {
                        sample.files.splice(i, 1);
                        sample.files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id,
                            linked: f.linked
                        });
                    } else {
                        sample.files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id,
                            linked: f.linked
                        });
                    }
                }
            });
            return sample;
        }
    };
}
<commit_msg>Added code to process-edit.service ot 'fill in' meiiing unit and units values<commit_after>angular.module('materialscommons').factory("processEdit", processEdit);

function processEdit() {
    /**
     * fillSetUp: will read all the setup values from process
     * and place inside template.
     *
     */
    function setUp(template, process) {
        process.setup[0].properties.forEach(function(property) {
            var i = _.indexOf(template.setup[0].properties, function(template_property) {
                return template_property.property.attribute === property.attribute
            });
            if (i > -1) {
                template.setup[0].properties[i].property.value = property.value;
                template.setup[0].properties[i].property.name = property.name;
                template.setup[0].properties[i].property.description = property.description;
                template.setup[0].properties[i].property.unit = property.unit;
                template.setup[0].properties[i].property.id = property.id;
                template.setup[0].properties[i].property.setup_id = property.setup_id;
                template.setup[0].properties[i].property.otype = property.otype;
                template.setup[0].properties[i].property.attribute = property.attribute;

                // If selection type then modify the choices when Other is selected, since the
                // user may have modified the value of other. We need to do this otherwise the
                // default other in the choices will update the value and the user will lose what
                // they set.
                if (property.otype === 'selection') {
                    if (property.value.name === 'Other') {
                        let otherChoicesIndex = _.indexOf(template.setup[0].properties[i].property.choices,
                            (c) => c.name === 'Other');
                        if (otherChoicesIndex !== -1) {
                            template.setup[0].properties[i].property.choices[otherChoicesIndex].value = property.value.value;
                        }
                    }
                }
            }
        });
        process.setup = template.setup;
        return process;
    }

    function samples(process) {
        //process.input_samples = process.input_samples;
        return process;
    }

    function files(process) {
        //process['input_files'] = process.input_files.map(function(file) {
        //    return {id: file.id, name: file.name}
        //});
        //process['output_files'] = process.output_files.map(function(file) {
        //    return {id: file.id, name: file.name}
        //});
        return process;
    }

    function addCompositionToMeasurements(prop, measurements) {
        for (let i = 0; i < measurements.length; i++) {
            let measurement = measurements[i];
            if (measurement.property.attribute === 'composition') {
                measurement.property.unit = prop.unit;
                measurement.property.value = prop.value;
                break;
            }
        }
    }

    function setupMeasurements(process, templateMeasurements, template) {
        if (template.category === 'create_samples') {
            // Hack, just extract the composition from one of the samples to display as the measurements.
            let foundComposition = false;
            for (let i = 0; i < process.output_samples.length; i++) {
                let sample = process.output_samples[i];
                for (let k = 0; k < sample.properties.length; k++) {
                    let prop = sample.properties[k];
                    if (prop.attribute === 'composition') {
                        addCompositionToMeasurements(prop.best_measure[0], templateMeasurements);
                        foundComposition = true;
                    }
                }
                if (foundComposition) {
                    break;
                }
            }
        }
        process.measurements = templateMeasurements;
    }

    function repairUnitsLists(template,process){
        let template_props = template.setup[0].properties;
        let process_props = process.setup[0].properties;
        for (var i = 0; i < template_props.length; i++){
            let tprop = template_props[i].property;
            for (var j = 0; j < process_props.length; j++) {
                let prop = process_props[j];
                if (tprop.attribute == prop.attribute){
                    if (tprop.units) {
                        prop.units = tprop.units
                    }
                    if (tprop.unit) {
                        prop.unit = tprop.unit
                    }
                }
            }
        }
        return process;
    }

    return {
        fillProcess: function(template, process) {
            console.log('fillProcess - enter', template, process.plain());
            process.measurements = [];
            // NOTE: code assumes that units arrya/list exists, and may be empty.
            //       This should be set on the server side, but is not,
            //       see issue #895 on materialscommons.org github project.
            process = repairUnitsLists(template, process);
            console.log('fillProcess - leave', template, process.plain());

            // NOTE: the following are part of future development
            //        and have been disabled for now
            //
            //process = setUp(template, process);
            //process = samples(process);
            //process = files(process);
            //setupMeasurements(process, template.measurements, template);
            //if (!('output_samples' in process)) {
            //    process.output_samples = [];
            //}
            //if (!('transformed_samples' in process)) {
            //    process.transformed_samples = [];
            //}
            return process;
        },

        addToSamplesFiles: function(files, process) {
            files.forEach(function(f) {
                var i = _.indexOf(process.samples_files, function(item) {
                    return f.id === item.id && f.sample_id == item.sample_id;
                });
                if (i !== -1) {
                    process.samples_files.splice(i, 1);
                    process.samples_files.push({
                        id: f.id,
                        command: f.command,
                        name: f.name,
                        sample_id: f.sample_id
                    });
                } else {
                    if (f.command) {
                        process.samples_files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id
                        });
                    }
                }
            });
            return process;
        },

        refreshSample: function(files, sample) {
            files.forEach(function(f) {
                if (f.command) {
                    var i = _.indexOf(sample.files, function(item) {
                        return f.id === item.id && f.sample_id == sample.id;
                    });
                    if (i !== -1) {
                        sample.files.splice(i, 1);
                        sample.files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id,
                            linked: f.linked
                        });
                    } else {
                        sample.files.push({
                            id: f.id,
                            command: f.command,
                            name: f.name,
                            sample_id: f.sample_id,
                            linked: f.linked
                        });
                    }
                }
            });
            return sample;
        }
    };
}
<|endoftext|>


<commit_before>define([
	"dojo",
	"..",
	"../place",
	"dojo/window"], function(dojo, dijit, place){

	// module:
	//		dijit/_base/place
	// summary:
	//		Back compatibility module, new code should use dijit/place directly instead of using this module.

	dijit.getViewport = function(){
		// summary:
		//		Deprecated method to return the dimensions and scroll position of the viewable area of a browser window.
		//		New code should use dojo.window.getBox()

		return dojo.window.getBox();
	};

	/*=====
	dijit.placeOnScreen: function(node, pos, corners, padding){
		// summary:
		//		Positions one of the node's corners at specified position
		//		such that node is fully visible in viewport.
		//		Deprecated, new code should use dijit.place.at() instead.
	=====*/
	dijit.placeOnScreen = place.at;

	/*=====
	dijit.placeOnScreenAroundElement = function(node, aroundElement, aroundCorners, layoutNode){
		// summary:
		//		Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
		//		for the "around" argument and finds a proper processor to place a node.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	====*/
	dijit.placeOnScreenAroundElement = function(node, aroundNode, aroundCorners, layoutNode){
		// Convert old style {"BL": "TL", "BR": "TR"} type argument
		// to style needed by dijit.place code:
		//		[
		// 			{aroundCorner: "BL", corner: "TL" },
		//			{aroundCorner: "BR", corner: "TR" }
		//		]
		var positions;
		if(dojo.isArray(aroundCorners)){
			positions = aroundCorners;
		}else{
			positions = [];
			for(var key in aroundCorners){
				positions.push({aroundCorner: key, corner: aroundCorners[key]});
			}
		}

		return place.around(node, aroundNode, positions, true, layoutNode);
	};

	/*=====
	dijit.placeOnScreenAroundNode = function(node, aroundNode, aroundCorners, layoutNode){
		// summary:
		//		Position node adjacent or kitty-corner to aroundNode
		//		such that it's fully visible in viewport.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	=====*/
	dijit.placeOnScreenAroundNode = dijit.placeOnScreenAroundElement;

	/*=====
	dijit.placeOnScreenAroundRectangle = function(node, aroundRect, aroundCorners, layoutNode){
		// summary:
		//		Like dijit.placeOnScreenAroundNode(), except that the "around"
		//		parameter is an arbitrary rectangle on the screen (x, y, width, height)
		//		instead of a dom node.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	=====*/
	dijit.placeOnScreenAroundRectangle = dijit.placeOnScreenAroundElement;

	dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
		// summary:
		//		Deprecated method, unneeded when using dijit/place directly.
		//		Transforms the passed array of preferred positions into a format suitable for
		//		passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
		//
		// position: String[]
		//		This variable controls the position of the drop down.
		//		It's an array of strings with the following values:
		//
		//			* before: places drop down to the left of the target node/widget, or to the right in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* after: places drop down to the right of the target node/widget, or to the left in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* above: drop down goes above target node
		//			* below: drop down goes below target node
		//
		//		The list is positions is tried, in order, until a position is found where the drop down fits
		//		within the viewport.
		//
		// leftToRight: Boolean
		//		Whether the popup will be displaying in leftToRight mode.
		//
		var align = {};
		dojo.forEach(position, function(pos){
			var ltr = leftToRight;
			switch(pos){
				case "after":
					align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
					break;
				case "before":
					align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
					break;
				case "below-alt":
					ltr = !ltr;
					// fall through
				case "below":
					// first try to align left borders, next try to align right borders (or reverse for RTL mode)
					align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR";
					align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL";
					break;
				case "above-alt":
					ltr = !ltr;
					// fall through
				case "above":
				default:
					// first try to align left borders, next try to align right borders (or reverse for RTL mode)
					align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR";
					align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL";
					break;
			}
		});
		return align;
	};

	return dijit;
});
<commit_msg>fix API doc, refs #12728<commit_after>define([
	"dojo",
	"..",
	"../place",
	"dojo/window"], function(dojo, dijit, place){

	// module:
	//		dijit/_base/place
	// summary:
	//		Back compatibility module, new code should use dijit/place directly instead of using this module.

	dijit.getViewport = function(){
		// summary:
		//		Deprecated method to return the dimensions and scroll position of the viewable area of a browser window.
		//		New code should use dojo.window.getBox()

		return dojo.window.getBox();
	};

	/*=====
	dijit.placeOnScreen = function(node, pos, corners, padding){
		// summary:
		//		Positions one of the node's corners at specified position
		//		such that node is fully visible in viewport.
		//		Deprecated, new code should use dijit.place.at() instead.
	=====*/
	dijit.placeOnScreen = place.at;

	/*=====
	dijit.placeOnScreenAroundElement = function(node, aroundElement, aroundCorners, layoutNode){
		// summary:
		//		Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
		//		for the "around" argument and finds a proper processor to place a node.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	====*/
	dijit.placeOnScreenAroundElement = function(node, aroundNode, aroundCorners, layoutNode){
		// Convert old style {"BL": "TL", "BR": "TR"} type argument
		// to style needed by dijit.place code:
		//		[
		// 			{aroundCorner: "BL", corner: "TL" },
		//			{aroundCorner: "BR", corner: "TR" }
		//		]
		var positions;
		if(dojo.isArray(aroundCorners)){
			positions = aroundCorners;
		}else{
			positions = [];
			for(var key in aroundCorners){
				positions.push({aroundCorner: key, corner: aroundCorners[key]});
			}
		}

		return place.around(node, aroundNode, positions, true, layoutNode);
	};

	/*=====
	dijit.placeOnScreenAroundNode = function(node, aroundNode, aroundCorners, layoutNode){
		// summary:
		//		Position node adjacent or kitty-corner to aroundNode
		//		such that it's fully visible in viewport.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	=====*/
	dijit.placeOnScreenAroundNode = dijit.placeOnScreenAroundElement;

	/*=====
	dijit.placeOnScreenAroundRectangle = function(node, aroundRect, aroundCorners, layoutNode){
		// summary:
		//		Like dijit.placeOnScreenAroundNode(), except that the "around"
		//		parameter is an arbitrary rectangle on the screen (x, y, width, height)
		//		instead of a dom node.
		//		Deprecated, new code should use dijit.place.around() instead.
	};
	=====*/
	dijit.placeOnScreenAroundRectangle = dijit.placeOnScreenAroundElement;

	dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
		// summary:
		//		Deprecated method, unneeded when using dijit/place directly.
		//		Transforms the passed array of preferred positions into a format suitable for
		//		passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
		//
		// position: String[]
		//		This variable controls the position of the drop down.
		//		It's an array of strings with the following values:
		//
		//			* before: places drop down to the left of the target node/widget, or to the right in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* after: places drop down to the right of the target node/widget, or to the left in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* above: drop down goes above target node
		//			* below: drop down goes below target node
		//
		//		The list is positions is tried, in order, until a position is found where the drop down fits
		//		within the viewport.
		//
		// leftToRight: Boolean
		//		Whether the popup will be displaying in leftToRight mode.
		//
		var align = {};
		dojo.forEach(position, function(pos){
			var ltr = leftToRight;
			switch(pos){
				case "after":
					align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
					break;
				case "before":
					align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
					break;
				case "below-alt":
					ltr = !ltr;
					// fall through
				case "below":
					// first try to align left borders, next try to align right borders (or reverse for RTL mode)
					align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR";
					align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL";
					break;
				case "above-alt":
					ltr = !ltr;
					// fall through
				case "above":
				default:
					// first try to align left borders, next try to align right borders (or reverse for RTL mode)
					align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR";
					align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL";
					break;
			}
		});
		return align;
	};

	return dijit;
});
<|endoftext|>