<commit_before>cdb.admin.mod.HeatmapWizard = cdb.admin.mod.SimpleWizard.extend({

  MODULES: ["infowindow"],

  initialize: function() {
    this.options.form = cdb.admin.forms.heatmap;
    cdb.admin.mod.SimpleWizard.prototype.initialize.call(this);

    this.type = 'heatmap';
  },

  isValid: function() {
    return this._getNumberColumns().length > 0;
  }

});

<commit_msg>Triggers the heatmap wizard<commit_after>cdb.admin.mod.HeatmapWizard = cdb.admin.mod.SimpleWizard.extend({

  MODULES: ["infowindow"],

  initialize: function() {
    this.options.form = cdb.admin.forms.heatmap;
    cdb.admin.mod.SimpleWizard.prototype.initialize.call(this);

    this.type = 'heatmap';

    this.options.table.bind('change:schema', function() {
      this.render();
    }, this);
  },

  render: function() {
    cdb.admin.mod.SimpleWizard.prototype.render.call(this);
    return this;
  }

});

<|endoftext|>


<commit_before>var StyleGenerator = require('../../../../../javascripts/cartodb3/editor/style/style-converter');

module.exports = [
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          },
          'image': null
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\nmarker-allow-overlap: true;\n}',
        type: 'CartoDB'
      },
      line: {
        cartocss: '#layer {\n}',
        type: 'CartoDB'
      },
      polygon: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        type: 'CartoDB'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        stroke: {
          'size': {
            fixed: 2
          },
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-line-width: 2;\nmarker-line-color: #000;\nmarker-line-opacity: 0.4;\n}',
        type: 'CartoDB'
      },
      line: {
        cartocss: '#layer {\nline-width: 2;\nline-color: #000;\nline-opacity: 0.4;\n}',
        type: 'CartoDB'
      },
      polygon: {
        cartocss: '#layer {\nline-width: 2;\nline-color: #000;\nline-opacity: 0.4;\n}';
        type: 'CartoDB'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          },
          'image': null
        },
        animated: {
          enabled: true,
          attribute: 'test',
          overlap: 'linear',
          duration: 30,
          steps: 256,
          resolution: 2,
          trails: 2
        }
      }
    },
    result: {
      point: {
        cartocss: 'Map {\n-torque-frame-count: 256;\n-torque-animation-duration: 30;\n-torque-time-attribute: "test";\n-torque-aggregation-function: "count(1)";\n-torque-resolution: 2;\n-torque-data-aggregation: linear;\n}#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\nmarker-allow-overlap: true;\n}',
        type: 'torque'
      },
      line: {
        cartocss: '#layer {\n}'
      },
      polygon: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        labels: {
          enabled: true,
          attribute: null,
          font: 'DejaVu Sans Book',
          fill: {
            'size': {
              fixed: 10
            },
            'color': {
              fixed: '#000',
              opacity: 1
            }
          },
          halo: {
            'size': {
              fixed: 1
            },
            'color': {
              fixed: '#111',
              opacity: 1
            }
          },
          offset: -10,
          overlap: true,
          placement: 'point'
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      },
      line: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      },
      polygon: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        labels: {
          enabled: true,
          attribute: 'test',
          font: 'DejaVu Sans Book',
          fill: {
            'size': {
              fixed: 10
            },
            'color': {
              fixed: '#000',
              opacity: 1
            }
          },
          halo: {
            'size': {
              fixed: 1
            },
            'color': {
              fixed: '#111',
              opacity: 1
            }
          },
          offset: -10,
          overlap: true,
          placement: 'point'
        }
      }
    },
    result: {
      point: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      },
      line: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      },
      polygon: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          size: {
            range: [1, 20],
            attribute: 'cartodb_id'
          },
          color: {
            range: 'colorbrewer(Greens)',
            attribute: 'test',
            bins: 6,
            operation: 'multiply',
            quantification: 'jenks',
            opacity: 0.5
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-width: ramp([cartodb_id], 1, 20);\nmarker-fill: ramp([test], colorbrewer(Greens), 6, jenks);\nmarker-comp-op: multiply;\nmarker-fill-opacity: 0.5;\nmarker-allow-overlap: true;\n}'
      },
      /*
      ,line: {
        cartocss: '#layer {\n}'
      },
      */
      polygon: {
        cartocss: '#layer {\npolygon-fill: ramp([test], colorbrewer(Greens), 6, jenks);\npolygon-comp-op: multiply;\npolygon-opacity: 0.5;\n}'
      }
    }
  },
  {
    style: {
      type: 'hexabins',
      properties: {
        aggregation: {
          size: 100,
          value: {
            operation: 'count',
            attribute: 'test'
          }
        },
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: 'WITH hgrid AS (SELECT CDB_HexagonGrid(ST_Expand(!bbox!, greatest(!pixel_width!,!pixel_height!) * 100), greatest(!pixel_width!,!pixel_height!) * 100) as cell) SELECT hgrid.cell as the_geom_webmercator, count(1) as points_count, count(1)/power( 100 * CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!)), 2 ) as points_density, 1 as cartodb_id FROM hgrid, (<%= sql %>) i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell'
      }
    }
  },
  {
    style: {
      type: 'regions',
      properties: {
        aggregation: {
          dataset: 'adm0',
          value: {
            operation: 'sum',
            attribute: 'testing'
          }
        },
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    /*result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: 'SELECT _poly.*, _merge.point_agg FROM adm0 _poly, lateral (\nSELECT count(1) point_agg FROM (<%= sql %>) _point where ST_Contains(_poly.the_geom_webmercator, _point.the_geom_webmercator) ) _merge'
      }
    }*/
    result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: "SELECT _poly.*, _merge.point_agg FROM adm0 _poly, lateral (\nSELECT sum(testing) point_agg FROM (<%= sql %>) _point where ST_Contains(_poly.the_geom_webmercator, _point.the_geom_webmercator) ) _merge"
      }
    }
  },
  {
    style: {
      type: 'none',
    },
    result: {
        point: {
          cartocss: StyleGenerator.GENERIC_STYLE
        },
        line: {
          cartocss: StyleGenerator.GENERIC_STYLE
        },
        polygon: {
          cartocss: StyleGenerator.GENERIC_STYLE
        }
    }
  }
  /*
{
  style: {
    type: 'squares',
    aggregation: {
      aggr_size: {
        size: {
          fixed: 100
        },
        distance_unit: {
          fixed: 'meters'
        }
      }
    },
    properties: {
      fill: {
        'color': {
          fixed: '#000',
          opacity: 0.4
        }
      }
    }
  },
  result: {
    point: {
      cartocss: 'Map {\n-torque-frame-count: 256;\n-torque-animation-duration: 30;\n-torque-time-attribute: "test";\n-torque-aggregation-function: "count(1)";\n-torque-resolution: 2;\n-torque-data-aggregation: linear;\n}#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\n}'
    }
  }
}
*/
];
<commit_msg>fixed tests<commit_after>var StyleGenerator = require('../../../../../javascripts/cartodb3/editor/style/style-converter');

module.exports = [
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          },
          'image': null
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\nmarker-allow-overlap: true;\n}',
        type: 'CartoDB'
      },
      line: {
        cartocss: '#layer {\n}',
        type: 'CartoDB'
      },
      polygon: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        type: 'CartoDB'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        stroke: {
          'size': {
            fixed: 2
          },
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-line-width: 2;\nmarker-line-color: #000;\nmarker-line-opacity: 0.4;\n}',
        type: 'CartoDB'
      },
      line: {
        cartocss: '#layer {\nline-width: 2;\nline-color: #000;\nline-opacity: 0.4;\n}',
        type: 'CartoDB'
      },
      polygon: {
        cartocss: '#layer {\nline-width: 2;\nline-color: #000;\nline-opacity: 0.4;\n}',
        type: 'CartoDB'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          },
          'image': null
        },
        animated: {
          enabled: true,
          attribute: 'test',
          overlap: 'linear',
          duration: 30,
          steps: 256,
          resolution: 2,
          trails: 2
        }
      }
    },
    result: {
      point: {
        cartocss: 'Map {\n-torque-frame-count: 256;\n-torque-animation-duration: 30;\n-torque-time-attribute: "test";\n-torque-aggregation-function: "count(1)";\n-torque-resolution: 2;\n-torque-data-aggregation: linear;\n}#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\nmarker-allow-overlap: true;\n}',
        type: 'torque'
      },
      line: {
        cartocss: '#layer {\n}'
      },
      polygon: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        labels: {
          enabled: true,
          attribute: null,
          font: 'DejaVu Sans Book',
          fill: {
            'size': {
              fixed: 10
            },
            'color': {
              fixed: '#000',
              opacity: 1
            }
          },
          halo: {
            'size': {
              fixed: 1
            },
            'color': {
              fixed: '#111',
              opacity: 1
            }
          },
          offset: -10,
          overlap: true,
          placement: 'point'
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      },
      line: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      },
      polygon: {
        cartocss: '#layer {\n}\n#layer::labels {\n}'
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        labels: {
          enabled: true,
          attribute: 'test',
          font: 'DejaVu Sans Book',
          fill: {
            'size': {
              fixed: 10
            },
            'color': {
              fixed: '#000',
              opacity: 1
            }
          },
          halo: {
            'size': {
              fixed: 1
            },
            'color': {
              fixed: '#111',
              opacity: 1
            }
          },
          offset: -10,
          overlap: true,
          placement: 'point'
        }
      }
    },
    result: {
      point: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      },
      line: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      },
      polygon: {
        cartocss: "#layer {\n}\n#layer::labels {\ntext-name: [test];\ntext-face-name: 'DejaVu Sans Book';\ntext-size: 10;\ntext-fill: #000;\ntext-label-position-tolerance: 0;\ntext-halo-radius: 1;\ntext-halo-fill: #111;\ntext-dy: -10;\ntext-allow-overlap: true;\ntext-placement: point;\ntext-placement-type: dummy;\n}"
      }
    }
  },
  {
    style: {
      type: 'simple',
      properties: {
        fill: {
          size: {
            range: [1, 20],
            attribute: 'cartodb_id'
          },
          color: {
            range: 'colorbrewer(Greens)',
            attribute: 'test',
            bins: 6,
            operation: 'multiply',
            quantification: 'jenks',
            opacity: 0.5
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\nmarker-width: ramp([cartodb_id], 1, 20);\nmarker-fill: ramp([test], colorbrewer(Greens), 6, jenks);\nmarker-comp-op: multiply;\nmarker-fill-opacity: 0.5;\nmarker-allow-overlap: true;\n}'
      },
      /*
      ,line: {
        cartocss: '#layer {\n}'
      },
      */
      polygon: {
        cartocss: '#layer {\npolygon-fill: ramp([test], colorbrewer(Greens), 6, jenks);\npolygon-comp-op: multiply;\npolygon-opacity: 0.5;\n}'
      }
    }
  },
  {
    style: {
      type: 'hexabins',
      properties: {
        aggregation: {
          size: 100,
          value: {
            operation: 'count',
            attribute: 'test'
          }
        },
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: 'WITH hgrid AS (SELECT CDB_HexagonGrid(ST_Expand(!bbox!, greatest(!pixel_width!,!pixel_height!) * 100), greatest(!pixel_width!,!pixel_height!) * 100) as cell) SELECT hgrid.cell as the_geom_webmercator, count(1) as points_count, count(1)/power( 100 * CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!)), 2 ) as points_density, 1 as cartodb_id FROM hgrid, (<%= sql %>) i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell'
      }
    }
  },
  {
    style: {
      type: 'regions',
      properties: {
        aggregation: {
          dataset: 'adm0',
          value: {
            operation: 'sum',
            attribute: 'testing'
          }
        },
        fill: {
          'color': {
            fixed: '#000',
            opacity: 0.4
          }
        }
      }
    },
    /*result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: 'SELECT _poly.*, _merge.point_agg FROM adm0 _poly, lateral (\nSELECT count(1) point_agg FROM (<%= sql %>) _point where ST_Contains(_poly.the_geom_webmercator, _point.the_geom_webmercator) ) _merge'
      }
    }*/
    result: {
      point: {
        cartocss: '#layer {\npolygon-fill: #000;\npolygon-opacity: 0.4;\n}',
        sql: "SELECT _poly.*, _merge.point_agg FROM adm0 _poly, lateral (\nSELECT sum(testing) point_agg FROM (<%= sql %>) _point where ST_Contains(_poly.the_geom_webmercator, _point.the_geom_webmercator) ) _merge"
      }
    }
  },
  {
    style: {
      type: 'none',
    },
    result: {
        point: {
          cartocss: StyleGenerator.GENERIC_STYLE
        },
        line: {
          cartocss: StyleGenerator.GENERIC_STYLE
        },
        polygon: {
          cartocss: StyleGenerator.GENERIC_STYLE
        }
    }
  }
  /*
{
  style: {
    type: 'squares',
    aggregation: {
      aggr_size: {
        size: {
          fixed: 100
        },
        distance_unit: {
          fixed: 'meters'
        }
      }
    },
    properties: {
      fill: {
        'color': {
          fixed: '#000',
          opacity: 0.4
        }
      }
    }
  },
  result: {
    point: {
      cartocss: 'Map {\n-torque-frame-count: 256;\n-torque-animation-duration: 30;\n-torque-time-attribute: "test";\n-torque-aggregation-function: "count(1)";\n-torque-resolution: 2;\n-torque-data-aggregation: linear;\n}#layer {\nmarker-fill: #000;\nmarker-fill-opacity: 0.4;\n}'
    }
  }
}
*/
];
<|endoftext|>


