<commit_before>// configurations
var margin = {top: 30, right: 30, bottom: 30, left: 30},
    width = 800 - margin.right - margin.left,
    height = 250 - margin.top - margin.bottom,
    transitionDuration = 800,
    formatDate = d3.time.format("%Y-%m-%d");

// global data structures
var data = [];
var filter = {};

// global chart objects
var brush = {};
var dateBarChart = {};
var countryBarChart = {};
var countryMap = {};

// queue all data file loading before proceeding further
queue()
  .defer(d3.csv, "data/kcna.csv")
  .defer(d3.json, "data/topo_countries.json")
  .await(ready);

// runs after all dependencies have downloaded
function ready(error, data, countries) {
  if (error) return console.error(error);

  // csv's load without type, so make date objects from dates and add indexes
  data.forEach(function(d,i) {
    d.index = i;
    d.date = formatDate.parse(d.date);
  });

  dateBarChart.dateDomain = d3.extent(data, function(d) { return d.date });

  buildCrossfilter(data, filter);

  // convert TopoJSON to plotable GeoJSON
  countryMap.data = topojson.feature(countries, countries.objects.countries);

  initialize();

  reDraw();
}

function buildCrossfilter(data, filter) {
  filter.cf = crossfilter(data);
  filter.byDate = filter.cf.dimension(function(p) { return p.date; });
  filter.groupByDate = filter.byDate.group();
  filter.byCountry = filter.cf.dimension(function(p) { return p.country; });
  filter.groupByCountry = filter.byCountry.group();
  return filter;
}

function initialize() {

  // variable declarations

  // DATE BAR CHART
  dateBarChart.scaleX = d3.time.scale()
    .domain(getDateBuffer())
    .range([0, width]);
  dateBarChart.scaleY = d3.scale.linear()
    .range([height, 0]);
  dateBarChart.scaleColor = d3.scale.linear()
    .range(colorbrewer.BuGn[3]);

  dateBarChart.axisX = d3.svg.axis()
    .scale(dateBarChart.scaleX)
    .orient("bottom")
    .ticks(10).tickFormat(formatDate);
  dateBarChart.axisY = d3.svg.axis()
    .scale(dateBarChart.scaleY)
    .orient("left")
    .ticks(3).tickFormat(d3.format("d"));

  // COUNTRY BAR CHART
  countryBarChart.scaleX = d3.scale.ordinal()
    .rangeRoundBands([0, width], 0.05);
  countryBarChart.scaleY =  d3.scale.linear()
    .range([height, 0]);
  countryBarChart.scaleColor = d3.scale.linear()
    .range(colorbrewer.OrRd[3]);

  countryBarChart.axisX = d3.svg.axis()
    .scale(countryBarChart.scaleX)
    .orient("bottom");

  countryBarChart.axisY = d3.svg.axis()
    .scale(countryBarChart.scaleY)
    .orient("left")
    .ticks(9)
    .tickFormat(d3.format("d"));

  // COUNTRY MAP
  countryMap.projection = d3.geo.mercator()
    .scale(150)
    .translate([width / 2, height / 2]);

  countryMap.path = d3.geo.path()
    .projection(countryMap.projection);

  // insert stuff on the DOM

  d3.selectAll("#charts .chart-container")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

  // DATE BAR CHART
  dateBarChart.gHandle = d3.select("#date-chart-container svg")
    .append("g")
    .attr("id", "date-bar-chart")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  dateBarChart.gHandle.append("g")
       .attr("class", "bars")
       .attr("id", "date-bars")
    .selectAll("rect")
       .data(filter.groupByDate.all())
       .enter()
       .append("rect")
       .attr("class", "date-bar");

  dateBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "date-axis")
    .attr("transform", "translate(0," + height + ")");

  dateBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "date-count-axis");

  // COUNTRY BAR CHART
  countryBarChart.gHandle = d3.select("#country-chart-container svg")
    .append("g")
    .attr("id", "country-bar-chart")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  countryBarChart.gHandle.append("g")
      .attr("class", "bars")
      .attr("id", "country-bars")
    .selectAll("rect")
      .data(filter.groupByCountry.all())
      .enter()
      .append("rect")
      .attr("class", "country-bar");

  countryBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "country-axis")
    .attr("transform", "translate(0," + height + ")");

  countryBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "country-count-axis");

  // COUNTRY MAP
  countryMap.gHandle = d3.select("#country-map-container svg")
    .append("g")
    .attr("class", "map")
    .attr("id", "country-map")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  countryMap.gHandle.selectAll(".country-poly")
      .data(countryMap.data.features)
    .enter()
      .append("path")
      .attr("class", "country-poly")
      .attr("id", function(d) { return d.properties.adm0_a3 })
      .attr("d", countryMap.path);

  // draw Background Rect For Brush
  dateBarChart.gHandle.append("rect")
    .attr("class", "grid-background")
    .attr("width", width)
    .attr("height", height);

  // draw brush
  brush = d3.svg.brush()
    .x(dateBarChart.scaleX)
    .extent(getBrushDefaultExtent())
    .on("brush", brushed);

  var gBrush = dateBarChart.gHandle.append("g")
    .attr("class", "brush")
    .call(brush);
  gBrush.selectAll("rect")
    .attr("y", -6)
    .attr("height", height + 7);
  gBrush.selectAll(".resize")
    .append("path")
    .attr("d", resizePath);

  // apply brushes' default extent
  filter.byDate.filterRange(brush.extent());
  reapplyFilters();
}

function reapplyFilters() {

  dateBarChart.scaleX.domain(getDateBuffer());
  dateBarChart.scaleY.domain([0,filter.groupByDate.top(1)[0].value]);
  dateBarChart.scaleColor.domain([0,filter.groupByDate.top(1)[0].value]);

  var filteredGroupByCountry = filter.groupByCountry.all().filter(function(d) { return d.value > 0; });

  countryBarChart.scaleX.domain(filteredGroupByCountry.map(function(d) { return d.key }).sort(d3.descending));
  countryBarChart.scaleY.domain([0,d3.max(filteredGroupByCountry.map(function(d) { return d.value }))]);
  countryBarChart.scaleColor.domain([0,d3.max(filteredGroupByCountry.map(function(d) { return d.value }))]);
}

function reDraw() {

  // DRAW DATE BAR GRAPH
  var dateBarWidth = (width / d3.time.days(dateBarChart.dateDomain[0],dateBarChart.dateDomain[1]).length);

  dateBarChart.gHandle.select("#date-bars")
    .selectAll("rect")
      .data(filter.groupByDate.all())
      .attr("fill", function(d) {
        return (brush.extent()[0] < d.key && d.key < brush.extent()[1] ? dateBarChart.scaleColor(d.value) : "#E3E3E3");
      })
    .transition().duration(transitionDuration)
      .attr("x", function(d, i) {
        return (dateBarChart.scaleX(d.key) - (dateBarWidth/2));
      })
      .attr("y", function(d) {
        return (dateBarChart.scaleY(d.value));
      })
      .attr("width", dateBarWidth)
      .attr("height", function(d) {
        return (height - dateBarChart.scaleY(d.value));
      });

  dateBarChart.gHandle.select("#date-axis").transition().duration(transitionDuration).call(dateBarChart.axisX);
  dateBarChart.gHandle.select("#date-count-axis").transition().duration(transitionDuration).call(dateBarChart.axisY);

  // DRAW COUNTRY BAR GRAPH
  countryBarChart.gHandle.select("#country-bars")
    .selectAll("rect")
      .data(filter.groupByCountry.all().filter(function(d) { return d.value > 0; }))
    .transition().duration(transitionDuration)
      .attr("x", function(d, i) {
          return countryBarChart.scaleX(d.key);
      })
      .attr("y", function(d) {
          return (countryBarChart.scaleY(d.value));
      })
      .attr("width", countryBarChart.scaleX.rangeBand())
      .attr("height", function(d) {
          return (height - countryBarChart.scaleY(d.value));
      })
      .attr("fill", function(d) {
          return countryBarChart.scaleColor(d.value);
      });

  countryBarChart.gHandle.select("#country-axis").transition().duration(transitionDuration).call(countryBarChart.axisX);
  countryBarChart.gHandle.select("#country-count-axis").transition().duration(transitionDuration).call(countryBarChart.axisY);

  countryMap.gHandle.selectAll(".country-poly")
    .transition().duration(transitionDuration)
      .attr("fill", function(d) { return getCountryValue(d.properties.adm0_a3) });
}

// Snapping behavior from http://bl.ocks.org/mbostock/6232620
function brushed() {
  var extent0 = brush.extent(),
      extent1;

  // if dragging, preserve the width of the extent
  if (d3.event.mode === "move") {
    var d0 = d3.time.day.round(extent0[0]),
        d1 = d3.time.day.offset(d0, Math.round((extent0[1] - extent0[0]) / 864e5));
    extent1 = [d0, d1];
  }

  // otherwise, if resizing, round both dates
  else {
    extent1 = extent0.map(d3.time.day.round);

    // if empty when rounded, use floor & ceil instead
    if (extent1[0] >= extent1[1]) {
      extent1[0] = d3.time.day.floor(extent0[0]);
      extent1[1] = d3.time.day.ceil(extent0[1]);
    }
  }

  d3.select(this).call(brush.extent(extent1));

  filter.byDate.filterRange(extent1);
  reapplyFilters();

  reDraw();
}

function getDateBuffer() {

  var minBuffer = 2; //days
  var maxBuffer = 2; //days

  var dateMinBuffer = new Date(dateBarChart.dateDomain[0]);
  dateMinBuffer.setDate(dateMinBuffer.getDate() - minBuffer);

  var dateMaxBuffer = new Date(dateBarChart.dateDomain[1]);
  dateMaxBuffer.setDate(dateMaxBuffer.getDate() + maxBuffer);

  return [dateMinBuffer, dateMaxBuffer];
}

function getBrushDefaultExtent() {

  var defaultRange = 14; //days

  var dateBrushMin = new Date(getDateBuffer()[1] - 12096e5);

  return [dateBrushMin, getDateBuffer()[1]];
}

// brush handles cribbed from [http://square.github.io/crossfilter/]
function resizePath(d) {
  var e = +(d == "e"),
      x = e ? 1 : -1,
      y = height / 3;
  return "M" + (.5 * x) + "," + y
      + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6)
      + "V" + (2 * y - 6)
      + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y)
      + "Z"
      + "M" + (2.5 * x) + "," + (y + 8)
      + "V" + (2 * y - 8)
      + "M" + (4.5 * x) + "," + (y + 8)
      + "V" + (2 * y - 8);
}

function getCountryValue(countryAlpha3) {

  var countryValue = 0;

  try {
    countryValue = filter.groupByCountry.all().filter(function(d) {
      return d.key == countryAlpha3;
    })[0].value;
  } catch(err) {
    countryValue = 0;
  }

  return countryBarChart.scaleColor(countryValue);
}
<commit_msg>specific heights for each chart instead of global "height" variable<commit_after>// configurations
var margin = {top: 30, right: 30, bottom: 30, left: 30},
    width = 800 - margin.right - margin.left,
    transitionDuration = 800,
    formatDate = d3.time.format("%Y-%m-%d");

