<commit_before>(function() {
  var module = angular.module('loom_feature_diff_service', []);

  // Private Variables
  var service_ = null;
  var rootScope_ = null;
  var mapService_ = null;
  var geogitService_ = null;
  var dialogService_ = null;
  var translate_ = null;

  var ours_ = null;
  var theirs_ = null;
  var ancestor_ = null;
  var merged_ = null;
  var repoId_ = null;
  var diffsNeeded_ = null;
  var diffsInError_ = 0;
  var crs_ = null;

  var FeaturePanel = function() {
    this.map = null;
    this.featureLayer = null;
    this.attributes = [];
    this.bounds = null;
    this.active = false;
    this.geometry = null;
    this.olFeature = null;

    this.clearFeature = function() {
      this.attributes = [];
      this.bounds = null;
      this.active = false;
      this.geometry = null;
      this.olFeature = null;
      this.featureLayer.clear();
    };

    this.getGeometry = function() {
      if (goog.isDefAndNotNull(this.geometry)) {
        return goog.isDefAndNotNull(this.geometry.newvalue) ? this.geometry.newvalue : this.geometry.oldvalue;
      }
      return null;
    };

    this.replaceLayers = function(newLayers) {
      var featurePanel = this;
      var layers = this.map.getLayers();
      layers.forEach(function(layer) {
        featurePanel.map.removeLayer(layer);
      });
      newLayers.forEach(function(layer) {
        if (!goog.isDefAndNotNull(layer.get('metadata').differences_layer) ||
            !layer.get('metadata').differences_layer) {
          featurePanel.map.addLayer(layer);
        }
      });
      this.map.addLayer(this.featureLayer);
    };
  };

  module.provider('featureDiffService', function() {
    this.title = 'Diffs';
    this.feature = null;
    this.left = new FeaturePanel();
    this.right = new FeaturePanel();
    this.merged = new FeaturePanel();
    this.change = null;
    this.leftName = null;
    this.rightName = null;
    this.schema = null;

    this.$get = function($rootScope, mapService, geogitService, dialogService, $translate) {
      service_ = this;
      rootScope_ = $rootScope;
      mapService_ = mapService;
      geogitService_ = geogitService;
      dialogService_ = dialogService;
      translate_ = $translate;
      var createMap = function(panel) {
        panel.map = new ol.Map({
          renderer: ol.RendererHint.CANVAS,
          view: new ol.View2D({
            center: ol.proj.transform([-87.2011, 14.1], 'EPSG:4326', 'EPSG:3857'),
            zoom: 14,
            maxZoom: 20
          })
        });

        var controls = panel.map.getControls();
        controls.forEach(function(control) {
          if (control instanceof ol.control.Attribution) {
            panel.map.removeControl(control);
          }
        });
        panel.featureLayer = makeFeatureLayer();
      };
      createMap(this.left);
      createMap(this.right);
      createMap(this.merged);
      this.merged.map.bindTo('view', service_.left.map);
      this.right.map.bindTo('view', service_.left.map);

      return this;
    };

    this.setTitle = function(title) {
      service_.title = title;
    };

    this.clear = function() {
      ours_ = null;
      theirs_ = null;
      ancestor_ = null;
      merged_ = null;
      repoId_ = null;
      service_.feature = null;
      service_.change = null;
      service_.left.clearFeature();
      service_.right.clearFeature();
      service_.merged.clearFeature();
      service_.leftName = null;
      service_.rightName = null;
      service_.schema = null;
    };

    this.chooseGeometry = function(panel) {
      this.merged.geometry = panel.geometry;
      this.merged.bounds = panel.bounds;
      this.merged.olFeature.setGeometry(panel.olFeature.getGeometry());
      this.merged.olFeature.set('MapLoomChange', panel.olFeature.get('MapLoomChange'));
      if (this.merged.geometry.changetype === 'REMOVED') {
        this.merged.attributes = $.extend(true, [], panel.attributes);
      }
      rootScope_.$broadcast('merge-feature-modified');
    };

    this.chooseAttribute = function(index, panel) {
      if (goog.isDefAndNotNull(service_.merged.geometry)) {
        if (goog.isDefAndNotNull(service_.merged.geometry.changetype)) {
          if (service_.merged.geometry.changetype === 'REMOVED') {
            return;
          }
        }
      }

      var type = this.merged.attributes[index].type;
      this.merged.attributes[index] = $.extend(true, {}, panel.attributes[index]);
      this.merged.attributes[index].type = type;
      assignAttributeTypes(this.merged.attributes, true);
    };

    this.choose = function(panel) {
      for (var i = 0; i < panel.attributes.length; i++) {
        this.chooseAttribute(i, panel);
      }
      this.chooseGeometry(panel);
    };

    this.attributesEqual = function(attr1, attr2) {
      return attr1.attributename == attr2.attributename &&
          attr1.changetype == attr2.changetype &&
          attr1.newvalue == attr2.newvalue &&
          attr1.oldvalue == attr2.oldvalue;
    };

    this.updateChangeType = function(attribute) {
      if (goog.isDefAndNotNull(attribute.oldvalue)) {
        if (goog.isDefAndNotNull(attribute.newvalue)) {
          if (attribute.oldvalue !== attribute.newvalue) {
            attribute.changetype = 'MODIFIED';
          } else {
            attribute.changetype = 'NO_CHANGE';
          }
        } else {
          attribute.changetype = 'REMOVED';
        }
      } else {
        if (goog.isDefAndNotNull(attribute.newvalue)) {
          attribute.changetype = 'ADDED';
        } else {
          attribute.changetype = 'NO_CHANGE';
        }
      }
    };

    this.getMerges = function() {
      var merges = {};
      if (service_.merged.geometry == service_.left.geometry) {
        merges[service_.merged.geometry.attributename] = {ours: true};
      } else if (service_.merged.geometry == service_.right.geometry) {
        merges[service_.merged.geometry.attributename] = {theirs: true};
      } else {
        merges[service_.merged.geometry.attributename] = {value: service_.merged.geometry};
      }

      for (var i = 0; i < service_.merged.attributes.length; i++) {
        if (service_.attributesEqual(service_.merged.attributes[i], service_.left.attributes[i])) {
          merges[service_.merged.attributes[i].attributename] = {ours: true};
        } else if (service_.attributesEqual(service_.merged.attributes[i], service_.right.attributes[i])) {
          merges[service_.merged.attributes[i].attributename] = {thiers: true};
        } else {
          merges[service_.merged.attributes[i].attributename] = {value: service_.merged.attributes[i].newvalue};
        }
      }

      return merges;
    };

    this.setFeature = function(feature, ours, theirs, ancestor, merged, repoId) {
      service_.change = feature.change;
      service_.left.clearFeature();
      service_.right.clearFeature();
      service_.merged.clearFeature();
      ours_ = ours;
      theirs_ = theirs;
      ancestor_ = ancestor;
      merged_ = merged;
      repoId_ = repoId;
      var layers = mapService_.map.getLayers();
      service_.feature = feature;
      service_.left.replaceLayers(layers);
      service_.right.replaceLayers(layers);
      service_.merged.replaceLayers(layers);

      crs_ = goog.isDefAndNotNull(feature.crs) ? feature.crs : null;
      var repoName = geogitService_.getRepoById(repoId_).name;
      mapService_.map.getLayers().forEach(function(layer) {
        var metadata = layer.get('metadata');
        if (goog.isDefAndNotNull(metadata)) {
          if (goog.isDefAndNotNull(metadata.geogitStore) && metadata.geogitStore === repoName) {
            var splitFeature = feature.id.split('/');
            if (goog.isDefAndNotNull(metadata.nativeName) && metadata.nativeName === splitFeature[0]) {
              if (goog.isDefAndNotNull(layer.get('metadata').schema)) {
                service_.schema = layer.get('metadata').schema;
              }
              if (goog.isDefAndNotNull(metadata.projection)) {
                crs_ = metadata.projection;
              }
            }
          }
        }
      });

      var geom = ol.parser.WKT.read(feature.geometry);
      if (goog.isDefAndNotNull(crs_)) {
        var transform = ol.proj.getTransform(crs_, mapService_.map.getView().getView2D().getProjection());
        geom.transform(transform);
      }
      var newBounds = geom.getBounds();
      var x = newBounds[2] - newBounds[0];
      var y = newBounds[3] - newBounds[1];
      x *= 0.5;
      y *= 0.5;
      newBounds[0] -= x;
      newBounds[2] += x;
      newBounds[1] -= y;
      newBounds[3] += y;

      diffsInError_ = 0;
      switch (feature.change) {
        case 'ADDED':
          diffsNeeded_ = 1;
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'REMOVED':
          diffsNeeded_ = 1;
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'MODIFIED':
          diffsNeeded_ = 2;
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'CONFLICT':
          diffsNeeded_ = 2;
          service_.merged.active = true;
          service_.merged.olFeature = new ol.Feature();
          service_.merged.olFeature.set('MapLoomChange', DiffColorMap[feature.change]);
          service_.merged.olFeature.setGeometry(geom);
          service_.merged.featureLayer.addFeatures([service_.merged.olFeature]);
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'MERGED':
          diffsNeeded_ = 3;
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          service_.performFeatureDiff(feature, merged_, ancestor_, service_.merged);
          break;
      }
      mapService_.zoomToExtent(newBounds);
      service_.title = feature.id;
      rootScope_.$broadcast('feature-diff-feature-set');
    };

    this.performFeatureDiff = function(feature, newCommit, oldCommit, panel) {
      var diffOptions = new GeoGitFeatureDiffOptions();
      diffOptions.all = true;
      diffOptions.newTreeish = newCommit;
      diffOptions.oldTreeish = oldCommit;
      diffOptions.path = feature.id;
      panel.active = true;
      geogitService_.command(repoId_, 'featurediff', diffOptions).then(function(response) {
        forEachArrayish(response.diff, function(item) {
          if (item.geometry !== true) {
            if (!goog.isDefAndNotNull(item.newvalue)) {
              item.newvalue = item.oldvalue;
            }
            panel.attributes.push(item);
          } else {
            panel.geometry = item;
          }
        });

        panel.attributes = panel.attributes.sort(function(a, b) {
          if (a.attributename > b.attributename) {
            return 1;
          }
          if (a.attributename < b.attributename) {
            return -1;
          }
          return 0;
        });

        var geom = ol.parser.WKT.read(panel.getGeometry());

        var localCrs = crs_;
        if (goog.isDefAndNotNull(panel.geometry.crs)) {
          localCrs = panel.geometry.crs;
        }
        if (goog.isDefAndNotNull(localCrs)) {
          var transform = ol.proj.getTransform(localCrs, panel.map.getView().getView2D().getProjection());
          geom.transform(transform);
        }
        var olFeature = new ol.Feature();
        olFeature.set('MapLoomChange', DiffColorMap[panel.geometry.changetype]);
        olFeature.setGeometry(geom);
        panel.featureLayer.addFeatures([olFeature]);
        panel.olFeature = olFeature;
        var newBounds = geom.getBounds();
        var x = newBounds[2] - newBounds[0];
        var y = newBounds[3] - newBounds[1];
        x *= 0.1;
        y *= 0.1;
        newBounds[0] -= x;
        newBounds[2] += x;
        newBounds[1] -= y;
        newBounds[3] += y;
        panel.bounds = newBounds;
        diffsNeeded_ -= 1;
        assignAttributeTypes(panel.attributes, false);
        if (diffsNeeded_ === 0) {
          if (diffsInError_ > 0) {
            dialogService_.error(translate_('error'), translate_('feature_diff_error'));
          } else {
            if (feature.change == 'CONFLICT') {
              service_.merged.attributes = $.extend(true, [], service_.left.attributes);
              if (goog.isDefAndNotNull(feature.merges)) {
                var geomattributename = panel.geometry.attributename;
                var geomMergeValue = feature.merges[geomattributename];
                if (geomMergeValue.ours === true) {
                  service_.chooseGeometry(service_.left);
                } else if (geomMergeValue.theirs === true) {
                  service_.chooseGeometry(service_.right);
                }
                for (var i = 0; i < service_.merged.attributes.length; i++) {
                  var attributename = service_.merged.attributes[i].attributename;
                  var mergeValue = feature.merges[attributename];
                  if (mergeValue.ours === true) {
                    // 'ours' is default and already picked.
                  } else if (mergeValue.theirs === true) {
                    service_.chooseAttribute(i, service_.right);
                  } else {
                    service_.merged.attributes[i].newvalue = mergeValue.value;
                    service_.updateChangeType(service_.merged.attributes[i]);
                  }
                }
                assignAttributeTypes(service_.merged.attributes, true);
              } else {
                service_.choose(service_.left);
                assignAttributeTypes(service_.merged.attributes, true);
              }
            }
            rootScope_.$broadcast('feature-diff-performed');
          }
        }
      }, function(reject) {
        diffsNeeded_ -= 1;
        diffsInError_ += 1;
        if (diffsNeeded_ === 0) {
          dialogService_.error(translate_('error'), translate_('feature_diff_error'));
        }
        console.log('Feature diff failed: ', panel, reject);
      });
    };
  });

  function makeFeatureLayer() {
    return new ol.layer.Vector({
      source: new ol.source.Vector({
        parser: null
      }),
      style: new ol.style.Style({rules: [
        new ol.style.Rule({
          filter: '(geometryType("polygon") || geometryType("multipolygon"))',
          symbolizers: [
            new ol.style.Fill({color: ol.expr.parse('MapLoomChange.fill'), opacity: 1.0}),
            new ol.style.Stroke({color: ol.expr.parse('MapLoomChange.stroke')})
          ]
        }),
        new ol.style.Rule({
          filter: '(geometryType("point") || geometryType("multipoint"))',
          symbolizers: [
            new ol.style.Shape({size: 20,
              fill: new ol.style.Fill({color: ol.expr.parse('MapLoomChange.fill'), opacity: 1.0}),
              stroke: new ol.style.Stroke({color: ol.expr.parse('MapLoomChange.stroke')})
            })
          ]
        })
      ]})
    });
  }

  function assignAttributeTypes(properties, editable) {
    if (goog.isDefAndNotNull(service_.schema)) {
      for (var propertyIndex = 0; propertyIndex < properties.length; propertyIndex++) {
        properties[propertyIndex].type = service_.schema[properties[propertyIndex].attributename]._type;
        if (properties[propertyIndex].type === 'simpleType') {
          properties[propertyIndex].enum =
              service_.schema[properties[propertyIndex].attributename].simpleType.restriction.enumeration;
        }
        properties[propertyIndex].valid = true;
        properties[propertyIndex].editable = editable;
      }
    }
  }

}());
<commit_msg>Fixed a bug with merging features (typo).<commit_after>(function() {
  var module = angular.module('loom_feature_diff_service', []);

  // Private Variables
  var service_ = null;
  var rootScope_ = null;
  var mapService_ = null;
  var geogitService_ = null;
  var dialogService_ = null;
  var translate_ = null;

  var ours_ = null;
  var theirs_ = null;
  var ancestor_ = null;
  var merged_ = null;
  var repoId_ = null;
  var diffsNeeded_ = null;
  var diffsInError_ = 0;
  var crs_ = null;

  var FeaturePanel = function() {
    this.map = null;
    this.featureLayer = null;
    this.attributes = [];
    this.bounds = null;
    this.active = false;
    this.geometry = null;
    this.olFeature = null;

    this.clearFeature = function() {
      this.attributes = [];
      this.bounds = null;
      this.active = false;
      this.geometry = null;
      this.olFeature = null;
      this.featureLayer.clear();
    };

    this.getGeometry = function() {
      if (goog.isDefAndNotNull(this.geometry)) {
        return goog.isDefAndNotNull(this.geometry.newvalue) ? this.geometry.newvalue : this.geometry.oldvalue;
      }
      return null;
    };

    this.replaceLayers = function(newLayers) {
      var featurePanel = this;
      var layers = this.map.getLayers();
      layers.forEach(function(layer) {
        featurePanel.map.removeLayer(layer);
      });
      newLayers.forEach(function(layer) {
        if (!goog.isDefAndNotNull(layer.get('metadata').differences_layer) ||
            !layer.get('metadata').differences_layer) {
          featurePanel.map.addLayer(layer);
        }
      });
      this.map.addLayer(this.featureLayer);
    };
  };

  module.provider('featureDiffService', function() {
    this.title = 'Diffs';
    this.feature = null;
    this.left = new FeaturePanel();
    this.right = new FeaturePanel();
    this.merged = new FeaturePanel();
    this.change = null;
    this.leftName = null;
    this.rightName = null;
    this.schema = null;

    this.$get = function($rootScope, mapService, geogitService, dialogService, $translate) {
      service_ = this;
      rootScope_ = $rootScope;
      mapService_ = mapService;
      geogitService_ = geogitService;
      dialogService_ = dialogService;
      translate_ = $translate;
      var createMap = function(panel) {
        panel.map = new ol.Map({
          renderer: ol.RendererHint.CANVAS,
          view: new ol.View2D({
            center: ol.proj.transform([-87.2011, 14.1], 'EPSG:4326', 'EPSG:3857'),
            zoom: 14,
            maxZoom: 20
          })
        });

        var controls = panel.map.getControls();
        controls.forEach(function(control) {
          if (control instanceof ol.control.Attribution) {
            panel.map.removeControl(control);
          }
        });
        panel.featureLayer = makeFeatureLayer();
      };
      createMap(this.left);
      createMap(this.right);
      createMap(this.merged);
      this.merged.map.bindTo('view', service_.left.map);
      this.right.map.bindTo('view', service_.left.map);

      return this;
    };

    this.setTitle = function(title) {
      service_.title = title;
    };

    this.clear = function() {
      ours_ = null;
      theirs_ = null;
      ancestor_ = null;
      merged_ = null;
      repoId_ = null;
      service_.feature = null;
      service_.change = null;
      service_.left.clearFeature();
      service_.right.clearFeature();
      service_.merged.clearFeature();
      service_.leftName = null;
      service_.rightName = null;
      service_.schema = null;
    };

    this.chooseGeometry = function(panel) {
      this.merged.geometry = panel.geometry;
      this.merged.bounds = panel.bounds;
      this.merged.olFeature.setGeometry(panel.olFeature.getGeometry());
      this.merged.olFeature.set('MapLoomChange', panel.olFeature.get('MapLoomChange'));
      if (this.merged.geometry.changetype === 'REMOVED') {
        this.merged.attributes = $.extend(true, [], panel.attributes);
      }
      rootScope_.$broadcast('merge-feature-modified');
    };

    this.chooseAttribute = function(index, panel) {
      if (goog.isDefAndNotNull(service_.merged.geometry)) {
        if (goog.isDefAndNotNull(service_.merged.geometry.changetype)) {
          if (service_.merged.geometry.changetype === 'REMOVED') {
            return;
          }
        }
      }

      var type = this.merged.attributes[index].type;
      this.merged.attributes[index] = $.extend(true, {}, panel.attributes[index]);
      this.merged.attributes[index].type = type;
      assignAttributeTypes(this.merged.attributes, true);
    };

    this.choose = function(panel) {
      for (var i = 0; i < panel.attributes.length; i++) {
        this.chooseAttribute(i, panel);
      }
      this.chooseGeometry(panel);
    };

    this.attributesEqual = function(attr1, attr2) {
      return attr1.attributename == attr2.attributename &&
          attr1.changetype == attr2.changetype &&
          attr1.newvalue == attr2.newvalue &&
          attr1.oldvalue == attr2.oldvalue;
    };

    this.updateChangeType = function(attribute) {
      if (goog.isDefAndNotNull(attribute.oldvalue)) {
        if (goog.isDefAndNotNull(attribute.newvalue)) {
          if (attribute.oldvalue !== attribute.newvalue) {
            attribute.changetype = 'MODIFIED';
          } else {
            attribute.changetype = 'NO_CHANGE';
          }
        } else {
          attribute.changetype = 'REMOVED';
        }
      } else {
        if (goog.isDefAndNotNull(attribute.newvalue)) {
          attribute.changetype = 'ADDED';
        } else {
          attribute.changetype = 'NO_CHANGE';
        }
      }
    };

    this.getMerges = function() {
      var merges = {};
      if (service_.merged.geometry == service_.left.geometry) {
        merges[service_.merged.geometry.attributename] = {ours: true};
      } else if (service_.merged.geometry == service_.right.geometry) {
        merges[service_.merged.geometry.attributename] = {theirs: true};
      } else {
        merges[service_.merged.geometry.attributename] = {value: service_.merged.geometry};
      }

      for (var i = 0; i < service_.merged.attributes.length; i++) {
        if (service_.attributesEqual(service_.merged.attributes[i], service_.left.attributes[i])) {
          merges[service_.merged.attributes[i].attributename] = {ours: true};
        } else if (service_.attributesEqual(service_.merged.attributes[i], service_.right.attributes[i])) {
          merges[service_.merged.attributes[i].attributename] = {theirs: true};
        } else {
          merges[service_.merged.attributes[i].attributename] = {value: service_.merged.attributes[i].newvalue};
        }
      }

      return merges;
    };

    this.setFeature = function(feature, ours, theirs, ancestor, merged, repoId) {
      service_.change = feature.change;
      service_.left.clearFeature();
      service_.right.clearFeature();
      service_.merged.clearFeature();
      ours_ = ours;
      theirs_ = theirs;
      ancestor_ = ancestor;
      merged_ = merged;
      repoId_ = repoId;
      var layers = mapService_.map.getLayers();
      service_.feature = feature;
      service_.left.replaceLayers(layers);
      service_.right.replaceLayers(layers);
      service_.merged.replaceLayers(layers);

      crs_ = goog.isDefAndNotNull(feature.crs) ? feature.crs : null;
      var repoName = geogitService_.getRepoById(repoId_).name;
      mapService_.map.getLayers().forEach(function(layer) {
        var metadata = layer.get('metadata');
        if (goog.isDefAndNotNull(metadata)) {
          if (goog.isDefAndNotNull(metadata.geogitStore) && metadata.geogitStore === repoName) {
            var splitFeature = feature.id.split('/');
            if (goog.isDefAndNotNull(metadata.nativeName) && metadata.nativeName === splitFeature[0]) {
              if (goog.isDefAndNotNull(layer.get('metadata').schema)) {
                service_.schema = layer.get('metadata').schema;
              }
              if (goog.isDefAndNotNull(metadata.projection)) {
                crs_ = metadata.projection;
              }
            }
          }
        }
      });

      var geom = ol.parser.WKT.read(feature.geometry);
      if (goog.isDefAndNotNull(crs_)) {
        var transform = ol.proj.getTransform(crs_, mapService_.map.getView().getView2D().getProjection());
        geom.transform(transform);
      }
      var newBounds = geom.getBounds();
      var x = newBounds[2] - newBounds[0];
      var y = newBounds[3] - newBounds[1];
      x *= 0.5;
      y *= 0.5;
      newBounds[0] -= x;
      newBounds[2] += x;
      newBounds[1] -= y;
      newBounds[3] += y;

      diffsInError_ = 0;
      switch (feature.change) {
        case 'ADDED':
          diffsNeeded_ = 1;
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'REMOVED':
          diffsNeeded_ = 1;
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'MODIFIED':
          diffsNeeded_ = 2;
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'CONFLICT':
          diffsNeeded_ = 2;
          service_.merged.active = true;
          service_.merged.olFeature = new ol.Feature();
          service_.merged.olFeature.set('MapLoomChange', DiffColorMap[feature.change]);
          service_.merged.olFeature.setGeometry(geom);
          service_.merged.featureLayer.addFeatures([service_.merged.olFeature]);
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          break;
        case 'MERGED':
          diffsNeeded_ = 3;
          service_.performFeatureDiff(feature, ours_, ancestor_, service_.left);
          service_.performFeatureDiff(feature, theirs_, ancestor_, service_.right);
          service_.performFeatureDiff(feature, merged_, ancestor_, service_.merged);
          break;
      }
      mapService_.zoomToExtent(newBounds);
      service_.title = feature.id;
      rootScope_.$broadcast('feature-diff-feature-set');
    };

    this.performFeatureDiff = function(feature, newCommit, oldCommit, panel) {
      var diffOptions = new GeoGitFeatureDiffOptions();
      diffOptions.all = true;
      diffOptions.newTreeish = newCommit;
      diffOptions.oldTreeish = oldCommit;
      diffOptions.path = feature.id;
      panel.active = true;
      geogitService_.command(repoId_, 'featurediff', diffOptions).then(function(response) {
        forEachArrayish(response.diff, function(item) {
          if (item.geometry !== true) {
            if (!goog.isDefAndNotNull(item.newvalue)) {
              item.newvalue = item.oldvalue;
            }
            panel.attributes.push(item);
          } else {
            panel.geometry = item;
          }
        });

        panel.attributes = panel.attributes.sort(function(a, b) {
          if (a.attributename > b.attributename) {
            return 1;
          }
          if (a.attributename < b.attributename) {
            return -1;
          }
          return 0;
        });

        var geom = ol.parser.WKT.read(panel.getGeometry());

        var localCrs = crs_;
        if (goog.isDefAndNotNull(panel.geometry.crs)) {
          localCrs = panel.geometry.crs;
        }
        if (goog.isDefAndNotNull(localCrs)) {
          var transform = ol.proj.getTransform(localCrs, panel.map.getView().getView2D().getProjection());
          geom.transform(transform);
        }
        var olFeature = new ol.Feature();
        olFeature.set('MapLoomChange', DiffColorMap[panel.geometry.changetype]);
        olFeature.setGeometry(geom);
        panel.featureLayer.addFeatures([olFeature]);
        panel.olFeature = olFeature;
        var newBounds = geom.getBounds();
        var x = newBounds[2] - newBounds[0];
        var y = newBounds[3] - newBounds[1];
        x *= 0.1;
        y *= 0.1;
        newBounds[0] -= x;
        newBounds[2] += x;
        newBounds[1] -= y;
        newBounds[3] += y;
        panel.bounds = newBounds;
        diffsNeeded_ -= 1;
        assignAttributeTypes(panel.attributes, false);
        if (diffsNeeded_ === 0) {
          if (diffsInError_ > 0) {
            dialogService_.error(translate_('error'), translate_('feature_diff_error'));
          } else {
            if (feature.change == 'CONFLICT') {
              service_.merged.attributes = $.extend(true, [], service_.left.attributes);
              if (goog.isDefAndNotNull(feature.merges)) {
                var geomattributename = panel.geometry.attributename;
                var geomMergeValue = feature.merges[geomattributename];
                if (geomMergeValue.ours === true) {
                  service_.chooseGeometry(service_.left);
                } else if (geomMergeValue.theirs === true) {
                  service_.chooseGeometry(service_.right);
                }
                for (var i = 0; i < service_.merged.attributes.length; i++) {
                  var attributename = service_.merged.attributes[i].attributename;
                  var mergeValue = feature.merges[attributename];
                  if (mergeValue.ours === true) {
                    // 'ours' is default and already picked.
                  } else if (mergeValue.theirs === true) {
                    service_.chooseAttribute(i, service_.right);
                  } else {
                    service_.merged.attributes[i].newvalue = mergeValue.value;
                    service_.updateChangeType(service_.merged.attributes[i]);
                  }
                }
                assignAttributeTypes(service_.merged.attributes, true);
              } else {
                service_.choose(service_.left);
                assignAttributeTypes(service_.merged.attributes, true);
              }
            }
            rootScope_.$broadcast('feature-diff-performed');
          }
        }
      }, function(reject) {
        diffsNeeded_ -= 1;
        diffsInError_ += 1;
        if (diffsNeeded_ === 0) {
          dialogService_.error(translate_('error'), translate_('feature_diff_error'));
        }
        console.log('Feature diff failed: ', panel, reject);
      });
    };
  });

  function makeFeatureLayer() {
    return new ol.layer.Vector({
      source: new ol.source.Vector({
        parser: null
      }),
      style: new ol.style.Style({rules: [
        new ol.style.Rule({
          filter: '(geometryType("polygon") || geometryType("multipolygon"))',
          symbolizers: [
            new ol.style.Fill({color: ol.expr.parse('MapLoomChange.fill'), opacity: 1.0}),
            new ol.style.Stroke({color: ol.expr.parse('MapLoomChange.stroke')})
          ]
        }),
        new ol.style.Rule({
          filter: '(geometryType("point") || geometryType("multipoint"))',
          symbolizers: [
            new ol.style.Shape({size: 20,
              fill: new ol.style.Fill({color: ol.expr.parse('MapLoomChange.fill'), opacity: 1.0}),
              stroke: new ol.style.Stroke({color: ol.expr.parse('MapLoomChange.stroke')})
            })
          ]
        })
      ]})
    });
  }

  function assignAttributeTypes(properties, editable) {
    if (goog.isDefAndNotNull(service_.schema)) {
      for (var propertyIndex = 0; propertyIndex < properties.length; propertyIndex++) {
        properties[propertyIndex].type = service_.schema[properties[propertyIndex].attributename]._type;
        if (properties[propertyIndex].type === 'simpleType') {
          properties[propertyIndex].enum =
              service_.schema[properties[propertyIndex].attributename].simpleType.restriction.enumeration;
        }
        properties[propertyIndex].valid = true;
        properties[propertyIndex].editable = editable;
      }
    }
  }

}());
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * The examples provided by Facebook are for non-commercial testing and
 * evaluation purposes only.
 *
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @flow
 */