<commit_before>define(['app/topology/topology.module'], function(topology) {

  topology.register.factory('TopologyRestangular', function(Restangular, ENV) {
    return Restangular.withConfig(function(RestangularConfig) {
      RestangularConfig.setBaseUrl(ENV.baseURL);
    });
  });

  topology.register.factory('NetworkTopologySvc', function(TopologyRestangular) {
      var svc = {
          base: function() {
              return TopologyRestangular.one('restconf').one('operational').one('network-topology:network-topology');
          },
          data: null,
          TOPOLOGY_CONST: {
              HT_SERVICE_ID:"host-tracker-service:id",
              IP:"ip",
              HT_SERVICE_ATTPOINTS:"host-tracker-service:attachment-points",
              HT_SERVICE_TPID:"host-tracker-service:tp-id",
              NODE_ID:"node-id",
              SOURCE_NODE:"source-node",
              DEST_NODE:"dest-node",
              SOURCE_TP:"source-tp",
              DEST_TP:"dest-tp",
              ADDRESSES:"addresses"
          }
      };
      svc.getCurrentData = function() {
          return svc.data;
      };
      svc.getAllNodes = function() {
          svc.data = svc.base().getList();
          return svc.data;
      };
      svc.getNode = function(node,cb) {
          //Determines the node id from the nodes array corresponding to the text passed
          var getNodeIdByText = function getNodeIdByText(inNodes, text) {
              var nodes = inNodes.filter(function(item, index) {
                      return item.label === text;
                  }),
                  nodeId;

              if(nodes && nodes[0]) {
                  nodeId = nodes[0].id;
              }else{
                  return null;
              }

              return nodeId;
          };
          //Checks if the edge is present in the links map or not so we show single edge link between switches
          var isEdgePresent = function(inLinks,srcId,dstId){
              if( inLinks[srcId+":"+dstId] === undefined && inLinks[dstId+":"+srcId] === undefined) {
                  return false;
              }
              else {
                  return true;
              }
          };
          return svc.base().one("topology", node).get().then(function(ntData){

              var nodes = [];
              var links = [];
              var linksMap = {};

              if(ntData.topology && ntData.topology[0]){
                  //Loop over the nodes
                  angular.forEach(ntData.topology[0].node, function(nodeData) {
                    var groupType = "", nodeTitle = "", nodeLabel = "";
                    var nodeId = nodeData[svc.TOPOLOGY_CONST.NODE_ID];
                      if(nodeId!==undefined && nodeId.indexOf("host")>=0){
                        groupType = "host";
                        var ht_serviceadd = nodeData[svc.TOPOLOGY_CONST.ADDRESSES];
                        //get title info
                            for(var i=0;i<ht_serviceadd.length;i++){
                                nodeTitle += 'IP: ' + ht_serviceadd[i][svc.TOPOLOGY_CONST.IP] + '
';
                            }
                        nodeTitle += 'Type: Host';
                      }
                      else{
                        groupType = "switch";
                        nodeTitle = 'Name: ' + nodeId + '
Type: Switch';
                      }

                    nodeLabel = nodeData[svc.TOPOLOGY_CONST.NODE_ID];
                    nodes.push({'id': nodes.length.toString(), 'label': nodeLabel, group: groupType,value:20,title:nodeTitle});
                  });
                  //Loops over the links
                  angular.forEach(ntData.topology[0].link, function(linkData) {
                      var srcId = getNodeIdByText(nodes, linkData.source[svc.TOPOLOGY_CONST.SOURCE_NODE]),
                          dstId = getNodeIdByText(nodes, linkData.destination[svc.TOPOLOGY_CONST.DEST_NODE]),
                          srcPort = linkData.source[svc.TOPOLOGY_CONST.SOURCE_TP],
                          dstPort = linkData.destination[svc.TOPOLOGY_CONST.DEST_TP],
                          linkId = links.length.toString();
                      if(srcId!=null && dstId!=null && !isEdgePresent(linksMap,srcId,dstId)){
                          links.push({id: linkId, 'from' : srcId, 'to': dstId, title:'Source Port: ' + srcPort + '
Dest Port: '+dstPort+''});
                          linksMap[srcId+":"+dstId]=linkId;
                      }
                  });

              }

              var data = {
                  "nodes" : nodes,
                  "links" : links
              };
              cb(data);
          },function(response) {
              console.log("Error with status code", response.status);
          });
      };
      return svc;
  });

});
<commit_msg>Bug 1857 - Support dlux topology with or without prefixes in the json response<commit_after>define(['app/topology/topology.module'], function(topology) {

  topology.register.factory('TopologyRestangular', function(Restangular, ENV) {
    return Restangular.withConfig(function(RestangularConfig) {
      RestangularConfig.setBaseUrl(ENV.baseURL);
    });
  });

  topology.register.factory('NetworkTopologySvc', function(TopologyRestangular) {
      var svc = {
          base: function() {
              return TopologyRestangular.one('restconf').one('operational').one('network-topology:network-topology');
          },
          data: null,
          TOPOLOGY_CONST: {
              HT_SERVICE_ID:"host-tracker-service:id",
              IP:"ip",
              HT_SERVICE_ATTPOINTS:"host-tracker-service:attachment-points",
              HT_SERVICE_TPID:"host-tracker-service:tp-id",
              NODE_ID:"node-id",
              SOURCE_NODE:"source-node",
              DEST_NODE:"dest-node",
              SOURCE_TP:"source-tp",
              DEST_TP:"dest-tp",
              ADDRESSES:"addresses",
              HT_SERVICE_ADDS:"host-tracker-service:addresses",
              HT_SERVICE_IP:"host-tracker-service:ip"
          }
      };
      svc.getCurrentData = function() {
          return svc.data;
      };
      svc.getAllNodes = function() {
          svc.data = svc.base().getList();
          return svc.data;
      };
      svc.getNode = function(node,cb) {
          //Determines the node id from the nodes array corresponding to the text passed
          var getNodeIdByText = function getNodeIdByText(inNodes, text) {
              var nodes = inNodes.filter(function(item, index) {
                      return item.label === text;
                  }),
                  nodeId;

              if(nodes && nodes[0]) {
                  nodeId = nodes[0].id;
              }else{
                  return null;
              }

              return nodeId;
          };
          //Checks if the edge is present in the links map or not so we show single edge link between switches
          var isEdgePresent = function(inLinks,srcId,dstId){
              if( inLinks[srcId+":"+dstId] === undefined && inLinks[dstId+":"+srcId] === undefined) {
                  return false;
              }
              else {
                  return true;
              }
          };
          return svc.base().one("topology", node).get().then(function(ntData){

              var nodes = [];
              var links = [];
              var linksMap = {};

              if(ntData.topology && ntData.topology[0]){
                  //Loop over the nodes
                  angular.forEach(ntData.topology[0].node, function(nodeData) {
                    var groupType = "", nodeTitle = "", nodeLabel = "";
                    var nodeId = nodeData[svc.TOPOLOGY_CONST.NODE_ID];
                      if(nodeId!==undefined && nodeId.indexOf("host")>=0){
                        groupType = "host";
                        var ht_serviceadd = nodeData[svc.TOPOLOGY_CONST.ADDRESSES];
                          if(ht_serviceadd===undefined){
                              ht_serviceadd = nodeData[svc.TOPOLOGY_CONST.HT_SERVICE_ADDS];
                          }
                          if(ht_serviceadd!==undefined){
                              var ip;
                            //get title info
                            for(var i=0;i<ht_serviceadd.length;i++){
                                ip = ht_serviceadd[i][svc.TOPOLOGY_CONST.IP];
                                if(ip===undefined){
                                    ip = ht_serviceadd[i][svc.TOPOLOGY_CONST.HT_SERVICE_IP];
                                }
                                nodeTitle += 'IP: ' + ip + '
';
                            }
                          }
                        nodeTitle += 'Type: Host';
                      }
                      else{
                        groupType = "switch";
                        nodeTitle = 'Name: ' + nodeId + '
Type: Switch';
                      }

                    nodeLabel = nodeData[svc.TOPOLOGY_CONST.NODE_ID];
                    nodes.push({'id': nodes.length.toString(), 'label': nodeLabel, group: groupType,value:20,title:nodeTitle});
                  });
                  //Loops over the links
                  angular.forEach(ntData.topology[0].link, function(linkData) {
                      var srcId = getNodeIdByText(nodes, linkData.source[svc.TOPOLOGY_CONST.SOURCE_NODE]),
                          dstId = getNodeIdByText(nodes, linkData.destination[svc.TOPOLOGY_CONST.DEST_NODE]),
                          srcPort = linkData.source[svc.TOPOLOGY_CONST.SOURCE_TP],
                          dstPort = linkData.destination[svc.TOPOLOGY_CONST.DEST_TP],
                          linkId = links.length.toString();
                      if(srcId!=null && dstId!=null && !isEdgePresent(linksMap,srcId,dstId)){
                          links.push({id: linkId, 'from' : srcId, 'to': dstId, title:'Source Port: ' + srcPort + '
Dest Port: '+dstPort+''});
                          linksMap[srcId+":"+dstId]=linkId;
                      }
                  });

              }

              var data = {
                  "nodes" : nodes,
                  "links" : links
              };
              cb(data);
          },function(response) {
              console.log("Error with status code", response.status);
          });
      };
      return svc;
  });

});
<|endoftext|>


<commit_before>import React from 'react';
import classnames from 'classnames';

import { KeyCodes } from 'constants/ActorAppConstants';

class Dropdown extends React.Component {
  static propTypes = {
    isShown: React.PropTypes.bool,
    className: React.PropTypes.string,
    children: React.PropTypes.array,
    onSelect: React.PropTypes.func.isRequired,
    onClose: React.PropTypes.func
  };

  constructor(props) {
    super(props);

    this.state = {
      isShown: props.isShown,
      selectedIndex: this.getDefaultIndex(props.children)
    };

    if (props.isShown) {
      this.setListeners();
    }
  }

  componentWillUnmount() {
    this.cleanListeners();
  }

  componentWillUpdate(nextProps, nextState) {
    if (nextState.isShown && !this.state.isShown) {
      this.setListeners();
    } else if (!nextState.isShown && this.state.isShown) {
      this.cleanListeners();
    }
  }

  componentWillReceiveProps(props) {
    this.setState({
      isShown: props.isShown,
      selectedIndex: this.getDefaultIndex(props.children)
    });
  }

  setListeners() {
    document.addEventListener('keydown', this.onKeyDown, false);
    document.addEventListener('click', this.closeDropdown, false);
  }

  cleanListeners() {
    document.removeEventListener('keydown', this.onKeyDown, false);
    document.removeEventListener('click', this.closeDropdown, false);
  }

  getDefaultIndex = (children) => {
    let index = null;

    if (children && children.length > 0) {
      index = children.length - 1;
    }

    // Set first element selected
    index = 0;

    return index;
  };

  getValue = (index) => {
    if (this.props.children.length > 0) {
      return this.props.children[index].props.value;
    } else {
      return null;
    }
  };

  closeDropdown = () => {
    this.setState({isShown: false});
  };

  onSelect = (value) => {
    if (this.props.onSelect) {
      this.props.onSelect(value);
    }
  };

  onKeyDown = (e) => {
    let index = this.state.selectedIndex;
    const menuNode = React.findDOMNode(this.refs.menu);

    if (index !== null) {
      switch (e.keyCode) {
        case KeyCodes.ENTER:
          e.stopPropagation();
          e.preventDefault();

          this.onSelect(this.getValue(this.state.selectedIndex));
          break;
        case KeyCodes.ARROW_UP:
          e.stopPropagation();
          e.preventDefault();

          if (index !== 0) {
            index -= 1;
          }

          menuNode.scrollTop = menuNode.scrollTop - 42;

          this.setState({selectedIndex: index});
          break;
        case KeyCodes.ARROW_DOWN:
          e.stopPropagation();
          e.preventDefault();

          if (index !== this.props.children.length - 1) {
            index += 1;
          }

          menuNode.scrollTop = menuNode.scrollTop + 42;

          this.setState({selectedIndex: index});
          break;
        default:
      }
    }

    if (e.keyCode === KeyCodes.ESC) {
      this.closeDropdown();
      if (this.props.onClose) {
        this.props.onClose();
      }
    }
  };

  render() {
    const { className, children } = this.props;

    let dropdownItems = [];

    React.Children.forEach(children, (child, index) => {
      let elClassName = 'dropdown__menu__item';

      if (this.state.selectedIndex === index) {
        elClassName += ' dropdown__menu__item--active';
      }

      dropdownItems.push(

 this.setState({selectedIndex: index})}>
          {child.props.children}

      );
    });

    const dropdownClassName = classnames({
      'dropdown': true,
      'dropdown--opened': this.state.isShown
    }, className);

    return (

          {dropdownItems}

    );
  }
}

class DropdownItem extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return this.props.children;
  }
}

export default { Dropdown, DropdownItem };
<commit_msg>fix(web): fix default selected index for mentions<commit_after>import React from 'react';
import classnames from 'classnames';

import { KeyCodes } from 'constants/ActorAppConstants';

class Dropdown extends React.Component {
  static propTypes = {
    isShown: React.PropTypes.bool,
    className: React.PropTypes.string,
    children: React.PropTypes.array,
    onSelect: React.PropTypes.func.isRequired,
    onClose: React.PropTypes.func
  };

  constructor(props) {
    super(props);

    this.state = {
      isShown: props.isShown,
      selectedIndex: this.getDefaultIndex(props.children)
    };

    if (props.isShown) {
      this.setListeners();
    }
  }

  componentWillUnmount() {
    this.cleanListeners();
  }

  componentWillUpdate(nextProps, nextState) {
    if (nextState.isShown && !this.state.isShown) {
      this.setListeners();
    } else if (!nextState.isShown && this.state.isShown) {
      this.cleanListeners();
    }
  }

  componentWillReceiveProps(props) {
    this.setState({
      isShown: props.isShown,
      selectedIndex: this.getDefaultIndex(props.children)
    });
  }

  setListeners() {
    document.addEventListener('keydown', this.onKeyDown, false);
    document.addEventListener('click', this.closeDropdown, false);
  }

  cleanListeners() {
    document.removeEventListener('keydown', this.onKeyDown, false);
    document.removeEventListener('click', this.closeDropdown, false);
  }

  getDefaultIndex = (children) => {
    let index = null;

    if (children && children.length > 0) {
      //index = children.length - 1;

      // Set first element selected
      index = 0;
    }

    return index;
  };

  getValue = (index) => {
    if (this.props.children.length > 0) {
      return this.props.children[index].props.value;
    } else {
      return null;
    }
  };

  closeDropdown = () => {
    this.setState({isShown: false});
  };

  onSelect = (value) => {
    if (this.props.onSelect) {
      this.props.onSelect(value);
    }
  };

  onKeyDown = (e) => {
    let index = this.state.selectedIndex;
    const menuNode = React.findDOMNode(this.refs.menu);

    if (index !== null) {
      switch (e.keyCode) {
        case KeyCodes.ENTER:
          e.stopPropagation();
          e.preventDefault();

          this.onSelect(this.getValue(this.state.selectedIndex));
          break;
        case KeyCodes.ARROW_UP:
          e.stopPropagation();
          e.preventDefault();

          if (index !== 0) {
            index -= 1;
          }

          menuNode.scrollTop = menuNode.scrollTop - 42;

          this.setState({selectedIndex: index});
          break;
        case KeyCodes.ARROW_DOWN:
          e.stopPropagation();
          e.preventDefault();

          if (index !== this.props.children.length - 1) {
            index += 1;
          }

          menuNode.scrollTop = menuNode.scrollTop + 42;

          this.setState({selectedIndex: index});
          break;
        default:
      }
    }

    if (e.keyCode === KeyCodes.ESC) {
      this.closeDropdown();
      if (this.props.onClose) {
        this.props.onClose();
      }
    }
  };

  render() {
    const { className, children } = this.props;

    let dropdownItems = [];

    React.Children.forEach(children, (child, index) => {
      let elClassName = 'dropdown__menu__item';

      if (this.state.selectedIndex === index) {
        elClassName += ' dropdown__menu__item--active';
      }

      dropdownItems.push(

 this.setState({selectedIndex: index})}>
          {child.props.children}

      );
    });

    const dropdownClassName = classnames({
      'dropdown': true,
      'dropdown--opened': this.state.isShown
    }, className);

    return (

          {dropdownItems}

    );
  }
}