// global data structures
var data = [];
var filter = {};

// global chart objects
var brush = {};
var dateBarChart = {};
var countryBarChart = {};
var countryMap = {};

// queue all data file loading before proceeding further
queue()
  .defer(d3.csv, "data/kcna.csv")
  .defer(d3.json, "data/topo_countries.json")
  .await(ready);

// runs after all dependencies have downloaded
function ready(error, data, countries) {
  if (error) return console.error(error);

  // csv's load without type, so make date objects from dates and add indexes
  data.forEach(function(d,i) {
    d.index = i;
    d.date = formatDate.parse(d.date);
  });

  dateBarChart.dateDomain = d3.extent(data, function(d) { return d.date });

  buildCrossfilter(data, filter);

  // convert TopoJSON to plotable GeoJSON
  countryMap.data = topojson.feature(countries, countries.objects.countries);

  initialize();

  reDraw();
}

function buildCrossfilter(data, filter) {
  filter.cf = crossfilter(data);
  filter.byDate = filter.cf.dimension(function(p) { return p.date; });
  filter.groupByDate = filter.byDate.group();
  filter.byCountry = filter.cf.dimension(function(p) { return p.country; });
  filter.groupByCountry = filter.byCountry.group();
  return filter;
}

function initialize() {

  // variable declarations

  // DATE BAR CHART
  dateBarChart.height = 250 - margin.top - margin.bottom;
  dateBarChart.scaleX = d3.time.scale()
    .domain(getDateBuffer())
    .range([0, width]);
  dateBarChart.scaleY = d3.scale.linear()
    .range([dateBarChart.height, 0]);
  dateBarChart.scaleColor = d3.scale.linear()
    .range(colorbrewer.BuGn[3]);

  dateBarChart.axisX = d3.svg.axis()
    .scale(dateBarChart.scaleX)
    .orient("bottom")
    .ticks(10).tickFormat(formatDate);
  dateBarChart.axisY = d3.svg.axis()
    .scale(dateBarChart.scaleY)
    .orient("left")
    .ticks(3).tickFormat(d3.format("d"));

  // COUNTRY BAR CHART
  countryBarChart.scaleX = d3.scale.ordinal()
    .rangeRoundBands([0, width], 0.05);
  countryBarChart.scaleY =  d3.scale.linear()
    .range([dateBarChart.height, 0]);
  countryBarChart.scaleColor = d3.scale.linear()
    .range(colorbrewer.OrRd[3]);

  countryBarChart.axisX = d3.svg.axis()
    .scale(countryBarChart.scaleX)
    .orient("bottom");

  countryBarChart.axisY = d3.svg.axis()
    .scale(countryBarChart.scaleY)
    .orient("left")
    .ticks(9)
    .tickFormat(d3.format("d"));

  // COUNTRY MAP
  countryMap.height = 600 - margin.top - margin.bottom;
  countryMap.projection = d3.geo.mercator()
    .scale(150)
    .translate([width / 2, countryMap.height / 2]);

  countryMap.path = d3.geo.path()
    .projection(countryMap.projection);

  // insert stuff on the DOM

  // DATE BAR CHART
   d3.select("#date-chart-container")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", dateBarChart.height + margin.top + margin.bottom);

  dateBarChart.gHandle = d3.select("#date-chart-container svg")
    .append("g")
    .attr("id", "date-bar-chart")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  dateBarChart.gHandle.append("g")
       .attr("class", "bars")
       .attr("id", "date-bars")
    .selectAll("rect")
       .data(filter.groupByDate.all())
       .enter()
       .append("rect")
       .attr("class", "date-bar");

  dateBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "date-axis")
    .attr("transform", "translate(0," + dateBarChart.height + ")");

  dateBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "date-count-axis");

  // COUNTRY BAR CHART
   d3.select("#country-chart-container")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", dateBarChart.height + margin.top + margin.bottom);

  countryBarChart.gHandle = d3.select("#country-chart-container svg")
    .append("g")
    .attr("id", "country-bar-chart")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  countryBarChart.gHandle.append("g")
      .attr("class", "bars")
      .attr("id", "country-bars")
    .selectAll("rect")
      .data(filter.groupByCountry.all())
      .enter()
      .append("rect")
      .attr("class", "country-bar");

  countryBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "country-axis")
    .attr("transform", "translate(0," + dateBarChart.height + ")");

  countryBarChart.gHandle.append("g")
    .attr("class", "axis")
    .attr("id", "country-count-axis");

  // COUNTRY MAP
   d3.select("#country-map-container")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", countryMap.height + margin.top + margin.bottom);

  countryMap.gHandle = d3.select("#country-map-container svg")
    .append("g")
    .attr("class", "map")
    .attr("id", "country-map")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  countryMap.gHandle.selectAll(".country-poly")
      .data(countryMap.data.features)
    .enter()
      .append("path")
      .attr("class", "country-poly")
      .attr("id", function(d) { return d.properties.adm0_a3 })
      .attr("d", countryMap.path);

  // draw Background Rect For Brush
  dateBarChart.gHandle.append("rect")
    .attr("class", "grid-background")
    .attr("width", width)
    .attr("height", dateBarChart.height);

  // draw brush
  brush = d3.svg.brush()
    .x(dateBarChart.scaleX)
    .extent(getBrushDefaultExtent())
    .on("brush", brushed);

  var gBrush = dateBarChart.gHandle.append("g")
    .attr("class", "brush")
    .call(brush);
  gBrush.selectAll("rect")
    .attr("y", -6)
    .attr("height", dateBarChart.height + 7);
  gBrush.selectAll(".resize")
    .append("path")
    .attr("d", resizePath);

  // apply brushes' default extent
  filter.byDate.filterRange(brush.extent());
  reapplyFilters();
}

function reapplyFilters() {

  dateBarChart.scaleX.domain(getDateBuffer());
  dateBarChart.scaleY.domain([0,filter.groupByDate.top(1)[0].value]);
  dateBarChart.scaleColor.domain([0,filter.groupByDate.top(1)[0].value]);

  var filteredGroupByCountry = filter.groupByCountry.all().filter(function(d) { return d.value > 0; });

  countryBarChart.scaleX.domain(filteredGroupByCountry.map(function(d) { return d.key }).sort(d3.descending));
  countryBarChart.scaleY.domain([0,d3.max(filteredGroupByCountry.map(function(d) { return d.value }))]);
  countryBarChart.scaleColor.domain([0,d3.max(filteredGroupByCountry.map(function(d) { return d.value }))]);
}

function reDraw() {

  // DRAW DATE BAR GRAPH
  var dateBarWidth = (width / d3.time.days(dateBarChart.dateDomain[0],dateBarChart.dateDomain[1]).length);

  dateBarChart.gHandle.select("#date-bars")
    .selectAll("rect")
      .data(filter.groupByDate.all())
      .attr("fill", function(d) {
        return (brush.extent()[0] < d.key && d.key < brush.extent()[1] ? dateBarChart.scaleColor(d.value) : "#E3E3E3");
      })
    .transition().duration(transitionDuration)
      .attr("x", function(d, i) {
        return (dateBarChart.scaleX(d.key) - (dateBarWidth/2));
      })
      .attr("y", function(d) {
        return (dateBarChart.scaleY(d.value));
      })
      .attr("width", dateBarWidth)
      .attr("height", function(d) {
        return (dateBarChart.height - dateBarChart.scaleY(d.value));
      });

  dateBarChart.gHandle.select("#date-axis").transition().duration(transitionDuration).call(dateBarChart.axisX);
  dateBarChart.gHandle.select("#date-count-axis").transition().duration(transitionDuration).call(dateBarChart.axisY);

  // DRAW COUNTRY BAR GRAPH
  countryBarChart.gHandle.select("#country-bars")
    .selectAll("rect")
      .data(filter.groupByCountry.all().filter(function(d) { return d.value > 0; }))
    .transition().duration(transitionDuration)
      .attr("x", function(d, i) {
          return countryBarChart.scaleX(d.key);
      })
      .attr("y", function(d) {
          return (countryBarChart.scaleY(d.value));
      })
      .attr("width", countryBarChart.scaleX.rangeBand())
      .attr("height", function(d) {
          return (dateBarChart.height - countryBarChart.scaleY(d.value));
      })
      .attr("fill", function(d) {
          return countryBarChart.scaleColor(d.value);
      });

  countryBarChart.gHandle.select("#country-axis").transition().duration(transitionDuration).call(countryBarChart.axisX);
  countryBarChart.gHandle.select("#country-count-axis").transition().duration(transitionDuration).call(countryBarChart.axisY);

  countryMap.gHandle.selectAll(".country-poly")
    .transition().duration(transitionDuration)
      .attr("fill", function(d) { return getCountryValue(d.properties.adm0_a3) });
}

// Snapping behavior from http://bl.ocks.org/mbostock/6232620
function brushed() {
  var extent0 = brush.extent(),
      extent1;

  // if dragging, preserve the width of the extent
  if (d3.event.mode === "move") {
    var d0 = d3.time.day.round(extent0[0]),
        d1 = d3.time.day.offset(d0, Math.round((extent0[1] - extent0[0]) / 864e5));
    extent1 = [d0, d1];
  }

  // otherwise, if resizing, round both dates
  else {
    extent1 = extent0.map(d3.time.day.round);

    // if empty when rounded, use floor & ceil instead
    if (extent1[0] >= extent1[1]) {
      extent1[0] = d3.time.day.floor(extent0[0]);
      extent1[1] = d3.time.day.ceil(extent0[1]);
    }
  }

  d3.select(this).call(brush.extent(extent1));

  filter.byDate.filterRange(extent1);
  reapplyFilters();

  reDraw();
}

function getDateBuffer() {

  var minBuffer = 2; //days
  var maxBuffer = 2; //days

  var dateMinBuffer = new Date(dateBarChart.dateDomain[0]);
  dateMinBuffer.setDate(dateMinBuffer.getDate() - minBuffer);

  var dateMaxBuffer = new Date(dateBarChart.dateDomain[1]);
  dateMaxBuffer.setDate(dateMaxBuffer.getDate() + maxBuffer);

  return [dateMinBuffer, dateMaxBuffer];
}

function getBrushDefaultExtent() {

  var defaultRange = 14; //days

  var dateBrushMin = new Date(getDateBuffer()[1] - 12096e5);

  return [dateBrushMin, getDateBuffer()[1]];
}

// brush handles cribbed from [http://square.github.io/crossfilter/]
function resizePath(d) {
  var e = +(d == "e"),
      x = e ? 1 : -1,
      y = dateBarChart.height / 3;
  return "M" + (.5 * x) + "," + y
      + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6)
      + "V" + (2 * y - 6)
      + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y)
      + "Z"
      + "M" + (2.5 * x) + "," + (y + 8)
      + "V" + (2 * y - 8)
      + "M" + (4.5 * x) + "," + (y + 8)
      + "V" + (2 * y - 8);
}

function getCountryValue(countryAlpha3) {

  var countryValue = 0;

  try {
    countryValue = filter.groupByCountry.all().filter(function(d) {
      return d.key == countryAlpha3;
    })[0].value;
  } catch(err) {
    countryValue = 0;
  }

  return countryBarChart.scaleColor(countryValue);
}
<|endoftext|>