/* eslint no-console: 0 */
'use strict';

var React = require('react');
var ReactNative = require('react-native');
var {
  StyleSheet,
  Text,
  View,
} = ReactNative;

exports.framework = 'React';
exports.title = 'Geolocation';
exports.description = 'Examples of using the Geolocation API.';

exports.examples = [
  {
    title: 'navigator.geolocation',
    render: function(): ReactElement<any> {
      return <GeolocationExample />;
    },
  }
];

class GeolocationExample extends React.Component {
  state = {
    initialPosition: 'unknown',
    lastPosition: 'unknown',
  };

  watchID: ?number = null;

  componentDidMount() {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        var initialPosition = JSON.stringify(position);
        this.setState({initialPosition});
      },
      (error) => alert(error.message),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    );
    this.watchID = navigator.geolocation.watchPosition((position) => {
      var lastPosition = JSON.stringify(position);
      this.setState({lastPosition});
    });
  }

  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  render() {
    return (
      <View>
        <Text>
          <Text style={styles.title}>Initial position: </Text>
          {this.state.initialPosition}
        </Text>
        <Text>
          <Text style={styles.title}>Current position: </Text>
          {this.state.lastPosition}
        </Text>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  title: {
    fontWeight: '500',
  },
});
<commit_msg>Fix alert's error message<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * The examples provided by Facebook are for non-commercial testing and
 * evaluation purposes only.
 *
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @flow
 */