class DropdownItem extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return this.props.children;
  }
}

export default { Dropdown, DropdownItem };
<|endoftext|>


<commit_before>/** @jsx React.DOM */
'use strict';

var Lazy = require('lazy.js'),
  React = require('react');

var EnumerationControl = React.createClass({
  propTypes: {
    default: React.PropTypes.string,
    error: React.PropTypes.string,
    label: React.PropTypes.component.isRequired,
    labels: React.PropTypes.object.isRequired,
    name: React.PropTypes.string.isRequired,
    onChange: React.PropTypes.func.isRequired,
    suggestion: React.PropTypes.string,
    suggestionIcon: React.PropTypes.component,
    value: React.PropTypes.oneOfType([
      React.PropTypes.number,
      React.PropTypes.string,
    ]),
  },
  handleChange: function(event) {
    this.props.onChange(event.target.value);
  },
  render: function() {
    return (

        {this.props.label}
        {! this.props.error && this.props.suggestion && this.props.suggestionIcon}
        <select
          className="form-control"
          id={this.props.name}
          onChange={this.handleChange}
          value={this.props.value}>
          <option value="">Non renseigné ({
            this.props.suggestion ?
              'valeur suggérée : ' + this.props.labels[this.props.suggestion] : // jshint ignore:line
              'valeur par défaut : ' + this.props.labels[this.props.default] // jshint ignore:line
          })</option>
          {
            Lazy(this.props.labels).map((label, labelId) =>
              <option key={'label-' + labelId} value={labelId}>{label}</option>
            ).toArray()
          }
        </select>

    );
  }
});

module.exports = EnumerationControl;
<commit_msg>Fix markup to avoid react exception.<commit_after>/** @jsx React.DOM */
'use strict';

var Lazy = require('lazy.js'),
  React = require('react');