<commit_before>/*!
    Copyright (C) 2015 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: ivan@reciprocitylabs.com
    Maintained By: ivan@reciprocitylabs.com
*/
(function($, GGRC) {
  GGRC.Utils = {
    getPickerElement: function (picker) {
      return _.find(_.values(picker), function (val) {
        if (val instanceof Node) {
          return /picker\-dialog/.test(val.className);
        }
        return false;
      });
    },
    download: function (filename, text) {
      var element = document.createElement('a');
      element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
      element.setAttribute('download', filename);
      element.style.display = 'none';
      document.body.appendChild(element);
      element.click();
      document.body.removeChild(element);
    },
    export_request: function (request) {
      return $.ajax({
        type: "POST",
        dataType: "text",
        headers: $.extend({
          "Content-Type": "application/json",
          "X-export-view": "blocks",
          "X-requested-by": "gGRC"
        }, request.headers || {}),
        url: "/_service/export_csv",
        data: JSON.stringify(request.data || {})
      });
    },
    is_mapped: function (target, destination) {
      var table_plural = CMS.Models[destination.type].table_plural,
          bindings = target.get_binding((target.has_binding(table_plural) ? "" : "related_") + table_plural);

      if (bindings && bindings.list && bindings.list.length) {
        return _.find(bindings.list, function (item) {
          return item.instance.id === destination.id;
        });
      }
      if (target.objects && target.objects.length) {
        return _.find(target.objects, function (item) {
          return item.id === destination.id && item.type === destination.type;
        });
      }
    },
    allowed_to_map: function (source, target, options) {
      var can_map = false,
          target_type, source_type, context_id;

      target_type = target instanceof can.Model ? target.constructor.shortName
                                                : (target.type || target);
      source_type = source.constructor.shortName || source;
      context_id = source.context ? source.context.id : null;

      if (!(source instanceof CMS.Models.Program)
        && target instanceof CMS.Models.Program) {
        context_id = target.context ? target.context.id : null;
      }

      can_map = Permission.is_allowed_for("update", source);
      if (target instanceof can.Model) {
        can_map = Permission.is_allowed_for("update", target);
      }
      return can_map;
    }
  };
})(jQuery, window.GGRC = window.GGRC || {});
<commit_msg>Remove context id since we get instance<commit_after>/*!
    Copyright (C) 2015 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: ivan@reciprocitylabs.com
    Maintained By: ivan@reciprocitylabs.com
*/
(function($, GGRC) {
  GGRC.Utils = {
    getPickerElement: function (picker) {
      return _.find(_.values(picker), function (val) {
        if (val instanceof Node) {
          return /picker\-dialog/.test(val.className);
        }
        return false;
      });
    },
    download: function (filename, text) {
      var element = document.createElement('a');
      element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
      element.setAttribute('download', filename);
      element.style.display = 'none';
      document.body.appendChild(element);
      element.click();
      document.body.removeChild(element);
    },
    export_request: function (request) {
      return $.ajax({
        type: "POST",
        dataType: "text",
        headers: $.extend({
          "Content-Type": "application/json",
          "X-export-view": "blocks",
          "X-requested-by": "gGRC"
        }, request.headers || {}),
        url: "/_service/export_csv",
        data: JSON.stringify(request.data || {})
      });
    },
    is_mapped: function (target, destination) {
      var table_plural = CMS.Models[destination.type].table_plural,
          bindings = target.get_binding((target.has_binding(table_plural) ? "" : "related_") + table_plural);

      if (bindings && bindings.list && bindings.list.length) {
        return _.find(bindings.list, function (item) {
          return item.instance.id === destination.id;
        });
      }
      if (target.objects && target.objects.length) {
        return _.find(target.objects, function (item) {
          return item.id === destination.id && item.type === destination.type;
        });
      }
    },
    allowed_to_map: function (source, target, options) {
      var can_map = false,
          target_type, source_type;

      target_type = target instanceof can.Model ? target.constructor.shortName
                                                : (target.type || target);
      source_type = source.constructor.shortName || source;

      can_map = Permission.is_allowed_for("update", source);
      if (target instanceof can.Model) {
        can_map = Permission.is_allowed_for("update", target);
      }
      return can_map;
    }
  };
})(jQuery, window.GGRC = window.GGRC || {});
<|endoftext|>


<commit_before>var common = require('./common')
var Peer = require('../')
var test = require('tape')
var bowser = require('bowser')

var config
test('get config', function (t) {
  common.getConfig(function (err, _config) {
    if (err) return t.fail(err)
    config = _config
    t.end()
  })
})

test('multistream', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(20)

  var peer1 = new Peer({
    config: config,
    initiator: true,
    wrtc: common.wrtc,
    streams: (new Array(10)).fill(null).map(function () { return common.getMediaStream() })
  })
  var peer2 = new Peer({
    config: config,
    wrtc: common.wrtc,
    streams: (new Array(10)).fill(null).map(function () { return common.getMediaStream() })
  })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var receivedIds = {}

  peer1.on('stream', function (stream) {
    t.pass('peer1 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
  })
  peer2.on('stream', function (stream) {
    t.pass('peer2 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
  })
})

test('incremental multistream', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(12)

  var peer1 = new Peer({
    config: config,
    initiator: true,
    wrtc: common.wrtc,
    streams: []
  })
  var peer2 = new Peer({
    config: config,
    wrtc: common.wrtc,
    streams: []
  })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  peer1.on('connect', function () {
    t.pass('peer1 connected')
    peer1.addStream(common.getMediaStream())
  })
  peer2.on('connect', function () {
    t.pass('peer2 connected')
    peer2.addStream(common.getMediaStream())
  })

  var receivedIds = {}

  var count1 = 0
  peer1.on('stream', function (stream) {
    t.pass('peer1 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
    count1++
    if (count1 < 5) {
      peer1.addStream(common.getMediaStream())
    }
  })

  var count2 = 0
  peer2.on('stream', function (stream) {
    t.pass('peer2 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
    count2++
    if (count2 < 5) {
      peer2.addStream(common.getMediaStream())
    }
  })
})

test('track and stream ids are correct', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  if (bowser.safari || bowser.ios) {
    // Note: WebKit bug filed here: https://bugs.webkit.org/show_bug.cgi?id=174519
    t.pass('Skipping test, track ids are randomized in Safari')
    t.end()
    return
  }
  t.plan(6)

  var peer1 = new Peer({ config: config, initiator: true, wrtc: common.wrtc })
  var peer2 = new Peer({ config: config, wrtc: common.wrtc })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var stream1 = common.getMediaStream()
  var stream2 = common.getMediaStream()

  stream1.removeTrack(stream1.getTracks()[1]) // single-track mediastream
  stream2.removeTrack(stream2.getTracks()[1])

  peer1.addTrack(stream1.getTracks()[0], stream1)
  peer2.addTrack(stream2.getTracks()[0], stream2)

  peer1.on('track', function (track, stream) {
    t.equal(track.id, stream2.getTracks()[0].id, 'track id is correct')
    t.equal(stream.id, stream2.id, 'stream id is correct')
  })
  peer2.on('track', function (track, stream) {
    t.equal(track.id, stream1.getTracks()[0].id, 'track id is correct')
    t.equal(stream.id, stream1.id, 'stream id is correct')
  })

  peer1.on('stream', function (stream) {
    t.equal(stream.id, stream2.id, 'stream id is correct')
  })
  peer2.on('stream', function (stream) {
    t.equal(stream.id, stream1.id, 'stream id is correct')
  })
})

test('removeTrack immediately', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(2)

  var peer1 = new Peer({ config: config, initiator: true, wrtc: common.wrtc })
  var peer2 = new Peer({ config: config, wrtc: common.wrtc })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var stream1 = common.getMediaStream()
  var stream2 = common.getMediaStream()

  peer1.addTrack(stream1.getTracks()[0], stream1)
  peer2.addTrack(stream2.getTracks()[0], stream2)

  peer1.removeTrack(stream1.getTracks()[0], stream1)
  peer2.removeTrack(stream2.getTracks()[0], stream2)

  peer1.on('track', function (track, stream) {
    t.fail('peer1 did not get track event')
  })
  peer1.on('removetrack', function (track, stream) {
    t.fail('remote removetrack not received')
  })

  peer2.on('track', function (track, stream) {
    t.fail('peer2 did not get track event')
  })
  peer2.on('removetrack', function (track, stream) {
    t.fail('remote removetrack not received')
  })

  peer1.on('connect', function () {
    t.pass('peer1 connected')
  })
  peer2.on('connect', function () {
    t.pass('peer2 connected')
  })
})
<commit_msg>Firefox no longer passes local MSIDs to the SDP<commit_after>var common = require('./common')
var Peer = require('../')
var test = require('tape')
var bowser = require('bowser')

var config
test('get config', function (t) {
  common.getConfig(function (err, _config) {
    if (err) return t.fail(err)
    config = _config
    t.end()
  })
})

test('multistream', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(20)

  var peer1 = new Peer({
    config: config,
    initiator: true,
    wrtc: common.wrtc,
    streams: (new Array(10)).fill(null).map(function () { return common.getMediaStream() })
  })
  var peer2 = new Peer({
    config: config,
    wrtc: common.wrtc,
    streams: (new Array(10)).fill(null).map(function () { return common.getMediaStream() })
  })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var receivedIds = {}

  peer1.on('stream', function (stream) {
    t.pass('peer1 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
  })
  peer2.on('stream', function (stream) {
    t.pass('peer2 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
  })
})

test('incremental multistream', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(12)

  var peer1 = new Peer({
    config: config,
    initiator: true,
    wrtc: common.wrtc,
    streams: []
  })
  var peer2 = new Peer({
    config: config,
    wrtc: common.wrtc,
    streams: []
  })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  peer1.on('connect', function () {
    t.pass('peer1 connected')
    peer1.addStream(common.getMediaStream())
  })
  peer2.on('connect', function () {
    t.pass('peer2 connected')
    peer2.addStream(common.getMediaStream())
  })

  var receivedIds = {}

  var count1 = 0
  peer1.on('stream', function (stream) {
    t.pass('peer1 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
    count1++
    if (count1 < 5) {
      peer1.addStream(common.getMediaStream())
    }
  })

  var count2 = 0
  peer2.on('stream', function (stream) {
    t.pass('peer2 got stream')
    if (receivedIds[stream.id]) {
      t.fail('received one unique stream per event')
    } else {
      receivedIds[stream.id] = true
    }
    count2++
    if (count2 < 5) {
      peer2.addStream(common.getMediaStream())
    }
  })
})

test('track and stream ids are correct', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  if (bowser.safari || bowser.ios || bowser.firefox) {
    // Note: WebKit bug filed here: https://bugs.webkit.org/show_bug.cgi?id=174519
    t.pass('Skipping test, track ids are randomized in Safari')
    t.end()
    return
  }
  t.plan(6)

  var peer1 = new Peer({ config: config, initiator: true, wrtc: common.wrtc })
  var peer2 = new Peer({ config: config, wrtc: common.wrtc })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var stream1 = common.getMediaStream()
  var stream2 = common.getMediaStream()

  stream1.removeTrack(stream1.getTracks()[1]) // single-track mediastream
  stream2.removeTrack(stream2.getTracks()[1])

  peer1.addTrack(stream1.getTracks()[0], stream1)
  peer2.addTrack(stream2.getTracks()[0], stream2)

  peer1.on('track', function (track, stream) {
    t.equal(track.id, stream2.getTracks()[0].id, 'track id is correct')
    t.equal(stream.id, stream2.id, 'stream id is correct')
  })
  peer2.on('track', function (track, stream) {
    t.equal(track.id, stream1.getTracks()[0].id, 'track id is correct')
    t.equal(stream.id, stream1.id, 'stream id is correct')
  })

  peer1.on('stream', function (stream) {
    t.equal(stream.id, stream2.id, 'stream id is correct')
  })
  peer2.on('stream', function (stream) {
    t.equal(stream.id, stream1.id, 'stream id is correct')
  })
})