/* eslint no-console: 0 */
'use strict';

var React = require('react');
var ReactNative = require('react-native');
var {
  StyleSheet,
  Text,
  View,
} = ReactNative;

exports.framework = 'React';
exports.title = 'Geolocation';
exports.description = 'Examples of using the Geolocation API.';

exports.examples = [
  {
    title: 'navigator.geolocation',
    render: function(): ReactElement<any> {
      return <GeolocationExample />;
    },
  }
];

class GeolocationExample extends React.Component {
  state = {
    initialPosition: 'unknown',
    lastPosition: 'unknown',
  };

  watchID: ?number = null;

  componentDidMount() {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        var initialPosition = JSON.stringify(position);
        this.setState({initialPosition});
      },
      (error) => alert(error),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    );
    this.watchID = navigator.geolocation.watchPosition((position) => {
      var lastPosition = JSON.stringify(position);
      this.setState({lastPosition});
    });
  }

  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  render() {
    return (
      <View>
        <Text>
          <Text style={styles.title}>Initial position: </Text>
          {this.state.initialPosition}
        </Text>
        <Text>
          <Text style={styles.title}>Current position: </Text>
          {this.state.lastPosition}
        </Text>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  title: {
    fontWeight: '500',
  },
});
<|endoftext|>


<commit_before>module.exports = {
    run: function(creep) {
            if (creep.memory.working == true && creep.carry.energy == 0) {
            creep.memory.working = false;
        }
        else if (creep.memory.working == false && creep.carry.energy == creep.carryCapacity) {
            creep.memory.working = true;
        }

        if (creep.memory.working == true) {
            if (creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
            //if (creep.transfer(Game.spawns.Spawn1, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
                creep.moveTo(creep.room.controller);
            }
        }
        else {
            var source = creep.pos.findClosestByPath(FIND_SOURCES);
            if (creep.harvest(source) == ERR_NOT_IN_RANGE) {
                creep.moveTo(source);
            }
        }
    }
};