var EnumerationControl = React.createClass({
  propTypes: {
    default: React.PropTypes.string,
    error: React.PropTypes.string,
    label: React.PropTypes.component.isRequired,
    labels: React.PropTypes.object.isRequired,
    name: React.PropTypes.string.isRequired,
    onChange: React.PropTypes.func.isRequired,
    suggestion: React.PropTypes.string,
    suggestionIcon: React.PropTypes.component,
    value: React.PropTypes.oneOfType([
      React.PropTypes.number,
      React.PropTypes.string,
    ]),
  },
  handleChange: function(event) {
    this.props.onChange(event.target.value);
  },
  render: function() {
    var firstOptionLabel = `Non renseigné (${
      this.props.suggestion ?
        'valeur suggérée : ' + this.props.labels[this.props.suggestion] :
        'valeur par défaut : ' + this.props.labels[this.props.default]
    })`;
    return (

        {this.props.label}
        {! this.props.error && this.props.suggestion && this.props.suggestionIcon}
        <select
          className="form-control"
          id={this.props.name}
          onChange={this.handleChange}
          value={this.props.value}>
          <option value="">{firstOptionLabel}</option>
          {
            Lazy(this.props.labels).map((label, labelId) =>
              <option key={'label-' + labelId} value={labelId}>{label}</option>
            ).toArray()
          }
        </select>

    );
  }
});

module.exports = EnumerationControl;
<|endoftext|>


<commit_before>/**
  Handles routes related to viewing email logs.

  @class AdminEmailSentRoute
  @extends Discourse.Route
  @namespace Discourse
  @module Discourse
**/
Discourse.AdminEmailLogsRoute = Discourse.Route.extend({

  model: function() {
    return Discourse.EmailLog.findAll({ status: this.get("status") });
  },

  setupController: function(controller) {
    // resets the filters
    controller.set("filter", { status: this.get("status") });
  },

  renderTemplate: function() {
    this.render("admin/templates/email_" + this.get("status"), { into: "adminEmail" });
  }

});

Discourse.AdminEmailAllRoute = Discourse.AdminEmailLogsRoute.extend({ status: "all" });
Discourse.AdminEmailSentRoute = Discourse.AdminEmailLogsRoute.extend({ status: "sent" });
Discourse.AdminEmailSkippedRoute = Discourse.AdminEmailLogsRoute.extend({ status: "skipped" });
<commit_msg>BUGFIX: do not forget Ember's default behavior<commit_after>/**
  Handles routes related to viewing email logs.

  @class AdminEmailSentRoute
  @extends Discourse.Route
  @namespace Discourse
  @module Discourse
**/
Discourse.AdminEmailLogsRoute = Discourse.Route.extend({

  model: function() {
    return Discourse.EmailLog.findAll({ status: this.get("status") });
  },

  setupController: function(controller, model) {
    this._super(controller, model);
    // resets the filters
    controller.set("filter", { status: this.get("status") });
  },

  renderTemplate: function() {
    this.render("admin/templates/email_" + this.get("status"), { into: "adminEmail" });
  }

});

Discourse.AdminEmailAllRoute = Discourse.AdminEmailLogsRoute.extend({ status: "all" });
Discourse.AdminEmailSentRoute = Discourse.AdminEmailLogsRoute.extend({ status: "sent" });
Discourse.AdminEmailSkippedRoute = Discourse.AdminEmailLogsRoute.extend({ status: "skipped" });
<|endoftext|>


<commit_before>import React, { Component } from 'react';

import Reaction from '../models/Reaction';
import GreenMaterialGroup from './GreenMaterialGroup';
import { UrlSilentNavigation } from '../utils/ElementUtils';
import ElementActions from '../actions/ElementActions';

import GreenMetrics from './GreenMetrics';

export default class GreenChemistry extends Component {
  constructor() {
    super();

    this.updateGroupData = this.updateGroupData.bind(this);
  }

  updateGroupData() {
    const { reaction, onReactionChange } = this.props;
    onReactionChange(reaction);
  }

  render() {
    const { reaction, onReactionChange } = this.props;

    return (

        <GreenMetrics reaction={reaction} />
        <GreenMaterialGroup
          group="starting_materials"
          materials={reaction.starting_materials}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="reactants"
          materials={reaction.reactants}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="products"
          materials={reaction.products}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="solvents"
          materials={reaction.solvents}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="purification_solvents"
          materials={reaction.purification_solvents}
          onChange={this.updateGroupData}
        />

          E factor:
          The E Factor 25 Years on: The Rise of Green Chemistry and Sustainability.
          Sheldon, Roger A.  Green Chemistry 19, Nr. 1 (3. Januar 2017): 18–43.

          Atom economy (AE):
          The Atom Economy--a Search for Synthetic Efficiency
          Trost, B. M. Science 254, Nr. 5037 (6. Dezember 1991): 1471–77.

    );
  }
}

GreenChemistry.propTypes = {
  reaction: React.PropTypes.instanceOf(Reaction).isRequired,
  onReactionChange: React.PropTypes.func.isRequired,
};
<commit_msg>Don't update schema while updating<commit_after>import React, { Component } from 'react';

import Reaction from '../models/Reaction';
import GreenMaterialGroup from './GreenMaterialGroup';
import { UrlSilentNavigation } from '../utils/ElementUtils';
import ElementActions from '../actions/ElementActions';

import GreenMetrics from './GreenMetrics';

export default class GreenChemistry extends Component {
  constructor() {
    super();

    this.updateGroupData = this.updateGroupData.bind(this);
  }

  updateGroupData() {
    const { reaction, onReactionChange } = this.props;
    onReactionChange(reaction, { schemaChanged: false });
  }

  render() {
    const { reaction, onReactionChange } = this.props;

    return (

        <GreenMetrics reaction={reaction} />
        <GreenMaterialGroup
          group="starting_materials"
          materials={reaction.starting_materials}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="reactants"
          materials={reaction.reactants}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="products"
          materials={reaction.products}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="solvents"
          materials={reaction.solvents}
          onChange={this.updateGroupData}
        />
        <GreenMaterialGroup
          group="purification_solvents"
          materials={reaction.purification_solvents}
          onChange={this.updateGroupData}
        />

          E factor:
          The E Factor 25 Years on: The Rise of Green Chemistry and Sustainability.
          Sheldon, Roger A.  Green Chemistry 19, Nr. 1 (3. Januar 2017): 18–43.

          Atom economy (AE):
          The Atom Economy--a Search for Synthetic Efficiency
          Trost, B. M. Science 254, Nr. 5037 (6. Dezember 1991): 1471–77.

    );
  }
}

GreenChemistry.propTypes = {
  reaction: React.PropTypes.instanceOf(Reaction).isRequired,
  onReactionChange: React.PropTypes.func.isRequired,
};
<|endoftext|>


<commit_before>mumuki.load(function() {
  let avatar_id = "";

  $("#edit-avatar-icon").on('click', function(){
    $('#avatar-picker').modal();
  });

  $("#user-form").on('submit', function(){
    if (!avatar_id) {
      const image_url = $('#user-avatar').attr('src');
      $(this).append(`<input type="hidden" name="user[image_url]" value="${image_url}"/>`);
    }

    $(this).append(`<input type="hidden" name="user[avatar_id]" value="${avatar_id}"/>`);
  });

  $('.avatar-item').on('click', function(){
    $('#user-avatar').attr('src', $(this).attr('src'));
    $('#avatar-picker').modal('hide');

    const item_avatar = $(this).attr('avatar_id');
    if (item_avatar) {
      avatar_id = item_avatar;
    } else {
      avatar_id = "";
    }
  });
});
<commit_msg>Use proper JS case<commit_after>mumuki.load(function() {
  let avatarId = "";

  $("#edit-avatar-icon").on('click', function(){
    $('#avatar-picker').modal();
  });

  $("#user-form").on('submit', function(){
    if (!avatarId) {
      const imageUrl = $('#user-avatar').attr('src');
      $(this).append(`<input type="hidden" name="user[image_url]" value="${imageUrl}"/>`);
    }

    $(this).append(`<input type="hidden" name="user[avatar_id]" value="${avatarId}"/>`);
  });

  $('.avatar-item').on('click', function(){
    $('#user-avatar').attr('src', $(this).attr('src'));
    $('#avatar-picker').modal('hide');

    const clickedAvatarId = $(this).attr('avatar_id');
    if (clickedAvatarId) {
      avatarId = clickedAvatarId;
    } else {
      avatarId = "";
    }
  });
});
<|endoftext|>


<commit_before>function UserShowTempChartDrawer(chartOptions){
  this.chartOptions = chartOptions;
  this.violations = 0;
  this.url = this.setUrl();
  this.response = null;
  this.chart = null;
}

UserShowTempChartDrawer.prototype.setUrl = function(){
  if( /collaborations/.test(document.URL) ){
    return /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
    // returns '/user/13/collaborations/35'
  } else if ( /live_update/.test(document.URL) ){
    return /\/users\/\d+\/live_update/.exec(document.URL)[0];
    // returns '/user/13/live_update'
  } else {
    return /\/users\/\d+/.exec(document.URL)[0];
    // returns '/user/13'
  }
};

UserShowTempChartDrawer.prototype.fixData = function(dataArrWithObjs) {
  var self = this;
  dataArrWithObjs.forEach(function(obj){
    obj.date = new Date(obj.created_at);
    obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 22;
    if(/live_update/.test(document.URL)){
      obj.violation = true;
    }
    if( obj.violation ){ self.violations++; }
  });
  return dataArrWithObjs;
};

UserShowTempChartDrawer.prototype.addViolationCountToLegend = function() {
  $("#violations span").text($("#violations span")
    .text().replace(/\d+/, this.violations));
};

UserShowTempChartDrawer.prototype.selectDataBasedOnScreenSize = function(){
  if (window.innerWidth < 450 && this.response.length > 45) {
    return this.response.slice(this.response.length - 46);
  }else if(window.innerWidth < 720 && this.response.length > 90){
    return this.response.slice(this.response.length - 91);
  }else if(window.innerWidth < 1080 && this.response.length > 135){
    return this.response.slice(this.response.length - 136);
  } else {
    return this.response;
  }
};

UserShowTempChartDrawer.prototype.createAndDrawChartSvg = function(){
  this.chart = new UserShowTempChartSvg(
    this.selectDataBasedOnScreenSize(), this.violations, this.chartOptions
  );
  this.chart.addChartElements();
};

UserShowTempChartDrawer.prototype.drawChartOnWindowResize = function(){
  var resizeTimer = 0,
      self = this;
  $('#d3-chart').html('');
  this.createAndDrawChartSvg();
  window.onresize = function(){
    if (resizeTimer){
      clearTimeout(resizeTimer);
    }
    resizeTimer = setTimeout(function(){
      self.createAndDrawChartSvg();
      self.drawChartOnWindowResize();
    }, 50);
  };
};

UserShowTempChartDrawer.prototype.updateTempForLiveUpdate = function(response){
  if ( $('#live-update').length > 0 ) {
    $('.temp-num').html(response[response.length - 1].temp + '°')
  }
};