test('removeTrack immediately', function (t) {
  if (common.wrtc) {
    t.pass('Skipping test, no MediaStream support on wrtc')
    t.end()
    return
  }
  t.plan(2)

  var peer1 = new Peer({ config: config, initiator: true, wrtc: common.wrtc })
  var peer2 = new Peer({ config: config, wrtc: common.wrtc })

  peer1.on('signal', function (data) { if (!peer2.destroyed) peer2.signal(data) })
  peer2.on('signal', function (data) { if (!peer1.destroyed) peer1.signal(data) })

  var stream1 = common.getMediaStream()
  var stream2 = common.getMediaStream()

  peer1.addTrack(stream1.getTracks()[0], stream1)
  peer2.addTrack(stream2.getTracks()[0], stream2)

  peer1.removeTrack(stream1.getTracks()[0], stream1)
  peer2.removeTrack(stream2.getTracks()[0], stream2)

  peer1.on('track', function (track, stream) {
    t.fail('peer1 did not get track event')
  })
  peer1.on('removetrack', function (track, stream) {
    t.fail('remote removetrack not received')
  })

  peer2.on('track', function (track, stream) {
    t.fail('peer2 did not get track event')
  })
  peer2.on('removetrack', function (track, stream) {
    t.fail('remote removetrack not received')
  })

  peer1.on('connect', function () {
    t.pass('peer1 connected')
  })
  peer2.on('connect', function () {
    t.pass('peer2 connected')
  })
})
<|endoftext|>


<commit_before>$('.nav a').on('click', function() {
    $('.navbar-toggle').click();
});
<commit_msg>Corrected non-mobile navbar click triggering toggle<commit_after>$('.nav a').on('click', function() {
    if ($('.navbar-collapse.in')[0])
        $('.navbar-toggle').click();
});
<|endoftext|>


<commit_before>'use strict';

var ko = require('knockout');
require('knockout.punches');
var $ = require('jquery');
var bootbox = require('bootbox');
var $osf = require('./osfHelpers');
var waterbutler = require('./waterbutler');

ko.punches.enableAll();

var urlParams = $osf.urlParams();

var Revision = function(data, index, file, node) {
    var self = this;
    var options = {};

    $.extend(self, data);

    if (urlParams.branch !== undefined) {
        options.branch = urlParams.branch;
    }
    options[self.versionIdentifier] = self.version;
    self.displayVersion = null;
    switch (file.provider) {
        // Note: Google Drive version identifiers often begin with the same sequence
        case 'googledrive':
            self.displayVersion = self.version.substring(self.version.length - 8);
            break;
        // Note: Dataverse internal version names are ugly; Substitute our own
        case 'dataverse':
            var displayMap = {
                'latest': 'Draft',
                'latest-published': 'Published'
            };

            self.displayVersion = self.version in displayMap ?
                displayMap[self.version] : self.version.substring(0, 8);
            break;
        default:
            self.displayVersion = self.version.substring(0, 8);
    }

    self.date = new $osf.FormattableDate(data.modified);
    self.displayDate = self.date.local !== 'Invalid date' ?
        self.date.local :
        data.date;

    // Append modification time to file name if OSF Storage and not current version
    if (file.provider === 'osfstorage' && file.name && index !== 0) {
        var parts = file.name.split('.');
        if (parts.length === 1) {
            options.displayName = parts[0] + '-' + data.modified;
        } else {
            options.displayName = parts.slice(0, parts.length - 1).join('') + '-' + data.modified + '.' + parts[parts.length - 1];
        }
    }

    self.osfViewUrl = '?' + $.param(options);
    self.osfDownloadUrl = '?' + $.param($.extend({action: 'download'}, options));
    self.waterbutlerDownloadUrl = waterbutler.buildDownloadUrl(file.path, file.provider, node.id, options);

    self.download = function() {
        window.location = self.waterbutlerDownloadUrl;
        return false;
    };
};

var RevisionsViewModel = function(node, file, editable) {
    var self = this;
    var fileExtra = file.extra || {};
    var revisionsOptions = {};

    if (urlParams.branch !== undefined) {
        fileExtra.branch = urlParams.branch;
        revisionsOptions.sha = urlParams.branch;
    }

    self.node = node;
    self.file = file;
    self.path = file.provider !== 'googledrive' ?
        (file.materializedPath || file.path).split('/') :
        (file.materializedPath || file.path).split('/').map(decodeURIComponent);

    // Hack: Set Figshare files to uneditable by default, then update after
    // fetching file metadata after revisions request fails
    self.editable = ko.observable(editable && file.provider !== 'figshare');
    self.urls = {
        delete: waterbutler.buildDeleteUrl(file.path, file.provider, node.id, fileExtra),
        download: waterbutler.buildDownloadUrl(file.path, file.provider, node.id, fileExtra),
        metadata: waterbutler.buildMetadataUrl(file.path, file.provider, node.id, revisionsOptions),
        revisions: waterbutler.buildRevisionsUrl(file.path, file.provider, node.id, revisionsOptions)
    };

    self.errorMessage = ko.observable('');
    self.currentVersion = ko.observable({});
    self.revisions = ko.observableArray([]);
    self.versioningSupported = ko.observable(true);

    self.userColumn = ko.computed(function() {
        return self.revisions()[0] &&
            self.revisions()[0].extra &&
            self.revisions()[0].extra.user;
    });

    self.hasDate = ko.computed(function() {
        return self.file.provider !== 'dataverse';
    });
};

RevisionsViewModel.prototype.fetch = function() {
    var self = this;

    // Dataverse Hack: Only latest version is editable;
    // Users without edit permission should not see revision table
    if (self.file.provider === 'dataverse') {
        if (self.editable()) {
            self.editable(urlParams.version === 'latest');
        } else {
            return;
        }
    }

    var request = $.ajax({
        url: self.urls.revisions,
        dataType: 'json',
        beforeSend: $osf.setXHRAuthorization
    });

    request.done(function(response) {
        self.revisions(ko.utils.arrayMap(response.data, function(item, index) {
            if ($osf.urlParams()[item.versionIdentifier] === item.version) {
                self.currentVersion(new Revision(item, index, self.file, self.node));
                return self.currentVersion();
            }
            return new Revision(item, index, self.file, self.node);
        }));

        if (Object.keys(self.currentVersion()).length === 0) {
            self.currentVersion(self.revisions()[0]);
        }

        $osf.tableResize('#fileRevisions', 4);
    });

    request.fail(function(response) {
        self.versioningSupported(false);
        var err = response.responseJSON ?
            response.responseJSON.message || 'Unable to fetch versions' :
            'Unable to fetch versions';

        self.errorMessage(err);

        if (self.file.provider === 'figshare') {
            // Hack for Figshare
            // only figshare will error on a revisions request
            // so dont allow downloads and set a fake current version
            $.ajax({
                method: 'GET',
                url: self.urls.metadata,
                beforeSend: $osf.setXHRAuthorization
            }).done(function(resp) {
                self.editable(resp.data.extra.canDelete && resp.data.permissions.edit );
            }).fail(function(xhr) {
                self.editable(false);
            });
        }

        self.currentVersion({
            osfViewUrl: '',
            osfDownloadUrl: '?action=download',
            download: function() {
                window.location = self.urls.download + '&' + $.param({displayName: self.file.name});
                return false;
            }
        });
    });
};

RevisionsViewModel.prototype.delete = function() {
    var self = this;
    $.ajax({
        type: 'DELETE',
        url: self.urls.delete,
        beforeSend: $osf.setXHRAuthorization
    }).done(function() {
        window.location = self.node.urls.files;
    }).fail(function() {
        $osf.growl('Error', 'Could not delete file.');
    });
};

RevisionsViewModel.prototype.askDelete = function() {
    var self = this;
    bootbox.confirm({
        title: 'Delete file?',
        message: '
' +
                'Are you sure you want to delete ' +
                self.file.safeName + '?' +
            '
',
        callback: function(confirm) {
            if (confirm) {
                self.delete();
            }
        }
    });
};

RevisionsViewModel.prototype.isActive = function(version) {
    var self = this;

    if (self.currentVersion() === version) {
        return 'info';
    }
    return;
};

var RevisionTable = function(selector, node, file, editable) {

    var self = this;

    self.viewModel = new RevisionsViewModel(node, file, editable);
    self.viewModel.fetch();
    $osf.applyBindings(self.viewModel, selector);

};

module.exports = RevisionTable;
<commit_msg>Make sure the Delete button appears on file viewer; Still no fix for read-only users seeing button on file viewer<commit_after>'use strict';

var ko = require('knockout');
require('knockout.punches');
var $ = require('jquery');
var bootbox = require('bootbox');
var $osf = require('./osfHelpers');
var waterbutler = require('./waterbutler');

ko.punches.enableAll();

var urlParams = $osf.urlParams();

var Revision = function(data, index, file, node) {
    var self = this;
    var options = {};

    $.extend(self, data);

    if (urlParams.branch !== undefined) {
        options.branch = urlParams.branch;
    }
    options[self.versionIdentifier] = self.version;
    self.displayVersion = null;
    switch (file.provider) {
        // Note: Google Drive version identifiers often begin with the same sequence
        case 'googledrive':
            self.displayVersion = self.version.substring(self.version.length - 8);
            break;
        // Note: Dataverse internal version names are ugly; Substitute our own
        case 'dataverse':
            var displayMap = {
                'latest': 'Draft',
                'latest-published': 'Published'
            };

            self.displayVersion = self.version in displayMap ?
                displayMap[self.version] : self.version.substring(0, 8);
            break;
        default:
            self.displayVersion = self.version.substring(0, 8);
    }

    self.date = new $osf.FormattableDate(data.modified);
    self.displayDate = self.date.local !== 'Invalid date' ?
        self.date.local :
        data.date;

    // Append modification time to file name if OSF Storage and not current version
    if (file.provider === 'osfstorage' && file.name && index !== 0) {
        var parts = file.name.split('.');
        if (parts.length === 1) {
            options.displayName = parts[0] + '-' + data.modified;
        } else {
            options.displayName = parts.slice(0, parts.length - 1).join('') + '-' + data.modified + '.' + parts[parts.length - 1];
        }
    }

    self.osfViewUrl = '?' + $.param(options);
    self.osfDownloadUrl = '?' + $.param($.extend({action: 'download'}, options));
    self.waterbutlerDownloadUrl = waterbutler.buildDownloadUrl(file.path, file.provider, node.id, options);

    self.download = function() {
        window.location = self.waterbutlerDownloadUrl;
        return false;
    };
};