var target = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
if(target) {
    if(creep.attack(target) == ERR_NOT_IN_RANGE) {
        creep.moveTo(target);
    }
}
<commit_msg>Delete role.guard.js<commit_after><|endoftext|>


<commit_before>var roleMiner = {

};

module.exports = roleMiner;
<commit_msg>added a function to assign a source to run when first spawned<commit_after>var roleMiner = {

  assignSource:function(creep){
    var sources = creep.room.find(FIND_SOURCES);
    for(var sIndex in sources){
      var s = sources[sIndex];
      var gID = s.id;
      var thisAssigned =false;
      for(var cName in Game.creeps){
          var c = Game.creeps[cName];
          if(c.memory.source === gID){
            thisAssigned = true;
          }
      }
      if(!thisAssigned && creep.memory.source === ""){
        creep.memory.source = gID;
      }
      Memory.roles.maxMiners = sources.length;
    }
  },

  run: function(creep) {

  }

};

module.exports = roleMiner;
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { setupFactoryGuy, make } from 'ember-data-factory-guy';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';

module('Integration | Component | provider-show', function(hooks) {
  setupRenderingTest(hooks);
  setupFactoryGuy(hooks);

  test('it renders', async function(assert) {
    this.set('model', make('client'));

    // Template block usage:
    await render(hbs`
      {{#provider-show model=model link="clients.index"}}

      {{/provider-show}}
    `);

    assert.dom('*').hasText('Organization Information Provider ID Contact Name Dr. Steven McEachern Service Contact Information General Contact Email ada@anu.edu.au Password has not been set Billing Information');
  });
});
<commit_msg>Update provider setting test<commit_after>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { setupFactoryGuy, make } from 'ember-data-factory-guy';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';

module('Integration | Component | provider-show', function(hooks) {
  setupRenderingTest(hooks);
  setupFactoryGuy(hooks);

  test('it renders', async function(assert) {
    this.set('model', make('client'));

    // Template block usage:
    await render(hbs`
      {{#provider-show model=model link="clients.index"}}

      {{/provider-show}}
    `);

    assert.dom('*').hasText('Organization Information Provider ID Contact Name Dr. Steven McEachern Service Contact Information General Contact Email ada@anu.edu.au Password has not been set has not been provided');
  });
});
<|endoftext|>


<commit_before>const path = require("path");

module.exports = {
    entry: __dirname + '/index.ts',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    resolve: {
        extensions: ['.ts', '.js'],
        alias: {
            "babylonjs": __dirname + '/../../../dist/preview release/babylon.max.js',
            "babylonjs-gui": __dirname + '/../../../dist/preview release/gui/babylon.gui.js',
            "babylonjs-inspector": __dirname + '/../../../dist/preview release/inspector/babylon.inspector.js',
            "babylonjs-loaders": __dirname + '/../../../dist/preview release/loaders/babylonjs.loaders.js',
            "babylonjs-serializers": __dirname + '/../../../dist/preview release/serializers/babylonjs.serializers.js',
        }
    },
    devtool: "source-map",
    module: {
        rules: [
            { test: /\.tsx?$/, loader: "ts-loader" },
        ]
    },
    mode: "development"
};<commit_msg>Fix module tests<commit_after>const path = require("path");

module.exports = {
    entry: __dirname + '/index.ts',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    resolve: {
        extensions: ['.ts', '.js'],
        alias: {
            "babylonjs": __dirname + '/../../../dist/preview release/babylon.max.js',
            "babylonjs-gui": __dirname + '/../../../dist/preview release/gui/babylon.gui.js',
            "babylonjs-inspector": __dirname + '/../../../dist/preview release/inspector/babylon.inspector.bundle.js',
            "babylonjs-loaders": __dirname + '/../../../dist/preview release/loaders/babylonjs.loaders.js',
            "babylonjs-serializers": __dirname + '/../../../dist/preview release/serializers/babylonjs.serializers.js',
        }
    },
    devtool: "source-map",
    module: {
        rules: [
            { test: /\.tsx?$/, loader: "ts-loader" },
        ]
    },
    mode: "development"
};<|endoftext|>