UserShowTempChartDrawer.prototype.drawChart = function() {
  var self = this;
  $.getJSON(this.url, function(response){
    self.response = self.fixData(response);
    self.drawChartOnWindowResize();
    self.updateTempForLiveUpdate(response);
    self.addViolationCountToLegend();
  });
};<commit_msg>Classify 10pm as nighttime on the user temperature chart<commit_after>function UserShowTempChartDrawer(chartOptions){
  this.chartOptions = chartOptions;
  this.violations = 0;
  this.url = this.setUrl();
  this.response = null;
  this.chart = null;
}

UserShowTempChartDrawer.prototype.setUrl = function(){
  if( /collaborations/.test(document.URL) ){
    return /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
    // returns '/user/13/collaborations/35'
  } else if ( /live_update/.test(document.URL) ){
    return /\/users\/\d+\/live_update/.exec(document.URL)[0];
    // returns '/user/13/live_update'
  } else {
    return /\/users\/\d+/.exec(document.URL)[0];
    // returns '/user/13'
  }
};

UserShowTempChartDrawer.prototype.fixData = function(dataArrWithObjs) {
  var self = this;
  dataArrWithObjs.forEach(function(obj){
    obj.date = new Date(obj.created_at);
    obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 21;
    if(/live_update/.test(document.URL)){
      obj.violation = true;
    }
    if( obj.violation ){ self.violations++; }
  });
  return dataArrWithObjs;
};

UserShowTempChartDrawer.prototype.addViolationCountToLegend = function() {
  $("#violations span").text($("#violations span")
    .text().replace(/\d+/, this.violations));
};

UserShowTempChartDrawer.prototype.selectDataBasedOnScreenSize = function(){
  if (window.innerWidth < 450 && this.response.length > 45) {
    return this.response.slice(this.response.length - 46);
  }else if(window.innerWidth < 720 && this.response.length > 90){
    return this.response.slice(this.response.length - 91);
  }else if(window.innerWidth < 1080 && this.response.length > 135){
    return this.response.slice(this.response.length - 136);
  } else {
    return this.response;
  }
};

UserShowTempChartDrawer.prototype.createAndDrawChartSvg = function(){
  this.chart = new UserShowTempChartSvg(
    this.selectDataBasedOnScreenSize(), this.violations, this.chartOptions
  );
  this.chart.addChartElements();
};

UserShowTempChartDrawer.prototype.drawChartOnWindowResize = function(){
  var resizeTimer = 0,
      self = this;
  $('#d3-chart').html('');
  this.createAndDrawChartSvg();
  window.onresize = function(){
    if (resizeTimer){
      clearTimeout(resizeTimer);
    }
    resizeTimer = setTimeout(function(){
      self.createAndDrawChartSvg();
      self.drawChartOnWindowResize();
    }, 50);
  };
};

UserShowTempChartDrawer.prototype.updateTempForLiveUpdate = function(response){
  if ( $('#live-update').length > 0 ) {
    $('.temp-num').html(response[response.length - 1].temp + '°')
  }
};

UserShowTempChartDrawer.prototype.drawChart = function() {
  var self = this;
  $.getJSON(this.url, function(response){
    self.response = self.fixData(response);
    self.drawChartOnWindowResize();
    self.updateTempForLiveUpdate(response);
    self.addViolationCountToLegend();
  });
};
<|endoftext|>


<commit_before>import through from 'through2'
import getAssetImporter from './getAssetImporter'
import promiseEach from 'promise-each-concurrency'

const batchSize = 10
const concurrency = 6

export default options => {
  const assetImporter = getAssetImporter(options)
  const documents = []

  return through.obj(onChunk, onFlush)

  async function uploadAssets(stream, cb) {
    await promiseEach(documents, assetImporter.processDocument, {concurrency})

    while (documents.length > 0) {
      stream.push(documents.shift())
    }

    cb()
  }

  function onChunk (chunk, enc, cb) {
    const newLength = documents.push(chunk)
    if (newLength !== batchSize) {
      return cb()
    }

    return uploadAssets(this, cb)
  }

  function onFlush(cb) {
    if (documents.length > 0) {
      uploadAssets(this, cb)
    }
  }
}
<commit_msg>[core] Fix bug where import would stall if no assets were left when stream is drained<commit_after>import through from 'through2'
import getAssetImporter from './getAssetImporter'
import promiseEach from 'promise-each-concurrency'

const batchSize = 10
const concurrency = 6

export default options => {
  const assetImporter = getAssetImporter(options)
  const documents = []

  return through.obj(onChunk, onFlush)

  async function uploadAssets(stream, cb) {
    await promiseEach(documents, assetImporter.processDocument, {concurrency})

    while (documents.length > 0) {
      stream.push(documents.shift())
    }

    cb()
  }

  function onChunk(chunk, enc, cb) {
    const newLength = documents.push(chunk)
    if (newLength !== batchSize) {
      return cb()
    }

    return uploadAssets(this, cb)
  }

  function onFlush(cb) {
    if (documents.length === 0) {
      cb()
      return
    }

    uploadAssets(this, cb)
  }
}
<|endoftext|>


<commit_before>import Vue from 'vue'
Vue.config.productionTip = false

window.GobiertoPlans.PlanTypesController = (function() {

    function PlanTypesController() {}

    PlanTypesController.prototype.show = function() {
      _loadPlan();
    };

    function _loadPlan() {

      // filters
      Vue.filter('translate', function (key) {
        if (!key) return
        return key[I18n.locale] || key["es"] || key["en"] || Object.values(key)[0] // fallback translations
      });

      Vue.filter('percent', function (value) {
        if (!value) return
        return (value / 100).toLocaleString(I18n.locale, { style: 'percent', maximumSignificantDigits: 4 })
      });

      Vue.filter('date', function (date) {
        if (!date) return
        return new Date(date).toLocaleString(I18n.locale, { year: 'numeric', month: 'short', day: 'numeric' })
      });

      // define the node root component
      Vue.component('node-root', {
        template: '#node-root-template',
        props: ['model'],
        data: function() {
          return {}
        },
        computed: {
          progressWidth: function () {
            return `${this.model.attributes.progress}%`
          }
        },
        methods: {
          open: function() {
            // Trigger event
            this.$emit('selection', { ...this.model });
          }
        }
      });

      // define the node list component
      Vue.component('node-list', {
        template: '#node-list-template',
        props: ['model', 'level'],
        data: function() {
          return {
            isOpen: false
          }
        },
        methods: {
          setActive: function() {
            if (this.model.type === "category" && !this.model.max_level) {
              var model = { ...this.model };

              this.$emit('selection', model);
            }

            if (this.model.type === "category" && this.model.max_level) {
              this.$emit("toggle");
              this.isOpen = !this.isOpen;
            }
          },
          getLabel: function(level, number_of_elements) {
            var key = this.level["level" + (level + 1)]
            return (number_of_elements == 1 ? key["one"] : key["other"])
          }
        }
      });

      // define the table view component
      Vue.component('table-view', {
        template: '#table-view-template',
        props: ['model', 'header', 'open'],
        data: function() {
          return {}
        },
        methods: {
          getProject: function(row) {
            if (this.open) {
              // var project = { ...this.model };
              var project = { ...row };

              this.$emit('selection', project);
            }
          }
        }
      });

      // main object
      new Vue({
        el: '#gobierto-planification',
        name: 'gobierto-planification',
        data: {
          json: {},
          levelKeys: {},
          optionKeys: [],
          activeNode: {},
          showTable: {},
          showTableHeader: true,
          openNode: false,
          rootid: 0
        },
        created: function() {
          this.getJson();

          let vm = this
          function locationHashChanged() {
              vm.getPermalink(window.location.hash.substring(1))
          }

          window.onhashchange = locationHashChanged
        },
        watch: {
          activeNode: {
            handler: function(node) {
              this.showTable = {}
              // update hash when a new node is active
              this.setPermalink()

              this.isOpen(node.level)
            },
            deep: true
          }
        },
        computed: {
          globalProgress: function () {
            return _.meanBy(this.json, 'attributes.progress')
          },
          availableOpts: function () {
            // Filter options object only to those values present in the configuration (optionKeys)
            return _.pick(this.activeNode.attributes.options, _.filter(_.keys(this.activeNode.attributes.options), function (o) {
              return _.includes(_.keys(this.optionKeys), o.toString().toLowerCase())
            }.bind(this)));
          }
        },
        methods: {
          getJson: function() {
            $.getJSON(window.location.href, {format: 'json'}, function(json) {
              // Tree with categories and the leaves (nodes)
              var data = json["plan_tree"];
              // Nodes can have variable attributes and these are their keys
              var optionKeys = json["option_keys"];
              // Keys for different levels
              var levelKeys = json["level_keys"];
              // If you can see the table header
              var showTableHeader = json["show_table_header"];
              // If you can open a node (project)
              var openNode = json["open_node"];

              // Hide spinner
              $(".js-toggle-overlay").removeClass('is-active');

              this.json = data;
              this.levelKeys = levelKeys;
              this.showTableHeader = showTableHeader;
              this.openNode = openNode;
              this.optionKeys = Object.keys(optionKeys).reduce(function(c, k) {
                return (c[k.toLowerCase()] = optionKeys[k]), c;
              }, {});

              // Parse permalink
              if (window.location.hash) {
                this.getPermalink(window.location.hash.substring(1))
              }

            }.bind(this));
          },
          color: function() {
            return this.rootid % this.json.length + 1;
          },
          setRootColor: function(index) {
            return index % this.json.length + 1;
          },
          setSelection: function(model) {
            this.activeNode = model;

            // To know the root node
            this.rootid = this.activeNode.uid.toString().charAt(0);
          },
          isOpen: function(level) {
            if (this.activeNode.level === undefined) return false

            let isOpen = false
            if (this.activeNode.level === 0) {
              // activeNode = 0, it means is a "line"
              // then, it shows level_0 and level_1
              isOpen = (level < 2)
            } else {
              // activeNode = X
              if (this.activeNode.type === "node") {
                // type = node, it means there's no further levels, then it shows as previous one
                isOpen = (level === 0) || (level === this.activeNode.level)
              } else {
                // then, it shows level_0 and level_(X+1), but not those between
                isOpen = (level === 0) || (level === (this.activeNode.level + 1))
              }
            }

            return isOpen
          },
          typeOf: function(val) {
            if (_.isString(val)) {
              return "string"
            } else if (_.isArray(val)) {
              return "array"
            }
            return "object";
          },
          toggle: function(i) {
            Vue.set(this.showTable, i, !(this.showTable[i]));
          },
          getLabel: function(level, number_of_elements) {
            var l = (_.keys(this.levelKeys).length === (level + 1)) ? level : (level + 1);
            var key = this.levelKeys["level" + l];
            return (number_of_elements == 1 ? key["one"] : key["other"]);
          },
          getParent: function() {
            // Initialize args
            var breakpoint = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;

            // From uid, turno into array all parents, and drop last item (myself)
            var ancestors = _.dropRight(this.activeNode.uid.split('.')).map(Number);

            var current = this.json; // First item. ROOT item
            for (var i = 0; i < ancestors.length; i++) {
              if (i === breakpoint) {
                // If there is breakpoint, I get the corresponding ancestor set by breakpoint
                break;
              }

              if (!_.isArray(current)) {
                current = current.children;
              }
              current = current[ancestors[i]];
            }

            return current || {}
          },
          setParent: function() {
            // Initialize args
            var breakpoint = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
            //hack 3rd level (3rd level has no SECTION)
            if (breakpoint === 3) breakpoint = breakpoint - 1;

            this.activeNode = this.getParent(breakpoint);
          },
          setPermalink: function () {
            window.location.hash = this.activeNode.uid
          },
          getPermalink: function (hash) {
            let found = this.searchByUid(hash, this.json)
            if (found) {
              this.setSelection(found)
            }
          },
          searchByUid: function(id, data) {
            let result = false

            if (_.isArray(data)) {
              _.each(data, d => {
                result = findNodeByProp(id, d, 'uid')

                // Return false to break loop
                if (result !== false) {
                  return false;
                }
              })
            } else {
              result = findNodeByProp(id, data, 'uid')
            }

            return result
          }
        }
      })

      function findNodeByProp(id, currentNode, prop = 'id') {
        var i,
          currentChild,
          result;

        if (id == currentNode[prop]) {
          return currentNode;
        } else {

          // Use a for loop instead of forEach to avoid nested functions
          // Otherwise "return" will not work properly
          for (i = 0; i < currentNode.children.length; i += 1) {
            currentChild = currentNode.children[i];

            // Search in the current child
            result = findNodeByProp(id, currentChild, prop);

            // Return the result if the node has been found
            if (result !== false) {
              return result;
            }
          }

          // The node has not been found and we have no more options
          return false;
        }
      }
    }

    return PlanTypesController;
  })();

  window.GobiertoPlans.plan_types_controller = new GobiertoPlans.PlanTypesController;