var RevisionsViewModel = function(node, file, editable) {
    var self = this;
    var fileExtra = file.extra || {};
    var revisionsOptions = {};

    if (urlParams.branch !== undefined) {
        fileExtra.branch = urlParams.branch;
        revisionsOptions.sha = urlParams.branch;
    }

    self.node = node;
    self.file = file;
    self.path = file.provider !== 'googledrive' ?
        (file.materializedPath || file.path).split('/') :
        (file.materializedPath || file.path).split('/').map(decodeURIComponent);

    // Hack: Set Figshare files to uneditable by default, then update after
    // fetching file metadata after revisions request fails
    self.editable = ko.observable(editable && file.provider !== 'figshare');
    self.urls = {
        delete: waterbutler.buildDeleteUrl(file.path, file.provider, node.id, fileExtra),
        download: waterbutler.buildDownloadUrl(file.path, file.provider, node.id, fileExtra),
        metadata: waterbutler.buildMetadataUrl(file.path, file.provider, node.id, revisionsOptions),
        revisions: waterbutler.buildRevisionsUrl(file.path, file.provider, node.id, revisionsOptions)
    };

    self.errorMessage = ko.observable('');
    self.currentVersion = ko.observable({});
    self.revisions = ko.observableArray([]);
    self.versioningSupported = ko.observable(true);

    self.userColumn = ko.computed(function() {
        return self.revisions()[0] &&
            self.revisions()[0].extra &&
            self.revisions()[0].extra.user;
    });

    self.hasDate = ko.computed(function() {
        return self.file.provider !== 'dataverse';
    });
};

RevisionsViewModel.prototype.fetch = function() {
    var self = this;

    // Dataverse Hack: Only latest version is editable;
    // Users without edit permission should not see revision table
    if (self.file.provider === 'dataverse') {
        if (self.editable()) {
            self.editable(urlParams.version === 'latest');
        } else {
            return;
        }
    }

    var request = $.ajax({
        url: self.urls.revisions,
        dataType: 'json',
        beforeSend: $osf.setXHRAuthorization
    });

    request.done(function(response) {
        self.revisions(ko.utils.arrayMap(response.data, function(item, index) {
            if ($osf.urlParams()[item.versionIdentifier] === item.version) {
                self.currentVersion(new Revision(item, index, self.file, self.node));
                return self.currentVersion();
            }
            return new Revision(item, index, self.file, self.node);
        }));

        if (Object.keys(self.currentVersion()).length === 0) {
            self.currentVersion(self.revisions()[0]);
        }

        $osf.tableResize('#fileRevisions', 4);
    });

    request.fail(function(response) {
        self.versioningSupported(false);
        var err = response.responseJSON ?
            response.responseJSON.message || 'Unable to fetch versions' :
            'Unable to fetch versions';

        self.errorMessage(err);

        if (self.file.provider === 'figshare') {
            // Hack for Figshare
            // only figshare will error on a revisions request
            // so dont allow downloads and set a fake current version
            $.ajax({
                method: 'GET',
                url: self.urls.metadata,
                beforeSend: $osf.setXHRAuthorization
            }).done(function(resp) {
                self.editable(resp.data.extra.canDelete);
            }).fail(function(xhr) {
                self.editable(false);
            });
        }

        self.currentVersion({
            osfViewUrl: '',
            osfDownloadUrl: '?action=download',
            download: function() {
                window.location = self.urls.download + '&' + $.param({displayName: self.file.name});
                return false;
            }
        });
    });
};

RevisionsViewModel.prototype.delete = function() {
    var self = this;
    $.ajax({
        type: 'DELETE',
        url: self.urls.delete,
        beforeSend: $osf.setXHRAuthorization
    }).done(function() {
        window.location = self.node.urls.files;
    }).fail(function() {
        $osf.growl('Error', 'Could not delete file.');
    });
};

RevisionsViewModel.prototype.askDelete = function() {
    var self = this;
    bootbox.confirm({
        title: 'Delete file?',
        message: '
' +
                'Are you sure you want to delete ' +
                self.file.safeName + '?' +
            '
',
        callback: function(confirm) {
            if (confirm) {
                self.delete();
            }
        }
    });
};

RevisionsViewModel.prototype.isActive = function(version) {
    var self = this;

    if (self.currentVersion() === version) {
        return 'info';
    }
    return;
};

var RevisionTable = function(selector, node, file, editable) {

    var self = this;

    self.viewModel = new RevisionsViewModel(node, file, editable);
    self.viewModel.fetch();
    $osf.applyBindings(self.viewModel, selector);

};

module.exports = RevisionTable;
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import ErrorText from './ErrorText';
import HelpText from './HelpText';
import WarningText from './WarningText';

class ValidationText extends PureComponent {
  render() {
    const { error, inverse, help, warning } = this.props;

    if (error) {
      return <ErrorText inverse={inverse}>{error}</ErrorText>;
    }

    if (warning) {
      return <WarningText inverse={inverse}>{warning}</WarningText>;
    }

    if (help) {
      return <HelpText inverse={inverse}>{help}</HelpText>;
    }

    return null;
  }
}

ValidationText.propTypes = {
  error: PropTypes.node,
  help: PropTypes.node,
  inverse: PropTypes.bool,
  warning: PropTypes.node,
};

export default ValidationText;
<commit_msg>Implement SuccessText in our ValidationText component<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import ErrorText from './ErrorText';
import HelpText from './HelpText';
import SuccessText from './SuccessText';
import WarningText from './WarningText';

class ValidationText extends PureComponent {
  render() {
    const { error, inverse, help, success, warning } = this.props;

    if (error) {
      return <ErrorText inverse={inverse}>{error}</ErrorText>;
    }

    if (warning) {
      return <WarningText inverse={inverse}>{warning}</WarningText>;
    }

    if (success) {
      return <SuccessText inverse={inverse}>{success}</SuccessText>;
    }

    if (help) {
      return <HelpText inverse={inverse}>{help}</HelpText>;
    }

    return null;
  }
}

ValidationText.propTypes = {
  error: PropTypes.node,
  help: PropTypes.node,
  inverse: PropTypes.bool,
  success: PropTypes.bool,
  warning: PropTypes.node,
};

export default ValidationText;
<|endoftext|>


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

var twitter = new ChirpStream({
    consumer: {
        public: process.env.TWITTER_CONSUMER_PUBLIC,
        secret: process.env.TWITTER_CONSUMER_SECRET
    },
    token: {
        public: process.env.TWITTER_TOKEN_PUBLIC,
        secret: process.env.TWITTER_SECRET_SECRET
    }
});

var userstream = twitter.stream('https://stream.twitter.com/1.1/statuses/filter.json', {
    data: {
        follow: 61260444 //me :)
    }
});

userstream.on('data', function(data) {
    console.log('data');
    console.log(data);
});

userstream.on('json', function(json) {
    console.log('json');
    console.log(json);
});

userstream.on('end', function() {
    console.log('end');
});

userstream.on('error', function(error) {
    console.log('error');
    console.log(error);
});<commit_msg>update example<commit_after>var ChirpStream = require('./');

var twitter = new ChirpStream({
    consumer: {
        public: process.env.TWITTER_CONSUMER_PUBLIC,
        secret: process.env.TWITTER_CONSUMER_SECRET
    },
    token: {
        public: process.env.TWITTER_TOKEN_PUBLIC,
        secret: process.env.TWITTER_SECRET_SECRET
    }
});

var userstream = twitter.stream('https://userstream.twitter.com/1.1/user.json');

userstream.on('data', function(data) {
    // console.log('data');
    // console.log(data);
});

userstream.on('json', function(json) {
    console.log('json');
    console.log(json);
});

userstream.on('end', function() {
    console.log('end');
});

userstream.on('error', function(error) {
    console.log('error');
    console.log(error);
});<|endoftext|>


<commit_before>const React = require('react')
const e = React.createElement
const Component = React.Component
const bindActionCreators = require('redux').bindActionCreators
const connect = require('react-redux').connect
const LoadingActions = require('../actions/loading')
const nodegit = require('../utils/nodegit').nodegit
const hashHistory = require('react-router').hashHistory

const LIMIT = 250

class History extends Component {

	constructor(props) {
		super(props)

		this.state = {
			tree: [],
		}
	}

	componentDidMount() {
		this.refresh()
	}

	refresh() {
		this.props.actions.loading.IncrementLoadingJobs()
		const tree = []
		let commitsPool = []
		let nextIsRemote = false
		let nextIsLocal = false

		const processPool = () => {
			if (commitsPool.length === 0 || tree.length === LIMIT) { // @TODO: note to user that limit was reached
				return
			}
			let nextCommit = commitsPool.reduce((accumulator, current) => {
				if (accumulator.commit.timeMs() < current.commit.timeMs()) {
					return current
				}
				return accumulator
			})
			commitsPool = commitsPool.filter((commit) => {
				if (commit.commit.sha() === nextCommit.commit.sha()) {
					if (commit.branch === 'remote') {
						nextIsRemote = true
					} else if (commit.branch === 'local') {
						nextIsLocal = true
					}
					return false
				} else {
					return true
				}
			})
			if (nextIsRemote && nextIsLocal) {
				nextCommit.branch = 'common'
			}
			return nextCommit.commit.getParents()
				.then((parents) => {
					tree.push({
						branch: nextCommit.branch,
						message: nextCommit.commit.message(),
						sha: nextCommit.commit.sha(),
						isMergeCommit: parents.length > 1,
					})
					commitsPool = commitsPool.concat(parents.map((commit) => {
						return {
							commit,
							branch: nextCommit.branch,
						}
					}))
					return processPool()
				})
		}

		let repo
		const getTopCommit = (reference, branch) => {
			return repo.getBranchCommit(reference)
				.then((commit) => commitsPool.push({
					commit,
					branch,
				}))
				.then(() => reference)
		}

		nodegit.Repository.open(this.props.projects.active.path)
			.then((r) => {
				repo = r
				return repo.getCurrentBranch()
			})
			.then((reference) => getTopCommit(reference, 'local'))
			.then(nodegit.Branch.upstream)
			.then((reference) => getTopCommit(reference, 'remote'))
			.then(() => processPool())
			.then(() => {
				this.setState(Object.assign({}, this.state, {
					tree,
				}))
			})
			.catch((error) => {
				console.error(error)
			})
			.then(() => {
				this.props.actions.loading.DecrementLoadingJobs()
			})
	}