<commit_before>import React from 'react';
import Select from 'react-select';
import { flattenArray } from '../../helpers/utils';

class Search extends React.Component {
	constructor(){
		super();

		this.state = {};

		this.onChange = this.onChange.bind(this);
		this.onFilter = this.onFilter.bind(this);
	    this.createOptions = this.createOptions.bind(this);
	}

  createOptions() {
    const tags = new Set(flattenArray(this.props.items.map(item => {
      if (!item.tags) {
        return '';
      }

      return item.tags.split(' ');
    })));

    const options = [...tags].map(tag => ({
      value: tag,
      label: tag,
    }));
    return options;
  }

	onChange(value){
		this.setState({ value }, this.onFilter);
	}

	onFilter(){
		this.props.onFilter(this.state.value);
	}

	render() {
		const options = this.createOptions();

		return (
			<Select
				multi
				onChange={this.onChange}
				options={options}
				value={this.state.value}
			/>
		);
	}

}

export default Search;
<commit_msg>Returns a list of tags to parents search Was originally returning a list of objects of tags to a custom function<commit_after>import React from 'react';
import Select from 'react-select';
import { flattenArray } from '../../helpers/utils';

class Search extends React.Component {
	constructor(){
		super();

		this.state = {};

		this.onChange = this.onChange.bind(this);
		this.onFilter = this.onFilter.bind(this);
	  this.createOptions = this.createOptions.bind(this);
	}

  createOptions() {
    const tags = new Set(flattenArray(this.props.items.map(item => {
      if (!item.tags) {
        return '';
      }

      return item.tags.split(' ');
    })));

    const options = [...tags].map(tag => ({
      value: tag,
      label: tag,
    }));
    return options;
  }

	onChange(value){
		this.setState({ value }, this.onFilter);
	}

	onFilter(){
		const tagList = this.state.value.map((tag) => (tag.value));

		const query = {
			...this.props.query,
			tags: (tagList.length !== 0) ? tagList : ''
		};

		this.props.onFilter(query);
	}

	render() {
		const options = this.createOptions();

		return (
			<Select
				multi
				onChange={this.onChange}
				options={options}
				value={this.state.value}
			/>
		);
	}

}

export default Search;
<|endoftext|>


<commit_before>import angular from 'angular';
import { TableDefaults, ColumnDefaults } from '../defaults';
import { AdjustColumnWidths, ForceFillColumnWidths } from '../utils/math';
import { ColumnsByPin, ColumnGroupWidths, CamelCase, ObjectId, ScrollbarWidth } from '../utils/utils';

export class DataTableController {

  /**
   * Creates an instance of the DataTable Controller
   * @param  {scope}
   * @param  {filter}
   */
  /*@ngInject*/
  constructor($scope, $filter, $log, $transclude){
    Object.assign(this, {
      $scope: $scope,
      $filter: $filter,
      $log: $log
    });

    this.defaults();

    // set scope to the parent
    this.options.$outer = $scope.$parent;

    $scope.$watch('dt.options.columns', (newVal, oldVal) => {
      this.transposeColumnDefaults();

      if(newVal.length !== oldVal.length){
        this.adjustColumns();
      }

      this.calculateColumns();
    }, true);

    // default sort
    var watch = $scope.$watch('dt.rows', (newVal) => {
      if(newVal){
        watch();
        this.onSorted();
      }
    });
  }

  /**
   * Creates and extends default options for the grid control
   */
  defaults(){
    this.expanded = this.expanded || {};

    this.options = angular.extend(angular.
      copy(TableDefaults), this.options);

    angular.forEach(TableDefaults.paging, (v,k) => {
      if(!this.options.paging[k]){
        this.options.paging[k] = v;
      }
    });

    if(this.options.selectable && this.options.multiSelect){
      this.selected = this.selected || [];
    }
  }

  /**
   * On init or when a column is added, we need to
   * make sure all the columns added have the correct
   * defaults applied.
   */
  transposeColumnDefaults(){
    for(var i=0, len = this.options.columns.length; i < len; i++) {
      var column = this.options.columns[i];
      column.$id = ObjectId();

      angular.forEach(ColumnDefaults, (v,k) => {
        if(!column.hasOwnProperty(k)){
          column[k] = v;
        }
      });

      if(column.name && !column.prop){
        column.prop = CamelCase(column.name);
      }

      this.options.columns[i] = column;
    }
  }

  /**
   * Calculate column groups and widths
   */
  calculateColumns(){
    var columns = this.options.columns;
    this.columnsByPin = ColumnsByPin(columns);
    this.columnWidths = ColumnGroupWidths(this.columnsByPin, columns);
  }

  /**
   * Returns the css classes for the data table.
   * @return {style object}
   */
  tableCss(){
    return {
      'fixed': this.options.scrollbarV,
      'selectable': this.options.selectable,
      'checkboxable': this.options.checkboxSelection
    };
  }

  /**
   * Adjusts the column widths to handle greed/etc.
   * @param  {int} forceIdx
   */
  adjustColumns(forceIdx){
    var width = this.options.internal.innerWidth - this.options.internal.scrollBarWidth;

    if(this.options.columnMode === 'force'){
      ForceFillColumnWidths(this.options.columns, width, forceIdx);
    } else if(this.options.columnMode === 'flex') {
      AdjustColumnWidths(this.options.columns, width);
    }
  }

  /**
   * Calculates the page size given the height * row height.
   * @return {[type]}
   */
  calculatePageSize(){
    this.options.paging.size = Math.ceil(
      this.options.internal.bodyHeight / this.options.rowHeight) + 1;
  }

  /**
   * Sorts the values of the grid for client side sorting.
   */
  onSorted(){
    if(!this.rows) return;

    // return all sorted column, in the same order in which they were sorted
    var sorts = this.options.columns
      .filter((c) => {
        return c.sort;
      })
      .sort((a, b) => {
        // sort the columns with lower sortPriority order first
        if (a.sortPriority && b.sortPriority){
          if (a.sortPriority > b.sortPriority) return 1;
          if (a.sortPriority < b.sortPriority) return -1;
        } else if (a.sortPriority){
          return -1;
        } else if (b.sortPriority){
          return 1;
        }

        return 0;
      })
      .map((c, i) => {
        // update sortPriority
        c.sortPriority = i + 1;
        return c;
      });

    if(sorts.length){
      this.onSort({sorts: sorts});

      if (this.options.onSort){
        this.options.onSort(sorts);
      }

      var clientSorts = [];
      for(var i=0, len=sorts.length; i < len; i++) {
        var c = sorts[i];
        if(c.comparator !== false){
          var dir = c.sort === 'asc' ? '' : '-';
          clientSorts.push(dir + c.prop);
        }
      }

      if(clientSorts.length){
        // todo: more ideal to just resort vs splice and repush
        // but wasn't responding to this change ...
        var sortedValues = this.$filter('orderBy')(this.rows, clientSorts);
        this.rows.splice(0, this.rows.length);
        this.rows.push(...sortedValues);
      }
    }

    this.options.internal.setYOffset(0);
  }

  /**
   * Invoked when a tree is collasped/expanded
   * @param  {row model}
   * @param  {cell model}
   */
  onTreeToggled(row, cell){
    this.onTreeToggle({
      row: row,
      cell: cell
    });
  }

  /**
   * Invoked when the body triggers a page change.
   * @param  {offset}
   * @param  {size}
   */
  onBodyPage(offset, size){
    this.onPage({
      offset: offset,
      size: size
    });
  }

  /**
   * Invoked when the footer triggers a page change.
   * @param  {offset}
   * @param  {size}
   */
  onFooterPage(offset, size){
    var pageBlockSize = this.options.rowHeight * size,
        offsetY = pageBlockSize * offset;

    this.options.internal.setYOffset(offsetY);
  }

  /**
   * Invoked when the header checkbox directive has changed.
   */
  onHeaderCheckboxChange(){
    if(this.rows){
      var matches = this.selected.length === this.rows.length;
      this.selected.splice(0, this.selected.length);

      if(!matches){
        this.selected.push(...this.rows);
      }
    }
  }

  /**
   * Returns if all the rows are selected
   * @return {Boolean} if all selected
   */
  isAllRowsSelected(){
    if(this.rows) return false;
    return this.selected.length === this.rows.length;
  }

  /**
   * Occurs when a header directive triggered a resize event
   * @param  {object} column
   * @param  {int} width
   */
  onResized(column, width){
    var idx =this.options.columns.indexOf(column);
    if(idx > -1){
      var column = this.options.columns[idx];
      column.width = width;
      column.canAutoResize = false;

      this.adjustColumns(idx);
      this.calculateColumns();
    }

    if (this.onColumnResize){
      this.onColumnResize({
        column: column,
        width: width
      });
    }
  }

  /**
   * Occurs when a row was selected
   * @param  {object} rows
   */
  onSelected(rows){
    this.onSelect({
      rows: rows
    });
  }

  /**
   * Occurs when a row was click but may not be selected.
   * @param  {object} row
   */
  onRowClicked(row){
    this.onRowClick({
      row: row
    });
  }