<commit_msg>Restrict JS call to specific controller action<commit_after>import Vue from 'vue'
Vue.config.productionTip = false

window.GobiertoPlans.PlanTypesController = (function() {

    function PlanTypesController() {}

    PlanTypesController.prototype.show = function() {
      if ($('body').attr('class').indexOf('gobierto_plans_plan_types_show') > -1) {
        _loadPlan();
      }
    };

    function _loadPlan() {

      // filters
      Vue.filter('translate', function (key) {
        if (!key) return
        return key[I18n.locale] || key["es"] || key["en"] || Object.values(key)[0] // fallback translations
      });

      Vue.filter('percent', function (value) {
        if (!value) return
        return (value / 100).toLocaleString(I18n.locale, { style: 'percent', maximumSignificantDigits: 4 })
      });

      Vue.filter('date', function (date) {
        if (!date) return
        return new Date(date).toLocaleString(I18n.locale, { year: 'numeric', month: 'short', day: 'numeric' })
      });

      // define the node root component
      Vue.component('node-root', {
        template: '#node-root-template',
        props: ['model'],
        data: function() {
          return {}
        },
        computed: {
          progressWidth: function () {
            return `${this.model.attributes.progress}%`
          }
        },
        methods: {
          open: function() {
            // Trigger event
            this.$emit('selection', { ...this.model });
          }
        }
      });

      // define the node list component
      Vue.component('node-list', {
        template: '#node-list-template',
        props: ['model', 'level'],
        data: function() {
          return {
            isOpen: false
          }
        },
        methods: {
          setActive: function() {
            if (this.model.type === "category" && !this.model.max_level) {
              var model = { ...this.model };

              this.$emit('selection', model);
            }

            if (this.model.type === "category" && this.model.max_level) {
              this.$emit("toggle");
              this.isOpen = !this.isOpen;
            }
          },
          getLabel: function(level, number_of_elements) {
            var key = this.level["level" + (level + 1)]
            return (number_of_elements == 1 ? key["one"] : key["other"])
          }
        }
      });

      // define the table view component
      Vue.component('table-view', {
        template: '#table-view-template',
        props: ['model', 'header', 'open'],
        data: function() {
          return {}
        },
        methods: {
          getProject: function(row) {
            if (this.open) {
              // var project = { ...this.model };
              var project = { ...row };

              this.$emit('selection', project);
            }
          }
        }
      });

      // main object
      new Vue({
        el: '#gobierto-planification',
        name: 'gobierto-planification',
        data: {
          json: {},
          levelKeys: {},
          optionKeys: [],
          activeNode: {},
          showTable: {},
          showTableHeader: true,
          openNode: false,
          rootid: 0
        },
        created: function() {
          this.getJson();

          let vm = this
          function locationHashChanged() {
              vm.getPermalink(window.location.hash.substring(1))
          }

          window.onhashchange = locationHashChanged
        },
        watch: {
          activeNode: {
            handler: function(node) {
              this.showTable = {}
              // update hash when a new node is active
              this.setPermalink()

              this.isOpen(node.level)
            },
            deep: true
          }
        },
        computed: {
          globalProgress: function () {
            return _.meanBy(this.json, 'attributes.progress')
          },
          availableOpts: function () {
            // Filter options object only to those values present in the configuration (optionKeys)
            return _.pick(this.activeNode.attributes.options, _.filter(_.keys(this.activeNode.attributes.options), function (o) {
              return _.includes(_.keys(this.optionKeys), o.toString().toLowerCase())
            }.bind(this)));
          }
        },
        methods: {
          getJson: function() {
            $.getJSON(window.location.href, {format: 'json'}, function(json) {
              // Tree with categories and the leaves (nodes)
              var data = json["plan_tree"];
              // Nodes can have variable attributes and these are their keys
              var optionKeys = json["option_keys"];
              // Keys for different levels
              var levelKeys = json["level_keys"];
              // If you can see the table header
              var showTableHeader = json["show_table_header"];
              // If you can open a node (project)
              var openNode = json["open_node"];

              // Hide spinner
              $(".js-toggle-overlay").removeClass('is-active');

              this.json = data;
              this.levelKeys = levelKeys;
              this.showTableHeader = showTableHeader;
              this.openNode = openNode;
              this.optionKeys = Object.keys(optionKeys).reduce(function(c, k) {
                return (c[k.toLowerCase()] = optionKeys[k]), c;
              }, {});

              // Parse permalink
              if (window.location.hash) {
                this.getPermalink(window.location.hash.substring(1))
              }

            }.bind(this));
          },
          color: function() {
            return this.rootid % this.json.length + 1;
          },
          setRootColor: function(index) {
            return index % this.json.length + 1;
          },
          setSelection: function(model) {
            this.activeNode = model;

            // To know the root node
            this.rootid = this.activeNode.uid.toString().charAt(0);
          },
          isOpen: function(level) {
            if (this.activeNode.level === undefined) return false

            let isOpen = false
            if (this.activeNode.level === 0) {
              // activeNode = 0, it means is a "line"
              // then, it shows level_0 and level_1
              isOpen = (level < 2)
            } else {
              // activeNode = X
              if (this.activeNode.type === "node") {
                // type = node, it means there's no further levels, then it shows as previous one
                isOpen = (level === 0) || (level === this.activeNode.level)
              } else {
                // then, it shows level_0 and level_(X+1), but not those between
                isOpen = (level === 0) || (level === (this.activeNode.level + 1))
              }
            }

            return isOpen
          },
          typeOf: function(val) {
            if (_.isString(val)) {
              return "string"
            } else if (_.isArray(val)) {
              return "array"
            }
            return "object";
          },
          toggle: function(i) {
            Vue.set(this.showTable, i, !(this.showTable[i]));
          },
          getLabel: function(level, number_of_elements) {
            var l = (_.keys(this.levelKeys).length === (level + 1)) ? level : (level + 1);
            var key = this.levelKeys["level" + l];
            return (number_of_elements == 1 ? key["one"] : key["other"]);
          },
          getParent: function() {
            // Initialize args
            var breakpoint = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;

            // From uid, turno into array all parents, and drop last item (myself)
            var ancestors = _.dropRight(this.activeNode.uid.split('.')).map(Number);

            var current = this.json; // First item. ROOT item
            for (var i = 0; i < ancestors.length; i++) {
              if (i === breakpoint) {
                // If there is breakpoint, I get the corresponding ancestor set by breakpoint
                break;
              }

              if (!_.isArray(current)) {
                current = current.children;
              }
              current = current[ancestors[i]];
            }

            return current || {}
          },
          setParent: function() {
            // Initialize args
            var breakpoint = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
            //hack 3rd level (3rd level has no SECTION)
            if (breakpoint === 3) breakpoint = breakpoint - 1;

            this.activeNode = this.getParent(breakpoint);
          },
          setPermalink: function () {
            window.location.hash = this.activeNode.uid
          },
          getPermalink: function (hash) {
            let found = this.searchByUid(hash, this.json)
            if (found) {
              this.setSelection(found)
            }
          },
          searchByUid: function(id, data) {
            let result = false

            if (_.isArray(data)) {
              _.each(data, d => {
                result = findNodeByProp(id, d, 'uid')

                // Return false to break loop
                if (result !== false) {
                  return false;
                }
              })
            } else {
              result = findNodeByProp(id, data, 'uid')
            }

            return result
          }
        }
      })

      function findNodeByProp(id, currentNode, prop = 'id') {
        var i,
          currentChild,
          result;

        if (id == currentNode[prop]) {
          return currentNode;
        } else {

          // Use a for loop instead of forEach to avoid nested functions
          // Otherwise "return" will not work properly
          for (i = 0; i < currentNode.children.length; i += 1) {
            currentChild = currentNode.children[i];

            // Search in the current child
            result = findNodeByProp(id, currentChild, prop);

            // Return the result if the node has been found
            if (result !== false) {
              return result;
            }
          }

          // The node has not been found and we have no more options
          return false;
        }
      }
    }

    return PlanTypesController;
  })();

  window.GobiertoPlans.plan_types_controller = new GobiertoPlans.PlanTypesController;
<|endoftext|>


<commit_before>import * as __d3 from 'd3'
import { distanceLimitedVoronoi } from './d3-distance-limited-voronoi.js'
import { d3locale, accounting } from 'lib/shared'

const d3 = { ...__d3, distanceLimitedVoronoi }