	renderTree() {
		let lineRemote = false
		let lineLocal = false

		return (
			e(
				'div',
				{
					className: 'history-tree',
				},
				e(
					'div',
					{
						className: 'history-titles',
					},
					e(
						'h2',
						{
							className: 'history-title',
						},
						'Změny na serveru'
					),
					e(
						'h2',
						{
							className: 'history-title',
						},
						'Vaše nezazálohované změny'
					)
				),
				this.state.tree.map((node, i) => {
					const lineClasses = ['history-line']
					if (node.branch === 'common') {
						lineClasses.push('history-line-common')
					} else {
						if (node.branch === 'local') {
							lineLocal = true
						} else if (node.branch === 'remote') {
							lineRemote = true
						}
						if (lineRemote) {
							lineClasses.push('history-line-remote')
						}
						if (lineLocal) {
							lineClasses.push('history-line-local')
							if (this.state.tree[i+1] && this.state.tree[i+1].branch === 'common') {
								lineClasses.push('history-line-merge')
							}
						}
					}
					if (i === this.state.tree.length-1) {
						lineClasses.push('history-line-last')
					}
					const nodeClasses = ['history-node', `history-node-${node.branch}`]
					if (node.isMergeCommit) {
						nodeClasses.push('history-node-mergeCommit')
					}
					const message = node.message.split('\n')
					return e(
						'div',
						{
							key: i,
							className: nodeClasses.join(' '),
						},
						e(
							'div',
							{
								className: lineClasses.join(' '),
							},
							e(
								'span',
								{
									className: 'history-line-in',
								}
							)
						),
						e(
							'button',
							{
								className: 'history-node-in',
								onClick: () => {
									hashHistory.push(`/commitDetail/${node.sha}`)
								},
							},
							message[0] + (message.length > 1 ? '…' : '')
						)
					)
				})
			)
		)
	}

	render() {
		return (
			e(
				'div',
				null,
				e('h1', null, 'Historie'),
				this.renderTree()
			)
		)
	}

}

function mapStateToProps(state) {
	return {
		loading: state.loading,
		projects: state.projects,
	}
}

function mapDispatchToProps(dispatch) {
	return {
		actions: {
			loading: bindActionCreators(LoadingActions, dispatch),
		}
	}
}

module.exports = connect(mapStateToProps, mapDispatchToProps)(History)
<commit_msg>History: always processPool<commit_after>const React = require('react')
const e = React.createElement
const Component = React.Component
const bindActionCreators = require('redux').bindActionCreators
const connect = require('react-redux').connect
const LoadingActions = require('../actions/loading')
const nodegit = require('../utils/nodegit').nodegit
const hashHistory = require('react-router').hashHistory

const LIMIT = 250

class History extends Component {

	constructor(props) {
		super(props)

		this.state = {
			tree: [],
		}
	}

	componentDidMount() {
		this.refresh()
	}

	refresh() {
		this.props.actions.loading.IncrementLoadingJobs()
		const tree = []
		let commitsPool = []
		let nextIsRemote = false
		let nextIsLocal = false

		const processPool = () => {
			if (commitsPool.length === 0 || tree.length === LIMIT) { // @TODO: note to user that limit was reached
				return
			}
			let nextCommit = commitsPool.reduce((accumulator, current) => {
				if (accumulator.commit.timeMs() < current.commit.timeMs()) {
					return current
				}
				return accumulator
			})
			commitsPool = commitsPool.filter((commit) => {
				if (commit.commit.sha() === nextCommit.commit.sha()) {
					if (commit.branch === 'remote') {
						nextIsRemote = true
					} else if (commit.branch === 'local') {
						nextIsLocal = true
					}
					return false
				} else {
					return true
				}
			})
			if (nextIsRemote && nextIsLocal) {
				nextCommit.branch = 'common'
			}
			return nextCommit.commit.getParents()
				.then((parents) => {
					tree.push({
						branch: nextCommit.branch,
						message: nextCommit.commit.message(),
						sha: nextCommit.commit.sha(),
						isMergeCommit: parents.length > 1,
					})
					commitsPool = commitsPool.concat(parents.map((commit) => {
						return {
							commit,
							branch: nextCommit.branch,
						}
					}))
					return processPool()
				})
		}

		let repo
		const getTopCommit = (reference, branch) => {
			return repo.getBranchCommit(reference)
				.then((commit) => commitsPool.push({
					commit,
					branch,
				}))
				.then(() => reference)
		}

		nodegit.Repository.open(this.props.projects.active.path)
			.then((r) => {
				repo = r
				return repo.getCurrentBranch()
			})
			.then((reference) => getTopCommit(reference, 'local'))
			.then((branch) => nodegit.Branch.upstream(branch))
			.then((reference) => getTopCommit(reference, 'remote'))
			.catch((error) => {
				console.error(error)
			})
			.then(() => processPool())
			.then(() => {
				this.setState(Object.assign({}, this.state, {
					tree,
				}))
			})
			.catch((error) => {
				console.error(error)
			})
			.then(() => {
				this.props.actions.loading.DecrementLoadingJobs()
			})
	}

	renderTree() {
		let lineRemote = false
		let lineLocal = false

		return (
			e(
				'div',
				{
					className: 'history-tree',
				},
				e(
					'div',
					{
						className: 'history-titles',
					},
					e(
						'h2',
						{
							className: 'history-title',
						},
						'Změny na serveru'
					),
					e(
						'h2',
						{
							className: 'history-title',
						},
						'Vaše nezazálohované změny'
					)
				),
				this.state.tree.map((node, i) => {
					const lineClasses = ['history-line']
					if (node.branch === 'common') {
						lineClasses.push('history-line-common')
					} else {
						if (node.branch === 'local') {
							lineLocal = true
						} else if (node.branch === 'remote') {
							lineRemote = true
						}
						if (lineRemote) {
							lineClasses.push('history-line-remote')
						}
						if (lineLocal) {
							lineClasses.push('history-line-local')
							if (this.state.tree[i+1] && this.state.tree[i+1].branch === 'common') {
								lineClasses.push('history-line-merge')
							}
						}
					}
					if (i === this.state.tree.length-1) {
						lineClasses.push('history-line-last')
					}
					const nodeClasses = ['history-node', `history-node-${node.branch}`]
					if (node.isMergeCommit) {
						nodeClasses.push('history-node-mergeCommit')
					}
					const message = node.message.split('\n')
					return e(
						'div',
						{
							key: i,
							className: nodeClasses.join(' '),
						},
						e(
							'div',
							{
								className: lineClasses.join(' '),
							},
							e(
								'span',
								{
									className: 'history-line-in',
								}
							)
						),
						e(
							'button',
							{
								className: 'history-node-in',
								onClick: () => {
									hashHistory.push(`/commitDetail/${node.sha}`)
								},
							},
							message[0] + (message.length > 1 ? '…' : '')
						)
					)
				})
			)
		)
	}

	render() {
		return (
			e(
				'div',
				null,
				e('h1', null, 'Historie'),
				this.renderTree()
			)
		)
	}

}

function mapStateToProps(state) {
	return {
		loading: state.loading,
		projects: state.projects,
	}
}

function mapDispatchToProps(dispatch) {
	return {
		actions: {
			loading: bindActionCreators(LoadingActions, dispatch),
		}
	}
}

module.exports = connect(mapStateToProps, mapDispatchToProps)(History)
<|endoftext|>


<commit_before>// Load in dependencies and library
var fs = require('fs');
var expect = require('chai').expect;
var extend = require('obj-extend');
var fixtureUtils = require('mocha-fixture-dir')(require('fixture-dir'));
var Store = require('../');

// Set up our /tmp namespace
fixtureUtils.init('fs-memory-store-tests');

// Define helper utilities for interacting with our store
var storeUtils = {
  init: function (options) {
    before(function createStore () {
      // By default, use the temporary `fixtureUtils` directory
      var params = extend({dir: this.dir.path}, options);
      this.store = new Store(params);
    });
    after(function cleanupStore () {
      delete this.store;
    });
  },
  get: function (key) {
    before(function getValue (done) {
      var that = this;
      this.store.get(key, function handleGet (err, val) {
        that.err = err;
        that.val = val;
        done();
      });
    });
    after(function cleanupValues () {
      delete this.err;
      delete this.val;
    });
  },
  set: function (key, val) {
    before(function setValue (done) {
      var that = this;
      this.store.set(key, val, function handleSet (err) {
        that.err = err;
        done();
      });
    });
    after(function cleanupError () {
      delete this.err;
    });
  }
};

// Start our tests
describe('An `fs-memory-store`', function () {
  describe('loading a non-existent value (from memory and disk)', function () {
    fixtureUtils.mkdir({folderName: 'non-existent'});
    storeUtils.init();
    storeUtils.get('nothing');

    it('calls back with `null`', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.equal(null);
    });
  });

  describe('loading an existent value from disk', function () {
    fixtureUtils.mkdir({
      folderName: 'existent',
      copyFrom: __dirname + '/test-files/existent'
    });
    storeUtils.init();
    storeUtils.get('hello');

    it('retrieves the value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({world: true});
    });
  });

  describe('saving a value', function () {
    fixtureUtils.mkdir({
      folderName: 'save'
    });
    storeUtils.init();
    storeUtils.set('hello', {moon: true});

    it('does not have any errors', function () {
      expect(this.err).to.equal(null);
    });

    it('writes the file to disk', function () {
      var files = fs.readdirSync(this.dir.path);
      expect(files).to.deep.equal(['hello.json']);
    });

    describe('loading the value from memory', function () {
      storeUtils.get('hello');

      it('loads its value', function () {
        expect(this.err).to.equal(null);
        expect(this.val).to.deep.equal({moon: true});
      });
    });
  });
});

// DEV: Previously, we tested loading from memory, now it is from disk
describe('A non-existent value from disk', function () {
  fixtureUtils.mkdir({
    folderName: 'non-existent-disk'
  });

  describe('when written', function () {
    storeUtils.init();
    storeUtils.set('hello', {sun: true});

    describe('and loaded from disk', function () {
      before(function (done) {
        var store = new Store({dir: this.dir.path});
        var that = this;
        store.get('hello', function (err, val) {
          that.val = val;
          done(err);
        });
      });

      it('loads its value', function () {
        expect(this.val).to.deep.equal({sun: true});
      });
    });
  });
});
describe('An existent value on disk', function () {
  fixtureUtils.mkdir({
    folderName: 'existent-disk',
    copyFrom: __dirname + '/test-files/existent'
  });

  describe('when overwritten', function () {
    storeUtils.init();
    storeUtils.set('hello', {stars: true});

    describe('and loaded again', function () {
      before(function (done) {
        var store = new Store({dir: this.dir.path});
        var that = this;
        store.get('hello', function (err, val) {
          that.val = val;
          done(err);
        });
      });

      it('loads its value', function () {
        expect(this.val).to.deep.equal({stars: true});
      });
    });
  });
});

// DEV: Assert that we do not have any contamination from either side to our in-memory cache
describe('A deep object saved to memory', function () {
  fixtureUtils.mkdir({
    folderName: 'deep-object-memory'
  });
  storeUtils.init();
  before(function (done) {
    this.obj = {headers: {host: '1234'}};
    this.store.set('hello', this.obj, done);
  });

  describe.skip('when the source value is modified', function () {
    before(function () {
      this.obj.headers.hai = true;
    });
    storeUtils.get('hello');

    it('does not effect the cached value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({headers: {host: '1234'}});
    });
  });

  describe('when a cache-get value is modified', function () {
    storeUtils.get('hello');
    before(function () {
      this.val.headers.hai = true;
    });
    storeUtils.get('hello');

    it('does not effect the cached value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({headers: {host: '1234'}});
    });
  });
});