  /**
   * Occurs when a row was double click but may not be selected.
   * @param  {object} row
   */
  onRowDblClicked(row){
    this.onRowDblClick({
      row: row
    });
  }

}
<commit_msg>make comparator work for our case<commit_after>import angular from 'angular';
import { TableDefaults, ColumnDefaults } from '../defaults';
import { AdjustColumnWidths, ForceFillColumnWidths } from '../utils/math';
import { ColumnsByPin, ColumnGroupWidths, CamelCase, ObjectId, ScrollbarWidth } from '../utils/utils';

export class DataTableController {

  /**
   * Creates an instance of the DataTable Controller
   * @param  {scope}
   * @param  {filter}
   */
  /*@ngInject*/
  constructor($scope, $filter, $log, $transclude){
    Object.assign(this, {
      $scope: $scope,
      $filter: $filter,
      $log: $log
    });

    this.defaults();

    // set scope to the parent
    this.options.$outer = $scope.$parent;

    $scope.$watch('dt.options.columns', (newVal, oldVal) => {
      this.transposeColumnDefaults();

      if(newVal.length !== oldVal.length){
        this.adjustColumns();
      }

      this.calculateColumns();
    }, true);

    // default sort
    var watch = $scope.$watch('dt.rows', (newVal) => {
      if(newVal){
        watch();
        this.onSorted();
      }
    });
  }

  /**
   * Creates and extends default options for the grid control
   */
  defaults(){
    this.expanded = this.expanded || {};

    this.options = angular.extend(angular.
      copy(TableDefaults), this.options);

    angular.forEach(TableDefaults.paging, (v,k) => {
      if(!this.options.paging[k]){
        this.options.paging[k] = v;
      }
    });

    if(this.options.selectable && this.options.multiSelect){
      this.selected = this.selected || [];
    }
  }

  /**
   * On init or when a column is added, we need to
   * make sure all the columns added have the correct
   * defaults applied.
   */
  transposeColumnDefaults(){
    for(var i=0, len = this.options.columns.length; i < len; i++) {
      var column = this.options.columns[i];
      column.$id = ObjectId();

      angular.forEach(ColumnDefaults, (v,k) => {
        if(!column.hasOwnProperty(k)){
          column[k] = v;
        }
      });

      if(column.name && !column.prop){
        column.prop = CamelCase(column.name);
      }

      this.options.columns[i] = column;
    }
  }

  /**
   * Calculate column groups and widths
   */
  calculateColumns(){
    var columns = this.options.columns;
    this.columnsByPin = ColumnsByPin(columns);
    this.columnWidths = ColumnGroupWidths(this.columnsByPin, columns);
  }

  /**
   * Returns the css classes for the data table.
   * @return {style object}
   */
  tableCss(){
    return {
      'fixed': this.options.scrollbarV,
      'selectable': this.options.selectable,
      'checkboxable': this.options.checkboxSelection
    };
  }

  /**
   * Adjusts the column widths to handle greed/etc.
   * @param  {int} forceIdx
   */
  adjustColumns(forceIdx){
    var width = this.options.internal.innerWidth - this.options.internal.scrollBarWidth;

    if(this.options.columnMode === 'force'){
      ForceFillColumnWidths(this.options.columns, width, forceIdx);
    } else if(this.options.columnMode === 'flex') {
      AdjustColumnWidths(this.options.columns, width);
    }
  }

  /**
   * Calculates the page size given the height * row height.
   * @return {[type]}
   */
  calculatePageSize(){
    this.options.paging.size = Math.ceil(
      this.options.internal.bodyHeight / this.options.rowHeight) + 1;
  }

  /**
   * Sorts the values of the grid for client side sorting.
   */
  onSorted(){
    if(!this.rows) return;

    // return all sorted column, in the same order in which they were sorted
    var sorts = this.options.columns
      .filter((c) => {
        return c.sort;
      })
      .sort((a, b) => {
        // sort the columns with lower sortPriority order first
        if (a.sortPriority && b.sortPriority){
          if (a.sortPriority > b.sortPriority) return 1;
          if (a.sortPriority < b.sortPriority) return -1;
        } else if (a.sortPriority){
          return -1;
        } else if (b.sortPriority){
          return 1;
        }

        return 0;
      })
      .map((c, i) => {
        // update sortPriority
        c.sortPriority = i + 1;
        return c;
      });

    if(sorts.length){
      this.onSort({sorts: sorts});

      if (this.options.onSort){
        this.options.onSort(sorts);
      }

      var clientSorts = [];
      for(var i=0, len=sorts.length; i < len; i++) {
        var c = sorts[i];
        if(c.comparator !== false){
          var dir = c.sort === 'asc' ? '' : '-';
          if (c.prop.text !== undefined) {
            clientSorts.push(dir + c.prop.text);
          } else {
            clientSorts.push(dir + c.prop);
          }
        }
      }

      if(clientSorts.length){
        // todo: more ideal to just resort vs splice and repush
        // but wasn't responding to this change ...
        var sortedValues = this.$filter('orderBy')(this.rows, clientSorts);
        this.rows.splice(0, this.rows.length);
        this.rows.push(...sortedValues);
      }
    }

    this.options.internal.setYOffset(0);
  }

  /**
   * Invoked when a tree is collasped/expanded
   * @param  {row model}
   * @param  {cell model}
   */
  onTreeToggled(row, cell){
    this.onTreeToggle({
      row: row,
      cell: cell
    });
  }

  /**
   * Invoked when the body triggers a page change.
   * @param  {offset}
   * @param  {size}
   */
  onBodyPage(offset, size){
    this.onPage({
      offset: offset,
      size: size
    });
  }

  /**
   * Invoked when the footer triggers a page change.
   * @param  {offset}
   * @param  {size}
   */
  onFooterPage(offset, size){
    var pageBlockSize = this.options.rowHeight * size,
        offsetY = pageBlockSize * offset;

    this.options.internal.setYOffset(offsetY);
  }

  /**
   * Invoked when the header checkbox directive has changed.
   */
  onHeaderCheckboxChange(){
    if(this.rows){
      var matches = this.selected.length === this.rows.length;
      this.selected.splice(0, this.selected.length);

      if(!matches){
        this.selected.push(...this.rows);
      }
    }
  }

  /**
   * Returns if all the rows are selected
   * @return {Boolean} if all selected
   */
  isAllRowsSelected(){
    if(this.rows) return false;
    return this.selected.length === this.rows.length;
  }

  /**
   * Occurs when a header directive triggered a resize event
   * @param  {object} column
   * @param  {int} width
   */
  onResized(column, width){
    var idx =this.options.columns.indexOf(column);
    if(idx > -1){
      var column = this.options.columns[idx];
      column.width = width;
      column.canAutoResize = false;

      this.adjustColumns(idx);
      this.calculateColumns();
    }

    if (this.onColumnResize){
      this.onColumnResize({
        column: column,
        width: width
      });
    }
  }

  /**
   * Occurs when a row was selected
   * @param  {object} rows
   */
  onSelected(rows){
    this.onSelect({
      rows: rows
    });
  }

  /**
   * Occurs when a row was click but may not be selected.
   * @param  {object} row
   */
  onRowClicked(row){
    this.onRowClick({
      row: row
    });
  }

  /**
   * Occurs when a row was double click but may not be selected.
   * @param  {object} row
   */
  onRowDblClicked(row){
    this.onRowDblClick({
      row: row
    });
  }

}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

import styles from './style.css'

/*
 * Adapt flex-box based grid for the layout. It is much easier to work with
 * than bootstrap3/patternfly grids.
 */
const Grid = ({ children, id, className = '', style }) => {
  const cn = `${styles['grid-container']} ${className}`
  return
{children}

}
Grid.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
}

const Row = ({ children, id, className = '', style }) => {
  const cn = `${styles['grid-row']} ${className}`
  return
{children}

}
Row.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
}

const Col = ({
  children,
  id,
  className = '',
  style,
  cols = -1,
  offset = -1,
  content = 'expand',
  wrapExpand = false,
  ...props
}) => {
  const cn = `${styles['grid-column']} ${className}`

  if (cols === -1 && offset > 0) {
    cols = 12 - offset
  }
  const widthPercent = cols * 100 / 12
  const colStyle = cols <= 0
    ? {}
    : wrapExpand
      ? { flex: `1 0 ${widthPercent}%` }
      : {
        flex: `0 0 ${widthPercent}%`,
        maxWidth: `${widthPercent}%`,
      }
  const offsetStyle = offset < 1 ? {} : {
    marginLeft: `${offset * 100 / 12}%`,
  }

  return (

      {children}

  )
}
Col.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
  cols: function (props, propName, componentName) {
    if (props.cols && (props.cols < 1 || props.cols > 12)) {
      return new Error(`Prop 'cols' of component '${componentName}' is not in valid range of 1 .. 12 `)
    }
  },
  offset: function (props, propName, componentName) {
    if (props.offset !== undefined) {
      const maxOffset = props.cols ? 12 - props.cols : 11
      if (props.offset < 1 || props.offset > maxOffset) {
        return new Error(`Prop 'offset' of component '${componentName}' is not in valid range of 1 .. ${maxOffset}`)
      }
    }
  },
  content: PropTypes.oneOf(['expand', 'auto']),
  wrapExpand: PropTypes.bool,
}

export {
  Grid,
  Row,
  Col,
}
<commit_msg>Refactor GridComponents Col `offset` param<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import styles from './style.css'

/*
 * Adapt flex-box based grid for the layout. It is much easier to work with
 * than bootstrap3/patternfly grids.
 */