export class VisRentDistribution {
  constructor(divId, city_id, province_id, current_year) {
    this.container = divId;
    this.cityId = city_id;
    this.provinceId = province_id;
    this.currentYear = (current_year !== undefined) ? parseInt(current_year) : null;
    this.data = null;
    this.tbiToken = window.populateData.token;
    this.rentUrl = window.populateData.endpoint + '/datasets/ds-renta-bruta-media-municipal.json?include=municipality&filter_by_province_id=' + this.provinceId;
    this.popUrl = window.populateData.endpoint + '/datasets/ds-poblacion-municipal.json?filter_by_year=' + this.currentYear + '&filter_by_province_id=' + this.provinceId;
    this.formatThousand = d3.format(',.0f');
    this.isMobile = window.innerWidth <= 768;

    // Set default locale
    d3.formatDefaultLocale(d3locale[I18n.locale]);

    // Chart dimensions
    this.margin = { top: 25, right: 15, bottom: 30, left: 15 };
    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    // Scales & Ranges
    this.xScale = d3.scaleLog();
    this.yScale = d3.scaleLinear();

    this.color = d3.scaleSequential(d3.interpolatePlasma);

    // Create axes
    this.xAxis = d3.axisBottom();
    this.yAxis = d3.axisRight();

    // Chart objects
    this.svg = null;
    this.chart = null;

    // Create main elements
    this.svg = d3.select(this.container)
      .append('svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom)
      .append('g')
      .attr('class', 'chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    // Append axes containers
    this.svg.append('g').attr('class','x axis');
    this.svg.append('g').attr('class','y axis');

    this.tooltip = d3.select(this.container)
      .append('div')
      .attr('class', 'tooltip');

    d3.select(window).on('resize.' + this.container, () => {
      if (this.data) {
        this._resize()
      }
    });
  }

  getData() {
    var rent = d3.json(this.rentUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var pop = d3.json(this.popUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    d3.queue()
      .defer(rent.get)
      .defer(pop.get)
      .await(function (error, rent, pop) {
        if (error) throw error;

        rent.forEach(function(d) {
          d.rent = d.value

          delete d.value;
        });

        this.data = _(rent)
          .concat(rent, pop)
          .groupBy('location_id')
          .map(_.spread(_.merge))
          .filter('rent')
          .value();

        this.updateRender();
        this._renderCircles();
        this.isMobile ? null : this._renderVoronoi();
      }.bind(this));
  }

  render() {
    if (this.data === null) {
      this.getData();
    } else {
      this.updateRender();
    }
  }

  updateRender() {
    this.xScale
      .rangeRound([0, this.width])
      .domain(d3.extent(this.data, function(d) { return d.value; }));

    this.yScale
      .rangeRound([this.height, 0])
      .domain(d3.extent(this.data, function(d) { return d.rent; }));

    this.color.domain(d3.extent(this.data, function(d) { return d.rent; }).reverse());

    this._renderAxis();
  }

  _renderCircles() {
    // We keep this separate to not create them after every resize
    var circles = this.svg.append('g')
      .attr('class', 'circles')
      .selectAll('circle')
      .data(this.data)
      .enter();

    circles.append('circle')
      .attr('class', function(d, i) { return d.location_id === +this.cityId ? 'circle' + i + ' selected-city' : 'circle' + i; }.bind(this))
      .attr('cx', function(d) { return this.xScale(d.value) }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.rent) }.bind(this))
      .attr('fill', function(d) { return this.color(d.rent) }.bind(this))
      .attr('stroke', 'white')
      .attr('r', this.isMobile ? 6 : 12);

    // Add name of the current city
    var cityLabel = this.svg.append('g')
      .attr('class', 'text-label');

    // cityLabel.append()

    cityLabel.selectAll('text')
      .data(this.data)
      .enter()
      .filter(function(d) { return d.location_id === +this.cityId; }.bind(this))
      .append('text')
      .attr('x', function(d) { return this.xScale(d.value) }.bind(this))
      .attr('y', function(d) { return this.yScale(d.rent) }.bind(this))
      .attr('dy', 7)
      .attr('dx', -15)
      .attr('text-anchor', 'end')
      .text(function(d) { return d.municipality_name });

  }

  _renderVoronoi() {

    // Create voronoi
    this.voronoi = d3.distanceLimitedVoronoi()
      .x(function(d) { return this.xScale(d.value); }.bind(this))
      .y(function(d) { return this.yScale(d.rent); }.bind(this))
      .limit(50)
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup = this.svg.append('g')
      .attr('class', 'voronoi');

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi(this.data))
      .enter()
      .append('path')
      .style('fill', 'none')
      .attr('class', 'voronoiPath')
      .attr('d', d => (d || {}).path)
      .style('pointer-events', 'all')
      .on('mousemove', this._mousemove.bind(this))
      .on('mouseout', this._mouseout.bind(this));

    // Attach hover circle
    this.svg.append('circle')
      .style('pointer-events', 'none')
      .attr('class', 'hover')
      .attr('fill', 'none')
      .attr('transform', 'translate(-100,-100)')
      .attr('r', this.isMobile ? 6 : 12);
  }

  _mousemove(d, i) {
    d3.select('.circle' + i).attr('stroke', 'none')

    d3.selectAll('.hover')
        .attr('stroke', '#111')
        .attr('stroke-width', 1.5)
        .attr('cx', this.xScale(d.datum.value))
        .attr('cy', this.yScale(d.datum.rent))
        .attr('transform', 'translate(0,0)');

    // // Fill the tooltip
    this.tooltip.html('
' + d.datum.municipality_name + '
' +
      '
' +
          '
' +
              '' + I18n.t('gobierto_common.visualizations.inhabitants') + '	' +
              ''+ accounting.formatNumber(d.datum.value, 0) +'	' +
          '
' +
          '
' +
              '' + I18n.t('gobierto_common.visualizations.gross_income') + '	' +
              '' + accounting.formatNumber(d.datum.rent, 0) + '€	' +
          '
' +
      '
')
      .style('opacity', 1);

    // Tooltip position
    if (this.isMobile) {
      this.tooltip.style('opacity', 0);
    } else {
      var coords = d3.mouse(d3.select(this.container)._groups[0][0]);
      var x = coords[0], y = coords[1];

      this.tooltip.style('top', (y + 23) + 'px');

      if (x > 900) {
        // Move tooltip to the left side
        return this.tooltip.style('left', (x - 200) + 'px');
      } else {
        return this.tooltip.style('left', (x - 20) + 'px');
      }
    }
  }

  _mouseout(d, i) {
    d3.selectAll('.circle' + i).attr('stroke', 'white');

    d3.select('.hover')
        .attr('stroke', 'none');

    this.tooltip.style('opacity', 0);
  }

  _renderAxis() {
    // X axis
    this.svg.select('.x.axis')
      .attr('transform', 'translate(0,' + this.height + ')');

    this.xAxis
      .tickPadding(10)
      .ticks(3)
      .tickSize(-this.height)
      .scale(this.xScale)
      .tickFormat(this._formatNumberX.bind(this));

    this.svg.select('.x.axis').call(this.xAxis);

    // Y axis
    this.svg.select('.y.axis')
      .attr('transform', 'translate(' + this.width + ' ,0)');

    this.yAxis
      .scale(this.yScale)
      .ticks(this.isMobile ? 3 : 4)
      .tickSize(-this.width)
      .tickFormat(this._formatNumberY.bind(this));

    this.svg.select('.y.axis').call(this.yAxis);

    // Place y axis labels on top of ticks
    this.svg.selectAll('.y.axis .tick text')
      .attr('dx', '-3.4em')
      .attr('dy', '-0.55em');

    // Remove the zero on the y axis
    this.svg.selectAll('.y.axis .tick')
      .filter(function (d) { return d === 0; })
      .remove();
  }

  _formatMillionAbbr(x) {
    return d3.format('.0f')(x / 1e6) + ' ' + I18n.t('gobierto_common.visualizations.million');
  }

  _formatThousandAbbr(x) {
    return d3.format('.0f')(x / 1e3) + ' ' + I18n.t('gobierto_common.visualizations.thousand');
  }

  _formatAbbreviation(x) {
    var v = Math.abs(x);

    return (v >= .9995e6 ? this._formatMillionAbbr : v >= .9995e4 ? this._formatThousandAbbr : this.formatThousand)(x);
  }

  _formatNumberX(d) {
    // Spanish custom thousand separator
    return this._formatAbbreviation(d);
  }

  _formatNumberY(d) {
    // Show percentages
    return accounting.formatNumber(d, 0) + '€';
  }

  _width() {
    return parseInt(d3.select(this.container).style('width'));
  }

  _height() {
    return this.isMobile ? 320 : this._width() * 0.5;
  }

  _resize() {
    this.width = this._width();
    this.height = this._height();

    this.updateRender();

    d3.select(this.container + ' svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom);

    this.svg.select('.chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    this.svg.selectAll('.circles circle')
      .attr('cx', function(d) { return this.xScale(d.value); }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.rent); }.bind(this));

    this.svg.select('.text-label text')
      .attr('x', function(d) { return this.xScale(d.value); }.bind(this))
      .attr('y', function(d) { return this.yScale(d.rent); }.bind(this));

    this.svg.selectAll('.rent-anno')
      .attr('x', this.width - 65);

    if (this.voronoi) {
      this.voronoi
        .extent([[0, 0], [this.width, this.height]]);

      this.voronoiGroup.selectAll('.voronoiPath')
        .data(this.voronoi(this.data))
        .attr("d", function(d, i, _) {
          if (!d) {
            console.log(d, i, _);

            return
          }

          return d.path;
         });
    }
  }

}
<commit_msg>Update rent_distribution.js<commit_after>import * as __d3 from 'd3'
import { distanceLimitedVoronoi } from './d3-distance-limited-voronoi.js'
import { d3locale, accounting } from 'lib/shared'

const d3 = { ...__d3, distanceLimitedVoronoi }

export class VisRentDistribution {
  constructor(divId, city_id, province_id, current_year) {
    this.container = divId;
    this.cityId = city_id;
    this.provinceId = province_id;
    this.currentYear = (current_year !== undefined) ? parseInt(current_year) : null;
    this.data = null;
    this.tbiToken = window.populateData.token;
    this.rentUrl = window.populateData.endpoint + '/datasets/ds-renta-bruta-media-municipal.json?include=municipality&filter_by_province_id=' + this.provinceId;
    this.popUrl = window.populateData.endpoint + '/datasets/ds-poblacion-municipal.json?filter_by_year=' + this.currentYear + '&filter_by_province_id=' + this.provinceId;
    this.formatThousand = d3.format(',.0f');
    this.isMobile = window.innerWidth <= 768;

    // Set default locale
    d3.formatDefaultLocale(d3locale[I18n.locale]);

    // Chart dimensions
    this.margin = { top: 25, right: 15, bottom: 30, left: 15 };
    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    // Scales & Ranges
    this.xScale = d3.scaleLog();
    this.yScale = d3.scaleLinear();

    this.color = d3.scaleSequential(d3.interpolatePlasma);

    // Create axes
    this.xAxis = d3.axisBottom();
    this.yAxis = d3.axisRight();

    // Chart objects
    this.svg = null;
    this.chart = null;

    // Create main elements
    this.svg = d3.select(this.container)
      .append('svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom)
      .append('g')
      .attr('class', 'chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    // Append axes containers
    this.svg.append('g').attr('class','x axis');
    this.svg.append('g').attr('class','y axis');

    this.tooltip = d3.select(this.container)
      .append('div')
      .attr('class', 'tooltip');

    d3.select(window).on('resize.' + this.container, () => {
      if (this.data) {
        this._resize()
      }
    });
  }

  getData() {
    var rent = d3.json(this.rentUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var pop = d3.json(this.popUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    d3.queue()
      .defer(rent.get)
      .defer(pop.get)
      .await(function (error, rent, pop) {
        if (error) throw error;

        rent.forEach(function(d) {
          d.rent = d.value

          delete d.value;
        });

        this.data = _(rent)
          .concat(rent, pop)
          .groupBy('location_id')
          .map(_.spread(_.merge))
          .filter('rent')
          .value();

        this.updateRender();
        this._renderCircles();
        this.isMobile ? null : this._renderVoronoi();
      }.bind(this));
  }

  render() {
    if (this.data === null) {
      this.getData();
    } else {
      this.updateRender();
    }
  }

  updateRender() {
    this.xScale
      .rangeRound([0, this.width])
      .domain(d3.extent(this.data, function(d) { return d.value; }));

    this.yScale
      .rangeRound([this.height, 0])
      .domain(d3.extent(this.data, function(d) { return d.rent; }));

    this.color.domain(d3.extent(this.data, function(d) { return d.rent; }).reverse());

    this._renderAxis();
  }

  _renderCircles() {
    // We keep this separate to not create them after every resize
    var circles = this.svg.append('g')
      .attr('class', 'circles')
      .selectAll('circle')
      .data(this.data)
      .enter();

    circles.append('circle')
      .attr('class', function(d, i) { return d.location_id === +this.cityId ? 'circle' + i + ' selected-city' : 'circle' + i; }.bind(this))
      .attr('cx', function(d) { return this.xScale(d.value) }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.rent) }.bind(this))
      .attr('fill', function(d) { return this.color(d.rent) }.bind(this))
      .attr('stroke', 'white')
      .attr('r', this.isMobile ? 6 : 12);

    // Add name of the current city
    var cityLabel = this.svg.append('g')
      .attr('class', 'text-label');

    // cityLabel.append()

    cityLabel.selectAll('text')
      .data(this.data)
      .enter()
      .filter(function(d) { return d.location_id === +this.cityId; }.bind(this))
      .append('text')
      .attr('x', function(d) { return this.xScale(d.value) }.bind(this))
      .attr('y', function(d) { return this.yScale(d.rent) }.bind(this))
      .attr('dy', 7)
      .attr('dx', -15)
      .attr('text-anchor', 'end')
      .text(function(d) { return d.municipality_name });

  }

  _renderVoronoi() {

    // Create voronoi
    this.voronoi = d3.distanceLimitedVoronoi()
      .x(function(d) { return this.xScale(d.value); }.bind(this))
      .y(function(d) { return this.yScale(d.rent); }.bind(this))
      .limit(50)
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup = this.svg.append('g')
      .attr('class', 'voronoi');

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi(this.data))
      .enter()
      .append('path')
      .style('fill', 'none')
      .attr('class', 'voronoiPath')
      .attr('d', d => (d || {}).path)
      .style('pointer-events', 'all')
      .on('mousemove', this._mousemove.bind(this))
      .on('mouseout', this._mouseout.bind(this));

    // Attach hover circle
    this.svg.append('circle')
      .style('pointer-events', 'none')
      .attr('class', 'hover')
      .attr('fill', 'none')
      .attr('transform', 'translate(-100,-100)')
      .attr('r', this.isMobile ? 6 : 12);
  }

  _mousemove(d, i) {
    d3.select('.circle' + i).attr('stroke', 'none')

    d3.selectAll('.hover')
        .attr('stroke', '#111')
        .attr('stroke-width', 1.5)
        .attr('cx', this.xScale(d.datum.value))
        .attr('cy', this.yScale(d.datum.rent))
        .attr('transform', 'translate(0,0)');

    // // Fill the tooltip
    this.tooltip.html('
' + d.datum.municipality_name + '
' +
      '
' +
          '
' +
              '' + I18n.t('gobierto_common.visualizations.inhabitants') + '	' +
              ''+ accounting.formatNumber(d.datum.value, 0) +'	' +
          '
' +
          '
' +
              '' + I18n.t('gobierto_common.visualizations.gross_income') + '	' +
              '' + accounting.formatNumber(d.datum.rent, 0) + '€	' +
          '
' +
      '
')
      .style('opacity', 1);

    // Tooltip position
    if (this.isMobile) {
      this.tooltip.style('opacity', 0);
    } else {
      var coords = d3.mouse(d3.select(this.container)._groups[0][0]);
      var x = coords[0], y = coords[1];

      this.tooltip.style('top', (y + 23) + 'px');

      if (x > 900) {
        // Move tooltip to the left side
        return this.tooltip.style('left', (x - 200) + 'px');
      } else {
        return this.tooltip.style('left', (x - 20) + 'px');
      }
    }
  }

  _mouseout(d, i) {
    d3.selectAll('.circle' + i).attr('stroke', 'white');

    d3.select('.hover')
        .attr('stroke', 'none');

    this.tooltip.style('opacity', 0);
  }

  _renderAxis() {
    // X axis
    this.svg.select('.x.axis')
      .attr('transform', 'translate(0,' + this.height + ')');

    this.xAxis
      .tickPadding(10)
      .ticks(3)
      .tickSize(-this.height)
      .scale(this.xScale)
      .tickFormat(this._formatNumberX.bind(this));

    this.svg.select('.x.axis').call(this.xAxis);

    // Y axis
    this.svg.select('.y.axis')
      .attr('transform', 'translate(' + this.width + ' ,0)');

    this.yAxis
      .scale(this.yScale)
      .ticks(this.isMobile ? 3 : 4)
      .tickSize(-this.width)
      .tickFormat(this._formatNumberY.bind(this));

    this.svg.select('.y.axis').call(this.yAxis);

    // Place y axis labels on top of ticks
    this.svg.selectAll('.y.axis .tick text')
      .attr('dx', '-3.4em')
      .attr('dy', '-0.55em');

    // Remove the zero on the y axis
    this.svg.selectAll('.y.axis .tick')
      .filter(function (d) { return d === 0; })
      .remove();
  }

  _formatMillionAbbr(x) {
    return d3.format('.0f')(x / 1e6) + ' ' + I18n.t('gobierto_common.visualizations.million');
  }

  _formatThousandAbbr(x) {
    return d3.format('.0f')(x / 1e3) + ' ' + I18n.t('gobierto_common.visualizations.thousand');
  }

  _formatAbbreviation(x) {
    var v = Math.abs(x);

    return (v >= .9995e6 ? this._formatMillionAbbr : v >= .9995e4 ? this._formatThousandAbbr : this.formatThousand)(x);
  }

  _formatNumberX(d) {
    // Spanish custom thousand separator
    return this._formatAbbreviation(d);
  }

  _formatNumberY(d) {
    // Show percentages
    return accounting.formatNumber(d, 0) + '€';
  }

  _width() {
    return parseInt(d3.select(this.container).style('width'));
  }

  _height() {
    return this.isMobile ? 320 : this._width() * 0.5;
  }

  _resize() {
    this.width = this._width();
    this.height = this._height();

    this.updateRender();

    d3.select(this.container + ' svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom);

    this.svg.select('.chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    this.svg.selectAll('.circles circle')
      .attr('cx', function(d) { return this.xScale(d.value); }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.rent); }.bind(this));

    this.svg.select('.text-label text')
      .attr('x', function(d) { return this.xScale(d.value); }.bind(this))
      .attr('y', function(d) { return this.yScale(d.rent); }.bind(this));

    this.svg.selectAll('.rent-anno')
      .attr('x', this.width - 65);

    if (this.voronoi) {
      this.voronoi
        .extent([[0, 0], [this.width, this.height]]);

      this.voronoiGroup.selectAll('.voronoiPath')
        .data(this.voronoi(this.data))
        .attr("d", function(d) { return (d || {}).path; });
    }
  }

}
<|endoftext|>


<commit_before>/* jshint -W117, -W030 */
describe('layout', function() {
    describe('sidebar', function() {
        var controller;
        var views = {
            dashboard: 'app/dashboard/dashboard.html',
            customers: 'app/customers/customers.html'
        };

        beforeEach(function() {
            module('app.layout', bard.fakeToastr);
            bard.inject('$controller', '$httpBackend', '$location',
                          '$rootScope', '$state', 'routerHelper');
        });

        beforeEach(function() {
            routerHelper.configureStates(mockData.getMockStates(), '/');
            controller = $controller('Sidebar');
            $rootScope.$apply();
        });

        bard.verifyNoOutstandingHttpRequests();

        it('should have isCurrent() for / to return `current`', function() {
            $location.path('/');
            expect(controller.isCurrent($state.current)).to.equal('current');
        });

        it('should have isCurrent() for /customers to return `current`', function() {
            $location.path('/customers');
            expect(controller.isCurrent($state.current)).to.equal('current');
        });

        it('should have isCurrent() for non route not return `current`', function() {
            $location.path('/invalid');
            expect(controller.isCurrent({title: 'invalid'})).not.to.equal('current');
        });
    });
});
<commit_msg>fixed sidebar controller's name<commit_after>/* jshint -W117, -W030 */
describe('layout', function() {
    describe('sidebar', function() {
        var controller;
        var views = {
            dashboard: 'app/dashboard/dashboard.html',
            customers: 'app/customers/customers.html'
        };

        beforeEach(function() {
            module('app.layout', bard.fakeToastr);
            bard.inject('$controller', '$httpBackend', '$location',
                          '$rootScope', '$state', 'routerHelper');
        });

        beforeEach(function() {
            routerHelper.configureStates(mockData.getMockStates(), '/');
            controller = $controller('SidebarController');
            $rootScope.$apply();
        });

        bard.verifyNoOutstandingHttpRequests();

        it('should have isCurrent() for / to return `current`', function() {
            $location.path('/');
            expect(controller.isCurrent($state.current)).to.equal('current');
        });

        it('should have isCurrent() for /customers to return `current`', function() {
            $location.path('/customers');
            expect(controller.isCurrent($state.current)).to.equal('current');
        });

        it('should have isCurrent() for non route not return `current`', function() {
            $location.path('/invalid');
            expect(controller.isCurrent({title: 'invalid'})).not.to.equal('current');
        });
    });
});
<|endoftext|>