describe.skip('A deep object loaded from disk', function () {
  fixtureUtils.mkdir({
    folderName: 'deep-object-disk'
  });
  storeUtils.init();

  describe('when a cache-get value is modified', function () {
    it('does not effect the cached value', function () {

    });
  });
});

<commit_msg>Completed test for from-disk modification<commit_after>// Load in dependencies and library
var fs = require('fs');
var expect = require('chai').expect;
var extend = require('obj-extend');
var fixtureUtils = require('mocha-fixture-dir')(require('fixture-dir'));
var Store = require('../');

// Set up our /tmp namespace
fixtureUtils.init('fs-memory-store-tests');

// Define helper utilities for interacting with our store
var storeUtils = {
  init: function (options) {
    before(function createStore () {
      // By default, use the temporary `fixtureUtils` directory
      var params = extend({dir: this.dir.path}, options);
      this.store = new Store(params);
    });
    after(function cleanupStore () {
      delete this.store;
    });
  },
  get: function (key) {
    before(function getValue (done) {
      var that = this;
      this.store.get(key, function handleGet (err, val) {
        that.err = err;
        that.val = val;
        done();
      });
    });
    after(function cleanupValues () {
      delete this.err;
      delete this.val;
    });
  },
  set: function (key, val) {
    before(function setValue (done) {
      var that = this;
      this.store.set(key, val, function handleSet (err) {
        that.err = err;
        done();
      });
    });
    after(function cleanupError () {
      delete this.err;
    });
  }
};

// Start our tests
describe('An `fs-memory-store`', function () {
  describe('loading a non-existent value (from memory and disk)', function () {
    fixtureUtils.mkdir({folderName: 'non-existent'});
    storeUtils.init();
    storeUtils.get('nothing');

    it('calls back with `null`', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.equal(null);
    });
  });

  describe('loading an existent value from disk', function () {
    fixtureUtils.mkdir({
      folderName: 'existent',
      copyFrom: __dirname + '/test-files/existent'
    });
    storeUtils.init();
    storeUtils.get('hello');

    it('retrieves the value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({world: true});
    });
  });

  describe('saving a value', function () {
    fixtureUtils.mkdir({
      folderName: 'save'
    });
    storeUtils.init();
    storeUtils.set('hello', {moon: true});

    it('does not have any errors', function () {
      expect(this.err).to.equal(null);
    });

    it('writes the file to disk', function () {
      var files = fs.readdirSync(this.dir.path);
      expect(files).to.deep.equal(['hello.json']);
    });

    describe('loading the value from memory', function () {
      storeUtils.get('hello');

      it('loads its value', function () {
        expect(this.err).to.equal(null);
        expect(this.val).to.deep.equal({moon: true});
      });
    });
  });
});

// DEV: Previously, we tested loading from memory, now it is from disk
describe('A non-existent value from disk', function () {
  fixtureUtils.mkdir({
    folderName: 'non-existent-disk'
  });

  describe('when written', function () {
    storeUtils.init();
    storeUtils.set('hello', {sun: true});

    describe('and loaded from disk', function () {
      before(function (done) {
        var store = new Store({dir: this.dir.path});
        var that = this;
        store.get('hello', function (err, val) {
          that.val = val;
          done(err);
        });
      });

      it('loads its value', function () {
        expect(this.val).to.deep.equal({sun: true});
      });
    });
  });
});
describe('An existent value on disk', function () {
  fixtureUtils.mkdir({
    folderName: 'existent-disk',
    copyFrom: __dirname + '/test-files/existent'
  });

  describe('when overwritten', function () {
    storeUtils.init();
    storeUtils.set('hello', {stars: true});

    describe('and loaded again', function () {
      before(function (done) {
        var store = new Store({dir: this.dir.path});
        var that = this;
        store.get('hello', function (err, val) {
          that.val = val;
          done(err);
        });
      });

      it('loads its value', function () {
        expect(this.val).to.deep.equal({stars: true});
      });
    });
  });
});

// DEV: Assert that we do not have any contamination from either side to our in-memory cache
describe('A deep object saved to memory', function () {
  fixtureUtils.mkdir({
    folderName: 'deep-object-memory'
  });
  storeUtils.init();
  before(function (done) {
    this.obj = {headers: {host: '1234'}};
    this.store.set('hello', this.obj, done);
  });

  describe.skip('when the source value is modified', function () {
    before(function () {
      this.obj.headers.hai = true;
    });
    storeUtils.get('hello');

    it('does not effect the cached value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({headers: {host: '1234'}});
    });
  });

  describe('when a cache-get value is modified', function () {
    storeUtils.get('hello');
    before(function () {
      this.val.headers.hai = true;
    });
    storeUtils.get('hello');

    it('does not effect the cached value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({headers: {host: '1234'}});
    });
  });
});

describe('A deep object loaded from disk', function () {
  fixtureUtils.mkdir({
    folderName: 'deep-object-disk',
    copyFrom: __dirname + '/test-files/deep-object-disk'
  });
  storeUtils.init();

  describe('when a cache-get value is modified', function () {
    storeUtils.get('hello');
    before(function () {
      this.val.nested.hai = true;
    });
    storeUtils.get('hello');

    it('does not effect the cached value', function () {
      expect(this.err).to.equal(null);
      expect(this.val).to.deep.equal({nested: {data: true}});
    });
  });
});

<|endoftext|>


<commit_before>/**
 * enyo.Spotlight.Decorator.Container kind definition
 * @author: Lex Podgorny
 */

enyo.kind({
	name: 'enyo.Spotlight.Decorator.Container',

	statics: {
		decorates: null,

		// Creates oSender._spotlight object
		_initComponent: function(oSender) {
			var oLastFocusedChild;
			if (!this._isInitialized(oSender)) {
				if (oSender.defaultSpotlightControl) {
					if (oSender.$[oSender.defaultSpotlightControl]) {
						oLastFocusedChild = oSender.$[oSender.defaultSpotlightControl];
					} else if (oSender.owner.$[oSender.defaultSpotlightControl]) {
						oLastFocusedChild = oSender.owner.$[oSender.defaultSpotlightControl];
					} else {
						throw 'Invalid default spotlight control specified in ' + oSender.name;
					}
				} else {
					oLastFocusedChild = enyo.Spotlight.getFirstChild(oSender);
				}

				if (oLastFocusedChild && oLastFocusedChild.isDescendantOf(oSender)) {
					this.setLastFocusedChild(oSender, oLastFocusedChild);
				}
				enyo.Spotlight.Util.interceptEvents(oSender, this._handleEvent);
			}
		},

		_isInitialized: function(oSender) {
			return typeof oSender._spotlight.lastFocusedChild != 'undefined';
		},

		// Handle events bubbling from within the container
		_handleEvent: function(oSender, oEvent) {
			switch (oEvent.type) {
				case 'onSpotlightFocus':
					if (oEvent.originator !== oSender) {
						enyo.Spotlight.Decorator.Container.setLastFocusedChild(oSender, oEvent.originator);
					}
					break;
				case 'onSpotlightKeyDown':
					// Inform other controls that spotlight 5-way event was generated within a container
					oEvent.spotSentFromContainer = true;
					break;
			}
		},

		// Was last spotted control the container's child?
		_hadFocus: function(oSender) {
			var oLastControl = enyo.Spotlight.getLastControl();
			if (oSender._spotlight.bEnorceOutsideIn)       { return false; } // Programmatically spotted containers are always treated as not having focus
			if (!enyo.Spotlight.isSpottable(oLastControl)) { return false; } // Because oLastControl might have been DHD'd
			return enyo.Spotlight.Util.isChild(oSender, oLastControl);
		},

		_focusLeave: function(oSender, s5WayEventType) {
			// console.log('FOCUS LEAVE', oSender.name);
			var sDirection = s5WayEventType.replace('onSpotlight','').toUpperCase();
			enyo.Spotlight.Util.dispatchEvent('onSpotlightContainerLeave', {direction: sDirection}, oSender);
		},

		_focusEnter: function(oSender, s5WayEventType) {
			// console.log('FOCUS ENTER', oSender.name);
			var sDirection = s5WayEventType.replace('onSpotlight','').toUpperCase();
			enyo.Spotlight.Util.dispatchEvent('onSpotlightContainerEnter', {direction: sDirection}, oSender);
		},

		/******************************/
		onSpotlightFocus: function(oSender, oEvent) {
			oSender._spotlight = oSender._spotlight || {};
			oSender._spotlight.bEnorceOutsideIn = !oEvent.dir;
		},
		onSpotlightFocused: function(oSender, oEvent) {
			// console.log('FOCUSED', oSender.name);
			if (enyo.Spotlight.isInitialized() && enyo.Spotlight.getPointerMode()) { return true; }
			this._initComponent(oSender);

			var s5WayEventType = enyo.Spotlight.getLast5WayEvent() ? enyo.Spotlight.getLast5WayEvent().type : '';

			if (this._hadFocus(oSender)) {   // Focus came from inside AND this was a 5-way move
				// console.log('FROM INSIDE', s5WayEventType);
				if (s5WayEventType) {
					enyo.Spotlight.Util.dispatchEvent(s5WayEventType, {spotSentFromContainer:true}, oSender);
				}
				this._focusLeave(oSender, s5WayEventType);
			} else {                            // Focus came from outside or this was a programmic spot
				var oLastFocusedChild = this.getLastFocusedChild(oSender);
				if (oLastFocusedChild) {
					enyo.Spotlight.spot(oLastFocusedChild);
				} else {
					if (s5WayEventType) {
						enyo.Spotlight.Util.dispatchEvent(s5WayEventType, {spotSentFromContainer:true}, oSender);
						return true;
					}
				}
				this._focusEnter(oSender, s5WayEventType);
			}

			return true;
		},

		// What child of container was last focused?
		getLastFocusedChild: function(oSender) {
			oSender._spotlight = oSender._spotlight || {};
			if (!oSender._spotlight.lastFocusedChild || !enyo.Spotlight.isSpottable(oSender._spotlight.lastFocusedChild)) {
				oSender._spotlight.lastFocusedChild = enyo.Spotlight.getChildren(oSender)[0];
			}
			return oSender._spotlight.lastFocusedChild;
		},

		// Set last focused child
		setLastFocusedChild: function(oSender, oChild) {
			if (!enyo.Spotlight.isSpottable(oChild)) {
				enyo.warn('Spotlight Container' + oSender.name + ' has not spottable lastFocusedChild ' + oChild.name);
			}
			oSender._spotlight = oSender._spotlight || {};
			oSender._spotlight.lastFocusedChild = oChild;
		}
	}
});<commit_msg>GF-58554 Accordion remember last focused item.<commit_after>/**
 * enyo.Spotlight.Decorator.Container kind definition
 * @author: Lex Podgorny
 */