const Grid = ({ children, id, className = '', style }) => {
  const cn = `${styles['grid-container']} ${className}`
  return
{children}

}
Grid.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
}

const Row = ({ children, id, className = '', style }) => {
  const cn = `${styles['grid-row']} ${className}`
  return
{children}

}
Row.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
}

const Col = ({
  children,
  id,
  className = '',
  style,
  cols = -1,
  offset = -1,
  content = 'expand',
  wrapExpand = false,
  ...props
}) => {
  const cn = `${styles['grid-column']} ${className}`

  if (cols === -1 && offset > 0) {
    cols = 12 - offset
  }
  const widthPercent = cols * 100 / 12
  const colStyle = cols <= 0
    ? {}
    : wrapExpand
      ? { flex: `1 0 ${widthPercent}%` }
      : {
        flex: `0 0 ${widthPercent}%`,
        maxWidth: `${widthPercent}%`,
      }

  return <React.Fragment>
    { offset > 0 &&
      <div
        style={{
          flex: `0 0 ${offset * 100 / 12}%`,
          maxWidth: `${offset * 100 / 12}%`,
        }}
      />
    }

      {children}

  </React.Fragment>
}
Col.propTypes = {
  children: PropTypes.node.isRequired,
  id: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
  cols: function (props, propName, componentName) {
    if (props.cols && (props.cols < 1 || props.cols > 12)) {
      return new Error(`Prop 'cols' of component '${componentName}' is not in valid range of 1 .. 12 `)
    }
  },
  offset: function (props, propName, componentName) {
    if (props.offset !== undefined) {
      const maxOffset = props.cols ? 12 - props.cols : 11
      if (props.offset < 1 || props.offset > maxOffset) {
        return new Error(`Prop 'offset' of component '${componentName}' is not in valid range of 1 .. ${maxOffset}`)
      }
    }
  },
  content: PropTypes.oneOf(['expand', 'auto']),
  wrapExpand: PropTypes.bool,
}

export {
  Grid,
  Row,
  Col,
}
<|endoftext|>


<commit_before>import React from 'react'

const WelcomeMessage = () => (

Avez-vous déjà entendu des réflexions de ce genre :

"Il a bien une tête de gaucho, lui !" ou "Il a pas une dégaine à voter Mitterand..."

Gauche ou Droite ? a pour objectif de tester cette afirmation.

Le bord politique d'un député se reconnaît-il au premier coup d'oeil ? Nos amis de l'assemblée sont-ils victimes de délit de faciès ?

À vous de nous le dire !

)

export default WelcomeMessage
<commit_msg>Fix some texts (again lol)<commit_after>import React from 'react'

const WelcomeMessage = () => (

Peut-être avez-vous déjà entendu ce type de réflexions :

"Il a bien une tête de gaucho, lui !" ou "Il a pas une dégaine à voter Mitterand..."

Gauche ou Droite ? a pour objectif de vérifier ces affirmations.

Le bord politique d'un député se reconnaît-il au premier coup d'oeil ? Nos amis de l'assemblée sont-ils victimes de délit de faciès ?

À vous de nous le dire !

)

export default WelcomeMessage
<|endoftext|>


<commit_before>import React from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { push } from "redux-router";

import { CardOverlay } from "../CardOverlay";
import { Card, CardText } from 'material-ui/Card';

import { Actions } from "./redux/actions";
import {
    Actions as ServiceActions,
    ActionKeyStore as ServiceActionKeyStore
} from "../../services/servicemanager/redux/actions";
import {
    Actions as ConfigurationsActions,
    ActionKeyStore as ConfigurationsActionKeyStore
} from "../../services/configurations/redux/actions";

import { resizeVisualization } from "../../utils/resize"

import { GraphManager } from "../Graphs/index";
import { ServiceManager } from "../../services/servicemanager/index";

import style from "./styles"

import FontAwesome from "react-fontawesome";

class VisualizationView extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            parameterizable: true,
            hasResults: false,
            showDescription: false,
        }
    }

    componentWillMount() {
        this.initialize(this.props.id);
    }

    componentDidMount() {
        this.updateSize();

        // If present, register the resize callback
        // to respond to interactive resizes from react-grid-layout.
        if (this.props.registerResize) {
            this.props.registerResize(this.updateSize.bind(this))
        }
    }

    componentWillReceiveProps(nextProps) {
        this.initialize(nextProps.id);
    }

    componentDidUpdate() {
        this.updateSize();
    }

    updateSize() {
        if (this._element) {
            const { width, height } = resizeVisualization(this._element);

            if (width !== this.state.width || height !== this.state.height) {
                this.setState({ width, height });
            }
        }
    }

    initialize(id) {

        this.props.fetchConfigurationIfNeeded(id).then((c) => {
            const { configuration } = this.props

            if (!configuration)
                return;

            this.props.fetchQueryIfNeeded(configuration.get("query")).then(() => {
                const { queryConfiguration, executeQueryIfNeeded, context } = this.props;

                if (!queryConfiguration)
                    return;

                executeQueryIfNeeded(queryConfiguration, context).then(
                    () => {
                        this.setState({
                            parameterizable: true,
                        });
                    },
                    (error) => {
                        this.setState({
                            parameterizable: false,
                        });
                    },
                );
            });

            if(configuration.get("listeners")){
                this.setState({
                    listeners: configuration.get("listeners").reduce((listeners, listener) => {
                        const {
                            event = "onMarkClick",
                            redirect = window.location.pathname,
                            params = {}
                        } = listener.toJS();

                        listeners[event] = (d) => {

                            console.log("TODO navigate to " + redirect);
                            console.log(d);

                            Object.keys(params).forEach((destinationParam) => {
                                const sourceColumn = params[destinationParam];
                                console.log("sourceColumn = " + sourceColumn);
                                console.log("destinationParam = " + destinationParam);
                                console.log(destinationParam + "=" + d[sourceColumn]);
                            });
                        };

                        return listeners;
                    }, {})
                });
            }
        });
    }

    shouldShowVisualization() {
        const { configuration, response } = this.props;

        return configuration && response && !response.isFetching;
    }

    renderVisualization() {
        const { configuration, queryConfiguration, response } = this.props;

        const graphName      = configuration.get("graph"),
              GraphComponent = GraphManager.getGraphComponent(graphName);

        let description;

        if (this.state.showDescription) {
            description = <CardOverlay
                                overlayStyle={style.descriptionContainer}
                                textStyle={style.descriptionText}
                                text={configuration.get("description")}
                                onTouchTapOverlay={() => { this.setState({showDescription: false}); }}
                                />
        }

        return (

                <GraphComponent
                  response={response}
                  configuration={configuration.toJS()}
                  queryConfiguration={queryConfiguration}
                  width={this.state.width}
                  height={this.state.height}
                  {...this.state.listeners}
                />
                {description}

        )
    }

    renderVisualizationIfNeeded() {
        if (this.shouldShowVisualization()) {
            return this.renderVisualization();
        }

        if (!this.state.parameterizable) {
            return (
                <CardOverlay
                    overlayStyle={style.overlayContainer}
                    textStyle={style.overlayText}
                    text={(

                            <FontAwesome
                                name="meh-o"
                                size="2x"
                                />

                            Oops, we are missing some parameters here!

                    )}
                    onTouchTapOverlay={() => { this.setState({showDescription: false}); }}
                    />
            )
        }

        return (

                    <FontAwesome
                        name="circle-o-notch"
                        spin
                        />

                    Please wait while loading...

        )
    }

    shouldShowTitle() {
        const { configuration } = this.props;

        return configuration && configuration.get("title") && this.state.parameterizable;
    }

    renderTitleIfNeeded() {
        const { configuration } = this.props;

        if (!this.shouldShowTitle())
            return;

        const descriptionIcon = !configuration.get("description") ? null : (

                <FontAwesome
                    name="info-circle"
                    onTouchTap={() => { this.setState({showDescription: !!configuration.get("description")}); }}
                    />

        )

        return (

                {configuration.get("title")}
                {descriptionIcon}

        )
    }

    cardTextReference = (c) => {
        if (this._element)
            return;

        this._element = ReactDOM.findDOMNode(c).parentElement;
    }

    render() {
        return (
            <Card
              style={style.card}
              containerStyle={style.cardContainer}
              ref={this.cardTextReference}
            >
                { this.renderTitleIfNeeded() };
                <CardText style={style.cardText}>
                    { this.renderVisualizationIfNeeded() }
                </CardText>
            </Card>
        );
    }
}

const mapStateToProps = (state, ownProps) => {

    const configurationID = ownProps.id || ownProps.params.id,
          context         = ownProps.context || ownProps.location.query;

    const props = {
        id: configurationID,
        context: context,

        configuration: state.configurations.getIn([
            ConfigurationsActionKeyStore.VISUALIZATIONS,
            configurationID,
            ConfigurationsActionKeyStore.DATA
        ]),

        error: state.configurations.getIn([
            ConfigurationsActionKeyStore.VISUALIZATIONS,
            configurationID,
            ConfigurationsActionKeyStore.ERROR
        ])

    };

    // Expose the query template as a JS object if it is available.
    if (props.configuration) {
        const queryConfiguration = state.configurations.getIn([
            ConfigurationsActionKeyStore.QUERIES,
            props.configuration.get("query")
        ]);

        if (queryConfiguration && !queryConfiguration.get(
            ConfigurationsActionKeyStore.IS_FETCHING
        )) {
            props.queryConfiguration = queryConfiguration.get(
                ConfigurationsActionKeyStore.DATA
            ).toJS();
        }

        // Expose received response if it is available
        if (props.queryConfiguration) {
            const requestID = ServiceManager.getRequestID(props.queryConfiguration, context);

            let response = state.services.getIn([
                ServiceActionKeyStore.REQUESTS,
                requestID
            ]);

            if (response && !response.get(ServiceActionKeyStore.IS_FETCHING))
                props.response = response.toJS();
        }
    }

    return props;
};