enyo.kind({
	name: 'enyo.Spotlight.Decorator.Container',

	statics: {
		decorates: null,

		// Creates oSender._spotlight object
		_initComponent: function(oSender) {
			var oLastFocusedChild;
			if (!this._isInitialized(oSender)) {
				if (oSender.defaultSpotlightControl) {
					if (oSender.$[oSender.defaultSpotlightControl]) {
						oLastFocusedChild = oSender.$[oSender.defaultSpotlightControl];
					} else if (oSender.owner.$[oSender.defaultSpotlightControl]) {
						oLastFocusedChild = oSender.owner.$[oSender.defaultSpotlightControl];
					} else {
						throw 'Invalid default spotlight control specified in ' + oSender.name;
					}
				} else {
					oLastFocusedChild = enyo.Spotlight.getFirstChild(oSender);
				}

				if (oLastFocusedChild && oLastFocusedChild.isDescendantOf(oSender)) {
					this.setLastFocusedChild(oSender, oLastFocusedChild);
				}
				enyo.Spotlight.Util.interceptEvents(oSender, this._handleEvent);
			}
		},

		_isInitialized: function(oSender) {
			return typeof oSender._spotlight.lastFocusedChild != 'undefined';
		},

		// Handle events bubbling from within the container
		_handleEvent: function(oSender, oEvent) {
			switch (oEvent.type) {
				case 'onSpotlightFocus':
					if (oEvent.originator !== oSender) {
						enyo.Spotlight.Decorator.Container.setLastFocusedChild(oSender, oEvent.originator);
					}
					break;
				case 'onSpotlightKeyDown':
					// Inform other controls that spotlight 5-way event was generated within a container
					oEvent.spotSentFromContainer = true;
					break;
			}
		},

		// Was last spotted control the container's child?
		_hadFocus: function(oSender) {
			var oLastControl = enyo.Spotlight.getLastControl();
			if (oSender._spotlight.bEnorceOutsideIn)       { return false; } // Programmatically spotted containers are always treated as not having focus
			if (!enyo.Spotlight.isSpottable(oLastControl)) { return false; } // Because oLastControl might have been DHD'd
			return enyo.Spotlight.Util.isChild(oSender, oLastControl);
		},

		_focusLeave: function(oSender, s5WayEventType) {
			// console.log('FOCUS LEAVE', oSender.name);
			var sDirection = s5WayEventType.replace('onSpotlight','').toUpperCase();
			enyo.Spotlight.Util.dispatchEvent('onSpotlightContainerLeave', {direction: sDirection}, oSender);
		},

		_focusEnter: function(oSender, s5WayEventType) {
			// console.log('FOCUS ENTER', oSender.name);
			var sDirection = s5WayEventType.replace('onSpotlight','').toUpperCase();
			enyo.Spotlight.Util.dispatchEvent('onSpotlightContainerEnter', {direction: sDirection}, oSender);
		},

		/******************************/
		onSpotlightFocus: function(oSender, oEvent) {
			oSender._spotlight = oSender._spotlight || {};
			oSender._spotlight.bEnorceOutsideIn = !oEvent.dir;
		},
		onSpotlightFocused: function(oSender, oEvent) {
			// console.log('FOCUSED', oSender.name);
			if (enyo.Spotlight.isInitialized() && enyo.Spotlight.getPointerMode()) { return true; }
			this._initComponent(oSender);

			var s5WayEventType = enyo.Spotlight.getLast5WayEvent() ? enyo.Spotlight.getLast5WayEvent().type : '';

			if (this._hadFocus(oSender)) {   // Focus came from inside AND this was a 5-way move
				// console.log('FROM INSIDE', s5WayEventType);
				if (s5WayEventType) {
					enyo.Spotlight.Util.dispatchEvent(s5WayEventType, {spotSentFromContainer:true}, oSender);
				}
				this._focusLeave(oSender, s5WayEventType);
			} else {                            // Focus came from outside or this was a programmic spot
				var oLastFocusedChild = this.getLastFocusedChild(oSender);
				if (oLastFocusedChild) {
					enyo.Spotlight.spot(oLastFocusedChild);
				} else {
					if (s5WayEventType) {
						enyo.Spotlight.Util.dispatchEvent(s5WayEventType, {spotSentFromContainer:true}, oSender);
						return true;
					}
				}
				this._focusEnter(oSender, s5WayEventType);
			}

			return true;
		},

		// What child of container was last focused?
		getLastFocusedChild: function(oSender) {
			oSender._spotlight = oSender._spotlight || {};
			if (!oSender._spotlight.lastFocusedChild || !enyo.Spotlight.isSpottable(oSender._spotlight.lastFocusedChild)) {
				oSender._spotlight.lastFocusedChild = enyo.Spotlight.getChildren(oSender)[0];
			}
			return oSender._spotlight.lastFocusedChild;
		},

		// Set last focused child
		setLastFocusedChild: function(oSender, oChild) {
			if (!enyo.Spotlight.isSpottable(oChild)) {
				oChild = this.getFirstChild(oChild);
			}
			if (oChild) {
				oSender._spotlight = oSender._spotlight || {};
				oSender._spotlight.lastFocusedChild = oChild;
			} else {
				enyo.warn('Spotlight Container' + oSender.name + ' has not spottable lastFocusedChild ' + oChild.name);
			}
		}
	}
});<|endoftext|>


<commit_before>var w = 70;
var h = 25;
var display = new ROT.Display({spacing:1.4, width: w, height: h});
var map ={};
var actors = {};
var mousedown = false;

function init(){
  var gameArea = document.getElementById("GameArea");
  gameArea.appendChild(display.getContainer());
  initMap(map);

  gameArea.addEventListener("mousedown",function(e){
    mousedown = true;
    mouseUsed(display.eventToPosition(e));
  });
  gameArea.addEventListener("mouseup",function(){
    mousedown = false;
  });

  gameArea.addEventListener("mousemove",function (e){
    if(mousedown){
      mouseUsed(display.eventToPosition(e));
    }
  });
}

function mouseUsed(clickCoOrd){
  var mouseType = document.getElementById("tileType").Tile.value;
  if(mouseType !== 'selector'){
    map[clickCoOrd[0]+","+clickCoOrd[1]] = mouseType;
    display.draw(clickCoOrd[0],clickCoOrd[1],mouseType);
  }

  document.getElementById('SelectedCoOrd').innerHTML = "Selected: "+ clickCoOrd[0] + "," + clickCoOrd[1];
}

function initMap(map){
  for(r = 0; r < w; r++){
    for(b = 0; b < h; b++){
      map[r+","+b] = '.';
      display.draw(r,b,'.');
    }
  }
}
function createThing(){
  var name = document.forms[1].elements[0].value;
  var color = document.forms[1].elements[1].value;
  var rune = document.forms[1].elements[2].value;
  var xCoOrd = parseInt(document.forms[1].elements[3].value);
  var yCoOrd = parseInt(document.forms[1].elements[4].value);

  if(actors[name] !== undefined){
    alert("Something is already named "+name+"!")
  }else{
    actors[name] = {
      color: color,
      rune: rune,
      x: xCoOrd,
      y: yCoOrd
    };
    display.draw(xCoOrd ,yCoOrd,rune,color );
  }
}

function loadMap(mapDnA){
  console.log("loadMap");
  var reader = new FileReader();
  var readFile;

  reader.onload = function(mapDna){
    readFile = JSON.parse(reader.result);

    console.log(typeof readFile);

    map = readFile.map;
    actors = readFile.gameObj;
    for(r = 0; r < w; r++){
      for(b = 0; b < h; b++){
        display.draw(r,b,map[r+","+b]);
      }
    }
    for(var name in actors){
      display.draw(actors[name].x,actors[name].y,actors[name].rune,actors[name].color);
    }
  };
  reader.readAsBinaryString(mapDnA);

}

function updateDataRealQuickLike(linkOnTheDL){
  linkOnTheDL.href="data:application/json,"+JSON.stringify({map: map, gameObj: actors});
  linkOnTheDL.download=document.getElementById("filename").value+".json";
}
<commit_msg>Can now delete game objects.<commit_after>var w = 70;
var h = 25;
var display = new ROT.Display({spacing:1.4, width: w, height: h});
var map ={};
var actors = {};
var mousedown = false;
var selected;

function init(){
  var gameArea = document.getElementById("GameArea");
  gameArea.appendChild(display.getContainer());
  initMap(map);

  gameArea.addEventListener("mousedown",function(e){
    mousedown = true;
    mouseUsed(display.eventToPosition(e));
  });
  gameArea.addEventListener("mouseup",function(){
    mousedown = false;
  });

  gameArea.addEventListener("mousemove",function (e){
    if(mousedown){
      mouseUsed(display.eventToPosition(e));
    }
  });
}

function mouseUsed(clickCoOrd){
  var mouseType = document.getElementById("tileType").Tile.value;
  if(mouseType !== 'selector'){
    map[clickCoOrd[0]+","+clickCoOrd[1]] = mouseType;
    display.draw(clickCoOrd[0],clickCoOrd[1],mouseType);
  }
  var found = false;

  for(var dude in actors){
      if(actors[dude].x === clickCoOrd[0] && actors[dude].y === clickCoOrd[1]){
          document.getElementById('SelectedCoOrd').innerHTML = "Selected: "+dude +" Delete?";
          selected = dude;
          found = true;
      };
  };
  if(!found){
    document.getElementById('SelectedCoOrd').innerHTML = "Selected: "+ clickCoOrd[0] + "," + clickCoOrd[1];
    selected = null;
  }
}
function smite(object){
  display.draw(actors[object].x,actors[object].y,'.');
  delete actors[object];
}
function initMap(map){
  for(r = 0; r < w; r++){
    for(b = 0; b < h; b++){
      map[r+","+b] = '.';
      display.draw(r,b,'.');
    }
  }
}
function createThing(){
  var name = document.forms[1].elements[0].value;
  var color = document.forms[1].elements[1].value;
  var rune = document.forms[1].elements[2].value;
  var xCoOrd = parseInt(document.forms[1].elements[3].value);
  var yCoOrd = parseInt(document.forms[1].elements[4].value);

  if(actors[name] !== undefined){
    alert("Something is already named "+name+"!")
  }else{
    actors[name] = {
      color: color,
      rune: rune,
      x: xCoOrd,
      y: yCoOrd
    };
    display.draw(xCoOrd ,yCoOrd,rune,color );
  }
}

function loadMap(mapDnA){
  console.log("loadMap");
  var reader = new FileReader();
  var readFile;

  reader.onload = function(mapDna){
    readFile = JSON.parse(reader.result);

    console.log(typeof readFile);

    map = readFile.map;
    actors = readFile.gameObj;
    for(r = 0; r < w; r++){
      for(b = 0; b < h; b++){
        display.draw(r,b,map[r+","+b]);
      }
    }
    for(var name in actors){
      display.draw(actors[name].x,actors[name].y,actors[name].rune,actors[name].color);
    }
  };
  reader.readAsBinaryString(mapDnA);

}

function updateDataRealQuickLike(linkOnTheDL){
  linkOnTheDL.href="data:application/json,"+JSON.stringify({map: map, gameObj: actors});
  linkOnTheDL.download=document.getElementById("filename").value+".json";
}
<|endoftext|>