const actionCreators = (dispatch) => ({

    setPageTitle: function(aTitle) {
        dispatch(Actions.updateTitle(aTitle));
    },

    goTo: function(link, filters) {
        dispatch(push({pathname:link, query:filters}));
    },

    fetchConfigurationIfNeeded: function(id) {
        return dispatch(ConfigurationsActions.fetchIfNeeded(
            id,
            ConfigurationsActionKeyStore.VISUALIZATIONS
        ));
    },

    fetchQueryIfNeeded: function(id) {
        return dispatch(ConfigurationsActions.fetchIfNeeded(
            id,
            ConfigurationsActionKeyStore.QUERIES
        ));
    },

    executeQueryIfNeeded: function(queryConfiguration, context) {
        return dispatch(ServiceActions.fetchIfNeeded(queryConfiguration, context));
    }

 });

export default connect(mapStateToProps, actionCreators)(VisualizationView);
<commit_msg>Navigate based on configured listeners. Closes #23<commit_after>import React from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { push } from "redux-router";

import { CardOverlay } from "../CardOverlay";
import { Card, CardText } from 'material-ui/Card';

import { Actions } from "./redux/actions";
import {
    Actions as ServiceActions,
    ActionKeyStore as ServiceActionKeyStore
} from "../../services/servicemanager/redux/actions";
import {
    Actions as ConfigurationsActions,
    ActionKeyStore as ConfigurationsActionKeyStore
} from "../../services/configurations/redux/actions";

import { resizeVisualization } from "../../utils/resize"

import { GraphManager } from "../Graphs/index";
import { ServiceManager } from "../../services/servicemanager/index";

import style from "./styles"

import FontAwesome from "react-fontawesome";

class VisualizationView extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            parameterizable: true,
            hasResults: false,
            showDescription: false,
        }
    }

    componentWillMount() {
        this.initialize(this.props.id);
    }

    componentDidMount() {
        this.updateSize();

        // If present, register the resize callback
        // to respond to interactive resizes from react-grid-layout.
        if (this.props.registerResize) {
            this.props.registerResize(this.updateSize.bind(this))
        }
    }

    componentWillReceiveProps(nextProps) {
        this.initialize(nextProps.id);
    }

    componentDidUpdate() {
        this.updateSize();
    }

    updateSize() {
        if (this._element) {
            const { width, height } = resizeVisualization(this._element);

            if (width !== this.state.width || height !== this.state.height) {
                this.setState({ width, height });
            }
        }
    }

    initialize(id) {

        this.props.fetchConfigurationIfNeeded(id).then((c) => {
            const { configuration } = this.props

            if (!configuration)
                return;

            this.props.fetchQueryIfNeeded(configuration.get("query")).then(() => {
                const { queryConfiguration, executeQueryIfNeeded, context } = this.props;

                if (!queryConfiguration)
                    return;

                executeQueryIfNeeded(queryConfiguration, context).then(
                    () => {
                        this.setState({
                            parameterizable: true,
                        });
                    },
                    (error) => {
                        this.setState({
                            parameterizable: false,
                        });
                    },
                );
            });

            if(configuration.get("listeners")){
                this.setState({
                    listeners: configuration.get("listeners").reduce((listeners, listener) => {
                        const {
                            event = "onMarkClick",
                            redirect = window.location.pathname,
                            params = {}
                        } = listener.toJS();

                        listeners[event] = (d) => {

                            console.log("TODO navigate to " + redirect);

                            const queryParams = Object.keys(params)
                                .reduce((queryParams, destinationParam) => {
                                    const sourceColumn = params[destinationParam];
                                    queryParams[destinationParam] = d[sourceColumn];
                                    return queryParams;
                                }, {});

                            this.props.goTo(redirect, queryParams);
                        };

                        return listeners;
                    }, {})
                });
            }
        });
    }

    shouldShowVisualization() {
        const { configuration, response } = this.props;

        return configuration && response && !response.isFetching;
    }

    renderVisualization() {
        const { configuration, queryConfiguration, response } = this.props;

        const graphName      = configuration.get("graph"),
              GraphComponent = GraphManager.getGraphComponent(graphName);

        let description;

        if (this.state.showDescription) {
            description = <CardOverlay
                                overlayStyle={style.descriptionContainer}
                                textStyle={style.descriptionText}
                                text={configuration.get("description")}
                                onTouchTapOverlay={() => { this.setState({showDescription: false}); }}
                                />
        }

        return (

                <GraphComponent
                  response={response}
                  configuration={configuration.toJS()}
                  queryConfiguration={queryConfiguration}
                  width={this.state.width}
                  height={this.state.height}
                  {...this.state.listeners}
                />
                {description}

        )
    }

    renderVisualizationIfNeeded() {
        if (this.shouldShowVisualization()) {
            return this.renderVisualization();
        }

        if (!this.state.parameterizable) {
            return (
                <CardOverlay
                    overlayStyle={style.overlayContainer}
                    textStyle={style.overlayText}
                    text={(

                            <FontAwesome
                                name="meh-o"
                                size="2x"
                                />

                            Oops, we are missing some parameters here!

                    )}
                    onTouchTapOverlay={() => { this.setState({showDescription: false}); }}
                    />
            )
        }

        return (

                    <FontAwesome
                        name="circle-o-notch"
                        spin
                        />

                    Please wait while loading...

        )
    }

    shouldShowTitle() {
        const { configuration } = this.props;

        return configuration && configuration.get("title") && this.state.parameterizable;
    }

    renderTitleIfNeeded() {
        const { configuration } = this.props;

        if (!this.shouldShowTitle())
            return;

        const descriptionIcon = !configuration.get("description") ? null : (

                <FontAwesome
                    name="info-circle"
                    onTouchTap={() => { this.setState({showDescription: !!configuration.get("description")}); }}
                    />

        )

        return (

                {configuration.get("title")}
                {descriptionIcon}

        )
    }

    cardTextReference = (c) => {
        if (this._element)
            return;

        this._element = ReactDOM.findDOMNode(c).parentElement;
    }

    render() {
        return (
            <Card
              style={style.card}
              containerStyle={style.cardContainer}
              ref={this.cardTextReference}
            >
                { this.renderTitleIfNeeded() };
                <CardText style={style.cardText}>
                    { this.renderVisualizationIfNeeded() }
                </CardText>
            </Card>
        );
    }
}

const mapStateToProps = (state, ownProps) => {

    const configurationID = ownProps.id || ownProps.params.id,
          context         = ownProps.context || ownProps.location.query;

    const props = {
        id: configurationID,
        context: context,

        configuration: state.configurations.getIn([
            ConfigurationsActionKeyStore.VISUALIZATIONS,
            configurationID,
            ConfigurationsActionKeyStore.DATA
        ]),

        error: state.configurations.getIn([
            ConfigurationsActionKeyStore.VISUALIZATIONS,
            configurationID,
            ConfigurationsActionKeyStore.ERROR
        ])

    };

    // Expose the query template as a JS object if it is available.
    if (props.configuration) {
        const queryConfiguration = state.configurations.getIn([
            ConfigurationsActionKeyStore.QUERIES,
            props.configuration.get("query")
        ]);

        if (queryConfiguration && !queryConfiguration.get(
            ConfigurationsActionKeyStore.IS_FETCHING
        )) {
            props.queryConfiguration = queryConfiguration.get(
                ConfigurationsActionKeyStore.DATA
            ).toJS();
        }

        // Expose received response if it is available
        if (props.queryConfiguration) {
            const requestID = ServiceManager.getRequestID(props.queryConfiguration, context);

            let response = state.services.getIn([
                ServiceActionKeyStore.REQUESTS,
                requestID
            ]);

            if (response && !response.get(ServiceActionKeyStore.IS_FETCHING))
                props.response = response.toJS();
        }
    }

    return props;
};

const actionCreators = (dispatch) => ({

    setPageTitle: function(aTitle) {
        dispatch(Actions.updateTitle(aTitle));
    },

    goTo: function(link, filters) {
        dispatch(push({pathname:link, query:filters}));
    },

    fetchConfigurationIfNeeded: function(id) {
        return dispatch(ConfigurationsActions.fetchIfNeeded(
            id,
            ConfigurationsActionKeyStore.VISUALIZATIONS
        ));
    },

    fetchQueryIfNeeded: function(id) {
        return dispatch(ConfigurationsActions.fetchIfNeeded(
            id,
            ConfigurationsActionKeyStore.QUERIES
        ));
    },

    executeQueryIfNeeded: function(queryConfiguration, context) {
        return dispatch(ServiceActions.fetchIfNeeded(queryConfiguration, context));
    }

 });

export default connect(mapStateToProps, actionCreators)(VisualizationView);
<|endoftext|>