<commit_before>var _ = require('underscore');
var InfoBox = require('./infobox');
var sanitize = require('../../core/sanitize');
var InfowindowModel = require('./infowindow-model');

var TooltipView = InfoBox.extend({
  defaultTemplate: '
{{text}}
',
  className: 'CDB-Tooltip-wrapper',

  defaults: {
    vertical_offset: 0,
    horizontal_offset: 0,
    position: 'top|center'
  },

  initialize: function () {
    if (!this.options.mapView) {
      throw new Error('mapView should be present');
    }
    this.options.template = this.options.template || this.defaultTemplate;
    InfoBox.prototype.initialize.call(this);
    this._filter = null;
    this.showing = false;
    this.showhideTimeout = null;
  },

  render: function (data) {
    var sanitizedOutput = sanitize.html(this.template(data));
    this.$el.html(sanitizedOutput);
    return this;
  },

  /**
   * sets a filter to open the tooltip. If the feature being hovered
   * pass the filter the tooltip is shown
   * setFilter(null) removes the filter
   */
  setFilter: function (f) {
    this._filter = f;
    return this;
  },

  setFields: function (fields) {
    this.options.fields = fields;
    return this;
  },

  setAlternativeNames: function (n) {
    this.options.alternative_names = n;
  },

  enable: function () {
    if (this.options.layer) {
      // unbind previous events
      this.options.layer.unbind(null, null, this);
      this.options.layer
        .on('mouseover', function (e, latlng, pos, data) {
          if (this.options.fields && this.options.fields.length > 0) {
            var non_valid_keys = ['fields', 'content'];

            if (this.options.omit_columns) {
              non_valid_keys = non_valid_keys.concat(this.options.omit_columns);
            }

            var c = InfowindowModel.contentForFields(data, this.options.fields, {
              show_empty_fields: false
            });

            // Remove fields and content from data
            // and make them visible for custom templates
            data.content = _.omit(data, non_valid_keys);

            // loop through content values
            data.fields = c.fields;

            // alternamte names
            var names = this.options.alternative_names;
            if (names) {
              for (var i = 0; i < data.fields.length; ++i) {
                var f = data.fields[i];
                f.title = names[f.title] || f.title;
              }
            }
            this.show(pos, data);
            this.showing = true;
          } else if (this.showing) {
            this.hide();
            this.showing = false;
          }
        }, this)
        .on('mouseout', function () {
          if (this.showing) {
            this.hide();
            this.showing = false;
          }
        }, this);
      this.add_related_model(this.options.layer);
    }
  },

  disable: function () {
    if (this.options.layer) {
      this.options.layer.unbind(null, null, this);
    }
    this.hide();
    this.showing = false;
  },

  _visibility: function () {
    var self = this;
    clearTimeout(this.showhideTimeout);
    this.showhideTimeout = setTimeout(self._showing ?
      function () { self.$el.fadeIn(100); }
      :
      function () { self.$el.fadeOut(200); }
      , 50);
  },

  hide: function () {
    if (this._showing) {
      this._showing = false;
      this._visibility();
    }
  },

  show: function (pos, data) {
    if (this._filter && !this._filter(data)) {
      return this;
    }
    this.render(data);
    this.setPosition(pos);
    if (!this._showing) {
      this._showing = true;
      this._visibility();
    }
    return this;
  },

  setPosition: function (point) {
    var pos = this.options.position;
    var height = this.$el.innerHeight();
    var width = this.$el.innerWidth();
    var mapViewSize = this.options.mapView.getSize();
    var top = 0;
    var left = 0;
    var modifierClass = 'CDB-Tooltip-wrapper--';

    // Remove tick class
    this._removePositionModifiers();

    // Vertically
    if (pos.indexOf('top') !== -1) {
      top = point.y - height;
    } else if (pos.indexOf('middle') !== -1) {
      top = point.y - (height / 2);
    } else { // bottom
      top = point.y;
    }

    // Fix vertical overflow
    if (top < 0) {
      top = point.y;
      modifierClass += 'top';
    } else if (top + height > mapViewSize.y) {
      top = point.y - height;
      modifierClass += 'bottom';
    } else {
      modifierClass += 'top';
    }

    // Horizontally
    if (pos.indexOf('left') !== -1) {
      left = point.x - width;
    } else if (pos.indexOf('center') !== -1) {
      left = point.x - (width / 2);
    } else { // right
      left = point.x;
    }

    // Fix horizontal overflow
    if (left < 0) {
      left = point.x;
      modifierClass += 'Left';
    } else if (left + width > mapViewSize.x) {
      left = point.x - width;
      modifierClass += 'Right';
    } else {
      modifierClass += 'Left';
    }

    // Add offsets
    top += this.options.vertical_offset;
    left += this.options.horizontal_offset;

    this.$el.css({
      top: top,
      left: left
    }).addClass(modifierClass);
  },

  _removePositionModifiers: function () {
    var positions = [ 'topLeft', 'topRight', 'bottomRight', 'bottomLeft' ];
    var positionModifiers = _.map(positions, function (className) {
      return this._modifierClassName(className);
    }, this);
    this.$el.removeClass(positionModifiers.join(' '));
  },

  _modifierClassName: function (className) {
    return this.className + '--' + className;
  }
});

module.exports = TooltipView;
<commit_msg>Lint errors<commit_after>var _ = require('underscore');
var InfoBox = require('./infobox');
var sanitize = require('../../core/sanitize');
var InfowindowModel = require('./infowindow-model');

var TooltipView = InfoBox.extend({
  defaultTemplate: '
{{text}}
',
  className: 'CDB-Tooltip-wrapper',

  defaults: {
    vertical_offset: 0,
    horizontal_offset: 0,
    position: 'top|center'
  },

  initialize: function () {
    if (!this.options.mapView) {
      throw new Error('mapView should be present');
    }
    this.options.template = this.options.template || this.defaultTemplate;
    InfoBox.prototype.initialize.call(this);
    this._filter = null;
    this.showing = false;
    this.showhideTimeout = null;
  },

  render: function (data) {
    var sanitizedOutput = sanitize.html(this.template(data));
    this.$el.html(sanitizedOutput);
    return this;
  },

  /**
   * sets a filter to open the tooltip. If the feature being hovered
   * pass the filter the tooltip is shown
   * setFilter(null) removes the filter
   */
  setFilter: function (f) {
    this._filter = f;
    return this;
  },

  setFields: function (fields) {
    this.options.fields = fields;
    return this;
  },

  setAlternativeNames: function (n) {
    this.options.alternative_names = n;
  },

  enable: function () {
    if (this.options.layer) {
      // unbind previous events
      this.options.layer.unbind(null, null, this);
      this.options.layer
        .on('mouseover', function (e, latlng, pos, data) {
          if (this.options.fields && this.options.fields.length > 0) {
            var non_valid_keys = ['fields', 'content'];

            if (this.options.omit_columns) {
              non_valid_keys = non_valid_keys.concat(this.options.omit_columns);
            }

            var c = InfowindowModel.contentForFields(data, this.options.fields, {
              show_empty_fields: false
            });

            // Remove fields and content from data
            // and make them visible for custom templates
            data.content = _.omit(data, non_valid_keys);

            // loop through content values
            data.fields = c.fields;

            // alternamte names
            var names = this.options.alternative_names;
            if (names) {
              for (var i = 0; i < data.fields.length; ++i) {
                var f = data.fields[i];
                f.title = names[f.title] || f.title;
              }
            }
            this.show(pos, data);
            this.showing = true;
          } else if (this.showing) {
            this.hide();
            this.showing = false;
          }
        }, this)
        .on('mouseout', function () {
          if (this.showing) {
            this.hide();
            this.showing = false;
          }
        }, this);
      this.add_related_model(this.options.layer);
    }
  },

  disable: function () {
    if (this.options.layer) {
      this.options.layer.unbind(null, null, this);
    }
    this.hide();
    this.showing = false;
  },

  _visibility: function () {
    var self = this;
    clearTimeout(this.showhideTimeout);

    var fadeIn = function () {
      self.$el.fadeIn(100);
    };

    var fadeOut = function () {
      self.$el.fadeOut(200);
    };

    this.showhideTimeout = setTimeout(self._showing ? fadeIn : fadeOut, 50);
  },

  hide: function () {
    if (this._showing) {
      this._showing = false;
      this._visibility();
    }
  },

  show: function (pos, data) {
    if (this._filter && !this._filter(data)) {
      return this;
    }
    this.render(data);
    this.setPosition(pos);
    if (!this._showing) {
      this._showing = true;
      this._visibility();
    }
    return this;
  },

  setPosition: function (point) {
    var pos = this.options.position;
    var height = this.$el.innerHeight();
    var width = this.$el.innerWidth();
    var mapViewSize = this.options.mapView.getSize();
    var top = 0;
    var left = 0;
    var modifierClass = 'CDB-Tooltip-wrapper--';

    // Remove tick class
    this._removePositionModifiers();

    // Vertically
    if (pos.indexOf('top') !== -1) {
      top = point.y - height;
    } else if (pos.indexOf('middle') !== -1) {
      top = point.y - (height / 2);
    } else { // bottom
      top = point.y;
    }

    // Fix vertical overflow
    if (top < 0) {
      top = point.y;
      modifierClass += 'top';
    } else if (top + height > mapViewSize.y) {
      top = point.y - height;
      modifierClass += 'bottom';
    } else {
      modifierClass += 'top';
    }

    // Horizontally
    if (pos.indexOf('left') !== -1) {
      left = point.x - width;
    } else if (pos.indexOf('center') !== -1) {
      left = point.x - (width / 2);
    } else { // right
      left = point.x;
    }

    // Fix horizontal overflow
    if (left < 0) {
      left = point.x;
      modifierClass += 'Left';
    } else if (left + width > mapViewSize.x) {
      left = point.x - width;
      modifierClass += 'Right';
    } else {
      modifierClass += 'Left';
    }

    // Add offsets
    top += this.options.vertical_offset;
    left += this.options.horizontal_offset;

    this.$el.css({
      top: top,
      left: left
    }).addClass(modifierClass);
  },

  _removePositionModifiers: function () {
    var positions = [ 'topLeft', 'topRight', 'bottomRight', 'bottomLeft' ];
    var positionModifiers = _.map(positions, function (className) {
      return this._modifierClassName(className);
    }, this);
    this.$el.removeClass(positionModifiers.join(' '));
  },

  _modifierClassName: function (className) {
    return this.className + '--' + className;
  }
});

module.exports = TooltipView;
<|endoftext|>


<commit_before>var d3 = require('d3');
var debug = require('debug')('transitive:display');
var each = require('each');

var Legend = require('./legend');
var TileLayer = require('./tile-layer');

var SphericalMercator = require('../util/spherical-mercator');
var sm = new SphericalMercator();

/**
 * Expose `Display`
 */

module.exports = Display;

/**
 * The D3-based SVG display.
 *
 * @param {Object} options
 */

function Display(transitive) {
  this.transitive = transitive;
  var el = this.el = transitive.el;
  this.width = el.clientWidth;
  this.height = el.clientHeight;

  // Set up the pan/zoom behavior
  var zoom = this.zoom = d3.behavior.zoom()
    .scaleExtent([0.25, 4]);

  var self = this;

  var zoomBehavior = function() {
    self.computeScale();
    if (self.scale !== self.lastScale) { // zoom action
      self.zoomChanged();
    } else { // pan action
      setTimeout(transitive.refresh.bind(transitive, true), 0);
    }

    var llb = self.llBounds();
    debug('ll bounds: ' + llb[0][0] + ',' + llb[0][1] + ' to ' + llb[1][0] +
      ',' + llb[1][1]);
  };

  this.zoom.on('zoom.transitive', zoomBehavior);

  this.zoomFactors = transitive.options.zoomFactors || this.getDefaultZoomFactors();

  // set up the svg display
  var div = d3.select(el)
    .attr('class', 'Transitive');

  if (transitive.options.zoomEnabled) {
    div.call(zoom);
  }

  this.svg = div
    .append('svg')
    .attr('class', 'schematic-map');

  // initialize the x/y scale objects
  this.xScale = d3.scale.linear();
  this.yScale = d3.scale.linear();

  // set up the resize event handler
  if (transitive.options.autoResize) {
    d3.select(window).on('resize.display', function() {
      self.resized();
      transitive.refresh();
    });
  }

  // set the scale
  var bounds;
  if (transitive.options.initialBounds) {
    bounds = [sm.forward(transitive.options.initialBounds[0]),
      sm.forward(transitive.options.initialBounds[1])
    ];
  } else if (transitive.network && transitive.network.graph) {
    bounds = transitive.network.graph.bounds();
  }

  if (bounds) {
    this.setScale(bounds, transitive.options);
//    this.updateActiveZoomFactors(this.scale);
    this.updateActiveZoomFactors(1);
    this.lastScale = this.scale;
  } else {
    this.updateActiveZoomFactors(1);
  }

  // set up the map layer
  if (transitive.options.mapboxId) {
    this.tileLayer = new TileLayer({
      el: this.el,
      display: this,
      graph: transitive.graph,
      mapboxId: transitive.options.mapboxId
    });
  }

  // set up the legend
  if (transitive.options.legendEl) {
    this.legend = new Legend(transitive.options.legendEl, this, transitive);
  }

  transitive.emit('initialize display', transitive, this);
  return this;
}

/**
 * zoomChanged -- called when the zoom level changes, either by through the native
 * zoom support or the setBounds() API call. Updates zoom factors as needed and
 * performs appropriate update action (render or refresh)
 */

Display.prototype.zoomChanged = function() {
//  if (this.updateActiveZoomFactors(this.scale)) {
  if (this.updateActiveZoomFactors(1)) {
    this.transitive.network = null;
    this.transitive.render();
  } else this.transitive.refresh();
  this.lastScale = this.scale;
};

Display.prototype.updateActiveZoomFactors = function(scale) {
  // Overriding default behavior to always show maximum detail
  // on displayed routes.
  var updated = false;

  this.activeZoomFactors = this.zoomFactors[this.zoomFactors.length - 1];
  return true;
  // Override ends here.

  for (var i = 0; i < this.zoomFactors.length; i++) {
    var min = this.zoomFactors[i].minScale;
    var max = (i < this.zoomFactors.length - 1) ?
      this.zoomFactors[i + 1].minScale : Number.MAX_VALUE;

    // check if we've crossed into a new zoomFactor partition
    if ((!this.lastScale || this.lastScale < min || this.lastScale >= max) &&
      scale >= min && scale < max) {
      this.activeZoomFactors = this.zoomFactors[i];
      updated = true;
    }
  }
  return updated;
};

/**
 * Return default zoom factors
 */

Display.prototype.getDefaultZoomFactors = function(data) {
  return [{
    minScale: 0,
    gridCellSize: 25,
    internalVertexFactor: 1000000,
    angleConstraint: 45,
    mergeVertexThreshold: 200
  }, {
    minScale: 1.5,
    gridCellSize: 0,
    internalVertexFactor: 0,
    angleConstraint: 5,
    mergeVertexThreshold: 0
  }];
};

/**
 * Empty the display
 */

Display.prototype.empty = function() {
  debug('emptying svg');
  this.svg.selectAll('*').remove();

  this.haloLayer = this.svg.insert('g', ':first-child');
};

/**
 * Set the scale
 */

Display.prototype.setScale = function(bounds, options) {

  this.height = this.el.clientHeight;
  this.width = this.el.clientWidth;

  var domains = getDomains(this, this.height, this.width, bounds, options);
  this.xScale.domain(domains[0]);
  this.yScale.domain(domains[1]);

  this.xScale.range([0, this.width]);
  this.yScale.range([this.height, 0]);

  debug('x scale %j -> %j', this.xScale.domain(), this.xScale.range());
  debug('y scale %j -> %j', this.yScale.domain(), this.yScale.range());

  this.zoom
    .x(this.xScale)
    .y(this.yScale);

  this.initXRes = (domains[0][1] - domains[0][0]) / this.width;
  this.scale = 1;

  this.scaleSet = true;
};

Display.prototype.computeScale = function() {
  var newXRes = (this.xScale.domain()[1] - this.xScale.domain()[0]) / this.width;
  this.scale = this.initXRes / newXRes;
};

/**
 * updateDomains -- set x/y domains of geographic (spherical mercator) coordinate
 * system. Does *not* check/adjust aspect ratio.
 */

Display.prototype.updateDomains = function(bounds) {
  this.xScale.domain([bounds[0][0], bounds[1][0]]);
  this.yScale.domain([bounds[0][1], bounds[1][1]]);

  this.zoom
    .x(this.xScale)
    .y(this.yScale);

  this.computeScale();
};

Display.prototype.resized = function() {

  var newWidth = this.el.clientWidth;
  var newHeight = this.el.clientHeight;

  var xDomain = this.xScale.domain();
  var xFactor = newWidth / this.width;
  var xDomainAdj = (xDomain[1] - xDomain[0]) * (xFactor - 1) / 2;
  this.xScale.domain([xDomain[0] - xDomainAdj, xDomain[1] + xDomainAdj]);

  var yDomain = this.yScale.domain();
  var yFactor = newHeight / this.height;
  var yDomainAdj = (yDomain[1] - yDomain[0]) * (yFactor - 1) / 2;
  this.yScale.domain([yDomain[0] - yDomainAdj, yDomain[1] + yDomainAdj]);

  this.xScale.range([0, newWidth]);
  this.yScale.range([newHeight, 0]);

  this.height = newHeight;
  this.width = newWidth;

  this.zoom
    .x(this.xScale)
    .y(this.yScale);
};

Display.prototype.xyBounds = function() {
  var x = this.xScale.domain();
  var y = this.yScale.domain();
  return [
    [x[0], y[0]],
    [x[1], y[1]]
  ];
};

/**
 * Lat/lon bounds
 */

Display.prototype.llBounds = function() {
  var x = this.xScale.domain();
  var y = this.yScale.domain();

  return [
    sm.inverse([x[0], y[0]]),
    sm.inverse([x[1], y[1]])
  ];
};

Display.prototype.isInRange = function(x, y) {
  var xRange = this.xScale.range();
  var yRange = this.yScale.range();

  return x >= xRange[0] && x <= xRange[1] && y >= yRange[1] && y <= yRange[0];
};

/**
 * Compute the x/y coordinate space domains to fit the graph.
 */

function getDomains(display, height, width, bounds, options) {
  var xmin = bounds[0][0],
    xmax = bounds[1][0];
  var ymin = bounds[0][1],
    ymax = bounds[1][1];
  var xRange = xmax - xmin;
  var yRange = ymax - ymin;

  var paddingFactor = (options && options.paddingFactor) ?
    options.paddingFactor : 0.1;

  var margins = getMargins(options);

  var usableHeight = height - margins.top - margins.bottom;
  var usableWidth = width - margins.left - margins.right;
  var displayAspect = width / height;
  var usableDisplayAspect = usableWidth / usableHeight;
  var graphAspect = xRange / (yRange === 0 ? -Infinity : yRange);

  var padding;
  var dispX1, dispX2, dispY1, dispY2;
  var dispXRange, dispYRange;

  if (usableDisplayAspect > graphAspect) { // y-axis is limiting
    padding = paddingFactor * yRange;
    dispY1 = ymin - padding;
    dispY2 = ymax + padding;
    dispYRange = yRange + 2 * padding;
    var addedYRange = (height / usableHeight * dispYRange) - dispYRange;
    if (margins.top > 0 || margins.bottom > 0) {
      dispY1 -= margins.bottom / (margins.bottom + margins.top) * addedYRange;
      dispY2 += margins.top / (margins.bottom + margins.top) * addedYRange;
    }
    dispXRange = (dispY2 - dispY1) * displayAspect;
    var xOffset = (margins.left - margins.right) / width;
    var xMidpoint = (xmax + xmin - dispXRange * xOffset) / 2;
    dispX1 = xMidpoint - dispXRange / 2;
    dispX2 = xMidpoint + dispXRange / 2;
  } else { // x-axis limiting
    padding = paddingFactor * xRange;
    dispX1 = xmin - padding;
    dispX2 = xmax + padding;
    dispXRange = xRange + 2 * padding;
    var addedXRange = (width / usableWidth * dispXRange) - dispXRange;
    if (margins.left > 0 || margins.right > 0) {
      dispX1 -= margins.left / (margins.left + margins.right) * addedXRange;
      dispX2 += margins.right / (margins.left + margins.right) * addedXRange;
    }

    dispYRange = (dispX2 - dispX1) / displayAspect;
    var yOffset = (margins.bottom - margins.top) / height;
    var yMidpoint = (ymax + ymin - dispYRange * yOffset) / 2;
    dispY1 = yMidpoint - dispYRange / 2;
    dispY2 = yMidpoint + dispYRange / 2;
  }

  return [
    [dispX1, dispX2],
    [dispY1, dispY2]
  ];
}

function getMargins(options) {
  var margins = {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0
  };

  if (options && options.displayMargins) {
    if (options.displayMargins.top) margins.top = options.displayMargins.top;
    if (options.displayMargins.bottom) margins.bottom = options.displayMargins.bottom;
    if (options.displayMargins.left) margins.left = options.displayMargins.left;
    if (options.displayMargins.right) margins.right = options.displayMargins.right;
  }

  return margins;
}
<commit_msg>adding console<commit_after>var d3 = require('d3');
var debug = require('debug')('transitive:display');
var each = require('each');

var Legend = require('./legend');
var TileLayer = require('./tile-layer');

var SphericalMercator = require('../util/spherical-mercator');
var sm = new SphericalMercator();

/**
 * Expose `Display`
 */

module.exports = Display;

/**
 * The D3-based SVG display.
 *
 * @param {Object} options
 */

function Display(transitive) {
  this.transitive = transitive;
  var el = this.el = transitive.el;
  //this.width = el.clientWidth;
  this.height = el.clientHeight;

  // Set up the pan/zoom behavior
  var zoom = this.zoom = d3.behavior.zoom()
    .scaleExtent([0.25, 4]);

  var self = this;

  var zoomBehavior = function() {
    self.computeScale();
    if (self.scale !== self.lastScale) { // zoom action
      self.zoomChanged();
    } else { // pan action
      setTimeout(transitive.refresh.bind(transitive, true), 0);
    }

    var llb = self.llBounds();
    debug('ll bounds: ' + llb[0][0] + ',' + llb[0][1] + ' to ' + llb[1][0] +
      ',' + llb[1][1]);
  };

  this.zoom.on('zoom.transitive', zoomBehavior);

  this.zoomFactors = transitive.options.zoomFactors || this.getDefaultZoomFactors();

  // set up the svg display
  var div = d3.select(el)
    .attr('class', 'Transitive');

  if (transitive.options.zoomEnabled) {
    div.call(zoom);
  }

  this.svg = div
    .append('svg')
    .attr('class', 'schematic-map');

  // initialize the x/y scale objects
  this.xScale = d3.scale.linear();
  this.yScale = d3.scale.linear();

  // set up the resize event handler
  if (transitive.options.autoResize) {
    d3.select(window).on('resize.display', function() {
      self.resized();
      transitive.refresh();
    });
  }

  // set the scale
  var bounds;
  if (transitive.options.initialBounds) {
    bounds = [sm.forward(transitive.options.initialBounds[0]),
      sm.forward(transitive.options.initialBounds[1])
    ];
  } else if (transitive.network && transitive.network.graph) {
    bounds = transitive.network.graph.bounds();
  }

  if (bounds) {
    this.setScale(bounds, transitive.options);
//    this.updateActiveZoomFactors(this.scale);
    this.updateActiveZoomFactors(1);
    this.lastScale = this.scale;
  } else {
    this.updateActiveZoomFactors(1);
  }

  // set up the map layer
  if (transitive.options.mapboxId) {
    this.tileLayer = new TileLayer({
      el: this.el,
      display: this,
      graph: transitive.graph,
      mapboxId: transitive.options.mapboxId
    });
  }

  // set up the legend
  if (transitive.options.legendEl) {
    this.legend = new Legend(transitive.options.legendEl, this, transitive);
  }

  transitive.emit('initialize display', transitive, this);
  return this;
}

/**
 * zoomChanged -- called when the zoom level changes, either by through the native
 * zoom support or the setBounds() API call. Updates zoom factors as needed and
 * performs appropriate update action (render or refresh)
 */

Display.prototype.zoomChanged = function() {
//  if (this.updateActiveZoomFactors(this.scale)) {
  if (this.updateActiveZoomFactors(1)) {
    this.transitive.network = null;
    this.transitive.render();
  } else this.transitive.refresh();
  this.lastScale = this.scale;
};

Display.prototype.updateActiveZoomFactors = function(scale) {
  // Overriding default behavior to always show maximum detail
  // on displayed routes.
  var updated = false;

  this.activeZoomFactors = this.zoomFactors[this.zoomFactors.length - 1];
  return true;
  // Override ends here.

  for (var i = 0; i < this.zoomFactors.length; i++) {
    var min = this.zoomFactors[i].minScale;
    var max = (i < this.zoomFactors.length - 1) ?
      this.zoomFactors[i + 1].minScale : Number.MAX_VALUE;

    // check if we've crossed into a new zoomFactor partition
    if ((!this.lastScale || this.lastScale < min || this.lastScale >= max) &&
      scale >= min && scale < max) {
      this.activeZoomFactors = this.zoomFactors[i];
      updated = true;
    }
  }
  return updated;
};

/**
 * Return default zoom factors
 */

Display.prototype.getDefaultZoomFactors = function(data) {
  return [{
    minScale: 0,
    gridCellSize: 25,
    internalVertexFactor: 1000000,
    angleConstraint: 45,
    mergeVertexThreshold: 200
  }, {
    minScale: 1.5,
    gridCellSize: 0,
    internalVertexFactor: 0,
    angleConstraint: 5,
    mergeVertexThreshold: 0
  }];
};

/**
 * Empty the display
 */

Display.prototype.empty = function() {
  debug('emptying svg');
  this.svg.selectAll('*').remove();

  this.haloLayer = this.svg.insert('g', ':first-child');
};

/**
 * Set the scale
 */

Display.prototype.setScale = function(bounds, options) {

  this.height = this.el.clientHeight;
  this.width = this.el.clientWidth;

  var domains = getDomains(this, this.height, this.width, bounds, options);
  this.xScale.domain(domains[0]);
  this.yScale.domain(domains[1]);

  this.xScale.range([0, this.width]);
  this.yScale.range([this.height, 0]);

  debug('x scale %j -> %j', this.xScale.domain(), this.xScale.range());
  debug('y scale %j -> %j', this.yScale.domain(), this.yScale.range());

  this.zoom
    .x(this.xScale)
    .y(this.yScale);

  this.initXRes = (domains[0][1] - domains[0][0]) / this.width;
  this.scale = 1;

  this.scaleSet = true;
};

Display.prototype.computeScale = function() {
  var newXRes = (this.xScale.domain()[1] - this.xScale.domain()[0]) / this.width;
  this.scale = this.initXRes / newXRes;
};

/**
 * updateDomains -- set x/y domains of geographic (spherical mercator) coordinate
 * system. Does *not* check/adjust aspect ratio.
 */

Display.prototype.updateDomains = function(bounds) {
  this.xScale.domain([bounds[0][0], bounds[1][0]]);
  this.yScale.domain([bounds[0][1], bounds[1][1]]);

  this.zoom
    .x(this.xScale)
    .y(this.yScale);

  this.computeScale();
};

Display.prototype.resized = function() {

  var newWidth = this.el.clientWidth;
  var newHeight = this.el.clientHeight;

  var xDomain = this.xScale.domain();
  var xFactor = newWidth / this.width;
  var xDomainAdj = (xDomain[1] - xDomain[0]) * (xFactor - 1) / 2;
  this.xScale.domain([xDomain[0] - xDomainAdj, xDomain[1] + xDomainAdj]);

  var yDomain = this.yScale.domain();
  var yFactor = newHeight / this.height;
  var yDomainAdj = (yDomain[1] - yDomain[0]) * (yFactor - 1) / 2;
  this.yScale.domain([yDomain[0] - yDomainAdj, yDomain[1] + yDomainAdj]);

  this.xScale.range([0, newWidth]);
  this.yScale.range([newHeight, 0]);

  this.height = newHeight;
  this.width = newWidth;

  this.zoom
    .x(this.xScale)
    .y(this.yScale);
};

Display.prototype.xyBounds = function() {
  var x = this.xScale.domain();
  var y = this.yScale.domain();
  return [
    [x[0], y[0]],
    [x[1], y[1]]
  ];
};

/**
 * Lat/lon bounds
 */

Display.prototype.llBounds = function() {
  var x = this.xScale.domain();
  var y = this.yScale.domain();

  return [
    sm.inverse([x[0], y[0]]),
    sm.inverse([x[1], y[1]])
  ];
};

Display.prototype.isInRange = function(x, y) {
  var xRange = this.xScale.range();
  var yRange = this.yScale.range();

  return x >= xRange[0] && x <= xRange[1] && y >= yRange[1] && y <= yRange[0];
};

/**
 * Compute the x/y coordinate space domains to fit the graph.
 */

function getDomains(display, height, width, bounds, options) {
  var xmin = bounds[0][0],
    xmax = bounds[1][0];
  var ymin = bounds[0][1],
    ymax = bounds[1][1];
  var xRange = xmax - xmin;
  var yRange = ymax - ymin;

  var paddingFactor = (options && options.paddingFactor) ?
    options.paddingFactor : 0.1;

  var margins = getMargins(options);

  var usableHeight = height - margins.top - margins.bottom;
  var usableWidth = width - margins.left - margins.right;
  var displayAspect = width / height;
  var usableDisplayAspect = usableWidth / usableHeight;
  var graphAspect = xRange / (yRange === 0 ? -Infinity : yRange);

  var padding;
  var dispX1, dispX2, dispY1, dispY2;
  var dispXRange, dispYRange;

  if (usableDisplayAspect > graphAspect) { // y-axis is limiting
    padding = paddingFactor * yRange;
    dispY1 = ymin - padding;
    dispY2 = ymax + padding;
    dispYRange = yRange + 2 * padding;
    var addedYRange = (height / usableHeight * dispYRange) - dispYRange;
    if (margins.top > 0 || margins.bottom > 0) {
      dispY1 -= margins.bottom / (margins.bottom + margins.top) * addedYRange;
      dispY2 += margins.top / (margins.bottom + margins.top) * addedYRange;
    }
    dispXRange = (dispY2 - dispY1) * displayAspect;
    var xOffset = (margins.left - margins.right) / width;
    var xMidpoint = (xmax + xmin - dispXRange * xOffset) / 2;
    dispX1 = xMidpoint - dispXRange / 2;
    dispX2 = xMidpoint + dispXRange / 2;
  } else { // x-axis limiting
    padding = paddingFactor * xRange;
    dispX1 = xmin - padding;
    dispX2 = xmax + padding;
    dispXRange = xRange + 2 * padding;
    var addedXRange = (width / usableWidth * dispXRange) - dispXRange;
    if (margins.left > 0 || margins.right > 0) {
      dispX1 -= margins.left / (margins.left + margins.right) * addedXRange;
      dispX2 += margins.right / (margins.left + margins.right) * addedXRange;
    }

    dispYRange = (dispX2 - dispX1) / displayAspect;
    var yOffset = (margins.bottom - margins.top) / height;
    var yMidpoint = (ymax + ymin - dispYRange * yOffset) / 2;
    dispY1 = yMidpoint - dispYRange / 2;
    dispY2 = yMidpoint + dispYRange / 2;
  }

  return [
    [dispX1, dispX2],
    [dispY1, dispY2]
  ];
}

function getMargins(options) {
  var margins = {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0
  };

  if (options && options.displayMargins) {
    if (options.displayMargins.top) margins.top = options.displayMargins.top;
    if (options.displayMargins.bottom) margins.bottom = options.displayMargins.bottom;
    if (options.displayMargins.left) margins.left = options.displayMargins.left;
    if (options.displayMargins.right) margins.right = options.displayMargins.right;
  }

  return margins;
}
<|endoftext|>


<commit_before>define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "Plugin", "tabManager", "menus", "commands", "settings",
        "tree", "save", "ui", "c9", "panels"
    ];
    main.provides = ["openfiles"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var tabs = imports.tabManager;
        var menus = imports.menus;
        var commands = imports.commands;
        var settings = imports.settings;
        var panels = imports.panels;
        var tree = imports.tree;
        var save = imports.save;
        var ui = imports.ui;

        var Tree = require("ace_tree/tree");
        var TreeData = require("./openfilesdp");
        var basename = require("path").basename;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();
        var staticPrefix = options.staticPrefix;

        // tree maximum height
        var showOpenFiles = false;
        var defaultShow = options.defaultShow;
        var dragged = false;

        // UI Elements
        var ofDataProvider, ofTree, treeParent, winFileTree;
        var ctxItem, preventUpdate, mnuFilesSettings;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Hook events to get the focussed tab
            tabs.on("focusSync", delayedUpdate);
            // tabs.on("tabDestroy", delayedUpdate);
            tabs.on("tabAfterClose", update);
            tabs.on("tabReparent", delayedUpdate);
            tabs.on("tabOrder", delayedUpdate);

            save.on("tabSavingState", refresh);

            commands.addCommand({
                name: "toggleOpenfiles",
                exec: function() {
                    toggleOpenfiles();
                }
            }, plugin);

            menus.addItemByPath("View/Open Files", new ui.item({
                type: "check",
                checked: "user/openfiles/@show"
                // command : "toggleOpenfiles"
            }), 210, plugin);

            tree.getElement("mnuFilesSettings", function(mnuFilesSettings){
                ui.insertByIndex(mnuFilesSettings, new ui.item({
                    caption: "Show Open Files",
                    type: "check",
                    checked: "user/openfiles/@show",
                }), 190, plugin);
                ui.insertByIndex(mnuFilesSettings,
                    new ui.divider(), 185, plugin);
            });

            settings.on("read", function(e) {
                // Defaults
                settings.setDefaults("user/openfiles", [
                    ["show", defaultShow],
                    ["hidetree", "false"]
                ]);
                showOpenFiles = settings.getBool("user/openfiles/@show");
                updateVisibility(showOpenFiles);
            }, plugin);

            settings.on("user/openfiles/@show", function(value) {
                showOpenFiles = value;
                updateVisibility(showOpenFiles);
            });

            panels.on("showPanelTree", function(){ update(); });
        }

        var drawn = false;
        function draw(){
            if (drawn) return;
            drawn = true;

            // ace_tree customization '.openfiles'
            ui.insertCss(require("text!./openfiles.css"), staticPrefix, plugin);

            tree.getElement("winOpenfiles", function(winOpenfiles) {
                treeParent = winOpenfiles;

                tree.getElement("winFileTree", function(winFileTreeL) {
                    winFileTree = winFileTreeL;
                });

                var div = document.createElement("div");
                treeParent.$int.appendChild(div);

                // Create the Ace Tree
                ofTree = new Tree(div);
                ofDataProvider = new TreeData();
                // ofTree.renderer.setScrollMargin(0, 10);
                ofTree.renderer.setTheme({cssClass: "filetree"});
                // Assign the dataprovider
                ofTree.setDataProvider(ofDataProvider);
                // Some global render metadata
                ofDataProvider.staticPrefix = staticPrefix;

                var height = parseInt(ui.getStyleRule(".openfiles .ace_tree .tree-row", "height"), 10);
                ofDataProvider.rowHeightInner = height;
                ofDataProvider.rowHeight = height + 1;

                ofTree.on("userSelect", function(){
                    setTimeout(onSelect, 40);
                });

                // make sure scrollbar on windows is in the padding area
                ofTree.renderer.on("scrollbarVisibilityChanged", updateScrollBarSize);
                ofTree.renderer.on("resize", updateScrollBarSize);
                function updateScrollBarSize() {
                    var w = ofTree.renderer.scrollBarV.getWidth();
                    ofTree.renderer.scroller.style.right = Math.max(w, 10) + "px";
                }

                // APF + DOM HACK: close tab with confirmation
                ofTree.on("mousedown", function(e) {
                    var domTarget = e.domEvent.target;
                    var pos = e.getDocumentPosition();
                    var node = ofDataProvider.findItemAtOffset(pos.y);

                    if (node.children && !~domTarget.className.indexOf("toggler")) {
                        e.preventDefault();
                        return;
                    }

                    if (! (node && node.path && domTarget && ~domTarget.className.indexOf("close")))
                        return;

                    var amlTab = node.tab.aml;
                    amlTab.parentNode.remove(amlTab, {});
                });

                ofTree.focus = function() {};

                ofTree.renderer.on("autoresize", function() {
                    updateHeight();
                });

                ofTree.setOption("maxLines", 100);
                ofTree.renderer.getMaxHeight = function () {
                    return Math.floor(treeParent.parentNode.$int.offsetHeight * 0.5 - 23);
                };

                mnuFilesSettings = tree.getElement("mnuFilesSettings");
                ctxItem = ui.insertByIndex(mnuFilesSettings, new ui.item({
                    caption: "Hide Workspace Files",
                    type: "check",
                    visible: treeParent.visible,
                    checked: "state/openfiles/@hidetree",
                    onclick: function(e) {
                        hideTree(this.checked);
                    }
                }), 195, plugin);

                if (showOpenFiles) {
                    tabs.once("ready", function(){ show(); });

                    if (settings.getBool("state/openfiles/@hidetree"))
                        hideTree(true);
                }
                else
                    hideOpenFiles();

                emit("draw");
            });
        }

        /***** Methods *****/

        function hideTree(state) {
            settings.set("state/openfiles/@hidetree", state);

            if (treeParent) {
                if (state)
                    ui.setStyleClass(treeParent.parentNode.$int, "hidetree");
                else
                    ui.setStyleClass(treeParent.parentNode.$int, "", ["hidetree"]);
            }

            if (mnuFilesSettings) {
                mnuFilesSettings.childNodes.forEach(function(node) {
                    if (node.$position >= 200) {
                        node.setAttribute("visible", !state);
                    }
                });
            }

            if (ofTree) {
                ofTree.resize();
                tree.resize();
            }
        }

        var updateTimer;
        function delayedUpdate() {
            if (updateTimer)
                return;
            updateTimer = setTimeout(function() {
                updateTimer = null;
                update();
            }, 10);
        }

        function update() {
            if (!showOpenFiles)
                return;

            if (!panels.isActive("tree"))
                return;

            draw();

            if (!ofTree)
                return;

            preventUpdate = true;

            var activePanes = tabs.getPanes(tabs.container);
            var focussedTab = tabs.focussedTab;
            // focussedTab can be the terminal or output views
            if (focussedTab && activePanes.indexOf(focussedTab.pane) === -1
              && activePanes.length)
                focussedTab = activePanes[0].getTab();

            // unhook document change update listeners
            tabs.getTabs().forEach(function (tab) {
                tab.document && tab.document.off("changed", refresh);
            });

            var selected;
            var root = { groups: [] };
            var actualRoot = {
                children: [
                    {
                        label: "open files",
                        path: "!openfiles",
                        isOpen: true,
                        className: "heading",
                        isRoot: true,
                        isFolder: true,
                        status: "loaded",
                        map: {},
                        children: root.groups,
                        noSelect: true
                    }
                ]
            };

            var oldRoot = ofDataProvider && ofDataProvider.root;
            var existing = oldRoot && oldRoot.groups || {};
            root.children = activePanes.map(function(pane, i) {
                var group = existing[i] || { isOpen: true, className: "group" };
                if (group.isOpen == "forced")
                    group.isOpen = false;
                root.groups[i] = group;
                group.children = null;
                // name: pane.name (tab0 ...)
                group.children =  pane.getTabs()
                    .filter(function(tab) {
                        return tab.path && tab.loaded && !tab.meta.$closing;
                    })
                    .map(function(tab) {
                        var node = {
                            name: basename(tab.path),
                            path: tab.path,
                            tab: tab
                        };
                        if (tab == focussedTab) {
                            selected = node;
                            group.isOpen = "forced";
                        }

                        tab.document.on("changed", refresh);
                        return node;
                    });
                return group;
            }).filter(function(pane) {
                return pane.children.length;
            }).map(function (node, i) {
                node.name = "GROUP " + (i+1);
                return node;
            });

            // Hide the openfiles
            if (!root.children.length) {
                preventUpdate = false;
                return hideOpenFiles();
            }

            ui.setStyleClass(treeParent.parentNode.$int, "hasopenfiles");

            treeParent.show();

            if (root.children.length === 1)
                actualRoot.children[0].children = root.children[0].children;

            ofDataProvider.setRoot(actualRoot);
            ofDataProvider.selection.selectNode(selected);

            updateHeight();
        }

        function updateHeight(selected) {
            preventUpdate = true;

            var maxHeight = treeParent.parentNode.$int.offsetHeight * 0.5;
            var treeHeight = ofTree.renderer.desiredHeight + 23;

            treeParent.$int.style.height = dragged
                ? Math.min(treeParent.getHeight(), treeHeight) + "px"
                : Math.min(treeHeight, maxHeight) + "px";

            // ofTree.resize(true);
            tree.resize();

            if (!selected)
                selected = ofTree.selectedNode;

            ofTree.renderer.scrollCaretIntoView(selected, 0.5);

            preventUpdate = false;
        }

        function refresh() {
            if (!showOpenFiles || !ofDataProvider)
                return;
            ofDataProvider._signal("change");
        }

        function onSelect() {
            var node = ofTree.selection.getCursor();
            if (node && tabs.focussedTab && tabs.focussedTab.path != node.path)
                tabs.focusTab(node.path);
        }

        function hideOpenFiles() {
            var htmlNode = treeParent && treeParent.parentNode.$int;
            htmlNode && ui.setStyleClass(htmlNode, "", ["hasopenfiles"]);
            treeParent && treeParent.hide();
            tree.resize();
        }

        function toggleOpenfiles() {
            showOpenFiles = !showOpenFiles;
            settings.set("user/openfiles/@show", showOpenFiles);
            updateVisibility(showOpenFiles);
        }

        function updateVisibility(show) {
            if (show) {
                draw();
                update();
                ctxItem && ctxItem.show();

                if (settings.getBool("state/openfiles/@hidetree"))
                    hideTree(true);

                if (!panels.isActive("tree")) {
                    panels.once("showPanelTree", function(){
                        ofTree.resize(true);
                        tree.resize(true);
                    });

                    panels.activate("tree");
                }
            }
            else {
                hideOpenFiles();
                ctxItem && ctxItem.hide();

                if (treeParent)
                    hideTree(false);
            }

            emit("visible", { value: show });
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
            drawn = false;
        });

        function show() {
            updateVisibility(true);
        }

        function hide() {
            updateVisibility(false);
        }

        /***** Register and define API *****/

        /**
         * Displays the open files above the tree.
         *
         * @singleton
         */
        plugin.freezePublicAPI({
            /**
             * Show the openfiles panel
             */
            show: show,

            /**
             * Hide the openfiles panel
             */
            hide: hide,

            /**
             * Trigger a complete update of the openfiles view, only when the
             * openfiles panel is visible.
             */
            update: update,

            /**
             * Rerender the viewed part of the tree without having to recreate
             * the tree data.
             * Example usage: when the saving state or document content changed
             * Only applies when openfiles is visible
             */
            refresh: refresh,

            /**
             *
             */
            showTree: hideTree.bind(null, false),

            /**
             *
             */
            hideTree: hideTree.bind(null, true)
        });

        register(null, {
            openfiles: plugin
        });
    }
});
<commit_msg>Working on resizing elements<commit_after>define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "Plugin", "tabManager", "menus", "commands", "settings",
        "tree", "save", "ui", "c9", "panels", "layout"
    ];
    main.provides = ["openfiles"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var tabs = imports.tabManager;
        var menus = imports.menus;
        var commands = imports.commands;
        var settings = imports.settings;
        var panels = imports.panels;
        var layout = imports.layout;
        var tree = imports.tree;
        var save = imports.save;
        var ui = imports.ui;

        var Tree = require("ace_tree/tree");
        var TreeData = require("./openfilesdp");
        var basename = require("path").basename;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();
        var staticPrefix = options.staticPrefix;

        // tree maximum height
        var showOpenFiles = false;
        var defaultShow = options.defaultShow;
        var dragged = false;

        // UI Elements
        var ofDataProvider, ofTree, treeParent, winFileTree;
        var ctxItem, preventUpdate, mnuFilesSettings;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Hook events to get the focussed tab
            tabs.on("focusSync", delayedUpdate);
            // tabs.on("tabDestroy", delayedUpdate);
            tabs.on("tabAfterClose", update);
            tabs.on("tabReparent", delayedUpdate);
            tabs.on("tabOrder", delayedUpdate);

            save.on("tabSavingState", refresh);

            commands.addCommand({
                name: "toggleOpenfiles",
                exec: function() {
                    toggleOpenfiles();
                }
            }, plugin);

            menus.addItemByPath("View/Open Files", new ui.item({
                type: "check",
                checked: "user/openfiles/@show"
                // command : "toggleOpenfiles"
            }), 210, plugin);

            tree.getElement("mnuFilesSettings", function(mnuFilesSettings){
                ui.insertByIndex(mnuFilesSettings, new ui.item({
                    caption: "Show Open Files",
                    type: "check",
                    checked: "user/openfiles/@show",
                }), 190, plugin);
                ui.insertByIndex(mnuFilesSettings,
                    new ui.divider(), 185, plugin);
            });

            settings.on("read", function(e) {
                // Defaults
                settings.setDefaults("user/openfiles", [
                    ["show", defaultShow],
                    ["hidetree", "false"]
                ]);
                showOpenFiles = settings.getBool("user/openfiles/@show");
                updateVisibility(showOpenFiles);
            }, plugin);

            settings.on("user/openfiles/@show", function(value) {
                showOpenFiles = value;
                updateVisibility(showOpenFiles);
            });

            panels.on("showPanelTree", function(){ update(); });
        }

        var drawn = false;
        function draw(){
            if (drawn) return;
            drawn = true;

            // ace_tree customization '.openfiles'
            ui.insertCss(require("text!./openfiles.css"), staticPrefix, plugin);

            tree.getElement("winOpenfiles", function(winOpenfiles) {
                treeParent = winOpenfiles;

                tree.getElement("winFileTree", function(winFileTreeL) {
                    winFileTree = winFileTreeL;
                });

                var div = document.createElement("div");
                treeParent.$int.appendChild(div);

                // Create the Ace Tree
                ofTree = new Tree(div);
                ofDataProvider = new TreeData();
                // ofTree.renderer.setScrollMargin(0, 10);
                ofTree.renderer.setTheme({cssClass: "filetree"});
                // Assign the dataprovider
                ofTree.setDataProvider(ofDataProvider);
                // Some global render metadata
                ofDataProvider.staticPrefix = staticPrefix;

                layout.on("eachTheme", function(e){
                    var height = parseInt(ui.getStyleRule(".openfiles .ace_tree .tree-row", "height"), 10);
                    ofDataProvider.rowHeightInner = height;
                    ofDataProvider.rowHeight = height + 1;

                    if (e.changed) tree.resize();
                });

                ofTree.on("userSelect", function(){
                    setTimeout(onSelect, 40);
                });

                // make sure scrollbar on windows is in the padding area
                ofTree.renderer.on("scrollbarVisibilityChanged", updateScrollBarSize);
                ofTree.renderer.on("resize", updateScrollBarSize);
                function updateScrollBarSize() {
                    var w = ofTree.renderer.scrollBarV.getWidth();
                    ofTree.renderer.scroller.style.right = Math.max(w, 10) + "px";
                }

                // APF + DOM HACK: close tab with confirmation
                ofTree.on("mousedown", function(e) {
                    var domTarget = e.domEvent.target;
                    var pos = e.getDocumentPosition();
                    var node = ofDataProvider.findItemAtOffset(pos.y);

                    if (node.children && !~domTarget.className.indexOf("toggler")) {
                        e.preventDefault();
                        return;
                    }

                    if (! (node && node.path && domTarget && ~domTarget.className.indexOf("close")))
                        return;

                    var amlTab = node.tab.aml;
                    amlTab.parentNode.remove(amlTab, {});
                });

                ofTree.focus = function() {};

                ofTree.renderer.on("autoresize", function() {
                    updateHeight();
                });

                ofTree.setOption("maxLines", 100);
                ofTree.renderer.getMaxHeight = function () {
                    return Math.floor(treeParent.parentNode.$int.offsetHeight * 0.5 - 23);
                };

                mnuFilesSettings = tree.getElement("mnuFilesSettings");
                ctxItem = ui.insertByIndex(mnuFilesSettings, new ui.item({
                    caption: "Hide Workspace Files",
                    type: "check",
                    visible: treeParent.visible,
                    checked: "state/openfiles/@hidetree",
                    onclick: function(e) {
                        hideTree(this.checked);
                    }
                }), 195, plugin);

                if (showOpenFiles) {
                    tabs.once("ready", function(){ show(); });

                    if (settings.getBool("state/openfiles/@hidetree"))
                        hideTree(true);
                }
                else
                    hideOpenFiles();

                emit("draw");
            });
        }

        /***** Methods *****/

        function hideTree(state) {
            settings.set("state/openfiles/@hidetree", state);

            if (treeParent) {
                if (state)
                    ui.setStyleClass(treeParent.parentNode.$int, "hidetree");
                else
                    ui.setStyleClass(treeParent.parentNode.$int, "", ["hidetree"]);
            }

            if (mnuFilesSettings) {
                mnuFilesSettings.childNodes.forEach(function(node) {
                    if (node.$position >= 200) {
                        node.setAttribute("visible", !state);
                    }
                });
            }

            if (ofTree) {
                ofTree.resize();
                tree.resize();
            }
        }

        var updateTimer;
        function delayedUpdate() {
            if (updateTimer)
                return;
            updateTimer = setTimeout(function() {
                updateTimer = null;
                update();
            }, 10);
        }

        function update() {
            if (!showOpenFiles)
                return;

            if (!panels.isActive("tree"))
                return;

            draw();

            if (!ofTree)
                return;

            preventUpdate = true;

            var activePanes = tabs.getPanes(tabs.container);
            var focussedTab = tabs.focussedTab;
            // focussedTab can be the terminal or output views
            if (focussedTab && activePanes.indexOf(focussedTab.pane) === -1
              && activePanes.length)
                focussedTab = activePanes[0].getTab();

            // unhook document change update listeners
            tabs.getTabs().forEach(function (tab) {
                tab.document && tab.document.off("changed", refresh);
            });

            var selected;
            var root = { groups: [] };
            var actualRoot = {
                children: [
                    {
                        label: "open files",
                        path: "!openfiles",
                        isOpen: true,
                        className: "heading",
                        isRoot: true,
                        isFolder: true,
                        status: "loaded",
                        map: {},
                        children: root.groups,
                        noSelect: true
                    }
                ]
            };

            var oldRoot = ofDataProvider && ofDataProvider.root;
            var existing = oldRoot && oldRoot.groups || {};
            root.children = activePanes.map(function(pane, i) {
                var group = existing[i] || { isOpen: true, className: "group" };
                if (group.isOpen == "forced")
                    group.isOpen = false;
                root.groups[i] = group;
                group.children = null;
                // name: pane.name (tab0 ...)
                group.children =  pane.getTabs()
                    .filter(function(tab) {
                        return tab.path && tab.loaded && !tab.meta.$closing;
                    })
                    .map(function(tab) {
                        var node = {
                            name: basename(tab.path),
                            path: tab.path,
                            tab: tab
                        };
                        if (tab == focussedTab) {
                            selected = node;
                            group.isOpen = "forced";
                        }

                        tab.document.on("changed", refresh);
                        return node;
                    });
                return group;
            }).filter(function(pane) {
                return pane.children.length;
            }).map(function (node, i) {
                node.name = "GROUP " + (i+1);
                return node;
            });

            // Hide the openfiles
            if (!root.children.length) {
                preventUpdate = false;
                return hideOpenFiles();
            }

            ui.setStyleClass(treeParent.parentNode.$int, "hasopenfiles");

            treeParent.show();

            if (root.children.length === 1)
                actualRoot.children[0].children = root.children[0].children;

            ofDataProvider.setRoot(actualRoot);
            ofDataProvider.selection.selectNode(selected);

            updateHeight();
        }

        function updateHeight(selected) {
            preventUpdate = true;

            var maxHeight = treeParent.parentNode.$int.offsetHeight * 0.5;
            var treeHeight = ofTree.renderer.desiredHeight + 23;

            treeParent.$int.style.height = dragged
                ? Math.min(treeParent.getHeight(), treeHeight) + "px"
                : Math.min(treeHeight, maxHeight) + "px";

            // ofTree.resize(true);
            tree.resize();

            if (!selected)
                selected = ofTree.selectedNode;

            ofTree.renderer.scrollCaretIntoView(selected, 0.5);

            preventUpdate = false;
        }

        function refresh() {
            if (!showOpenFiles || !ofDataProvider)
                return;
            ofDataProvider._signal("change");
        }

        function onSelect() {
            var node = ofTree.selection.getCursor();
            if (node && tabs.focussedTab && tabs.focussedTab.path != node.path)
                tabs.focusTab(node.path);
        }

        function hideOpenFiles() {
            var htmlNode = treeParent && treeParent.parentNode.$int;
            htmlNode && ui.setStyleClass(htmlNode, "", ["hasopenfiles"]);
            treeParent && treeParent.hide();
            tree.resize();
        }

        function toggleOpenfiles() {
            showOpenFiles = !showOpenFiles;
            settings.set("user/openfiles/@show", showOpenFiles);
            updateVisibility(showOpenFiles);
        }

        function updateVisibility(show) {
            if (show) {
                draw();
                update();
                ctxItem && ctxItem.show();

                if (settings.getBool("state/openfiles/@hidetree"))
                    hideTree(true);

                if (!panels.isActive("tree")) {
                    panels.once("showPanelTree", function(){
                        ofTree.resize(true);
                        tree.resize(true);
                    });

                    panels.activate("tree");
                }
            }
            else {
                hideOpenFiles();
                ctxItem && ctxItem.hide();

                if (treeParent)
                    hideTree(false);
            }

            emit("visible", { value: show });
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
            drawn = false;
        });

        function show() {
            updateVisibility(true);
        }

        function hide() {
            updateVisibility(false);
        }

        /***** Register and define API *****/

        /**
         * Displays the open files above the tree.
         *
         * @singleton
         */
        plugin.freezePublicAPI({
            /**
             * Show the openfiles panel
             */
            show: show,

            /**
             * Hide the openfiles panel
             */
            hide: hide,

            /**
             * Trigger a complete update of the openfiles view, only when the
             * openfiles panel is visible.
             */
            update: update,

            /**
             * Rerender the viewed part of the tree without having to recreate
             * the tree data.
             * Example usage: when the saving state or document content changed
             * Only applies when openfiles is visible
             */
            refresh: refresh,

            /**
             *
             */
            showTree: hideTree.bind(null, false),

            /**
             *
             */
            hideTree: hideTree.bind(null, true)
        });

        register(null, {
            openfiles: plugin
        });
    }
});
<|endoftext|>


<commit_before>define([
  'angular',
  'lodash',
  './query_def'
],
function (angular, _, queryDef) {
  'use strict';

  var module = angular.module('grafana.directives');

  module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q, $rootScope) {
    var metricAggs = $scope.target.metrics;

    $scope.metricAggTypes = queryDef.metricAggTypes;
    $scope.extendedStats = queryDef.extendedStats;
    $scope.pipelineAggOptions = [];

    $scope.init = function() {
      $scope.agg = metricAggs[$scope.index];
      $scope.validateModel();
      $scope.updatePipelineAggOptions();
    };

    $scope.updatePipelineAggOptions = function() {
      $scope.pipelineAggOptions = queryDef.getMovingAverageOptions($scope.target);
    };

    $rootScope.onAppEvent('elastic-query-updated', function() {
      $scope.index = _.indexOf(metricAggs, $scope.agg);
      $scope.updatePipelineAggOptions();
      $scope.validateModel();
    }, $scope);

    $scope.validateModel = function() {
      $scope.isFirst = $scope.index === 0;
      $scope.isSingle = metricAggs.length === 1;
      $scope.settingsLinkText = '';
      $scope.aggDef = _.findWhere($scope.metricAggTypes, {value: $scope.agg.type});

      if (!$scope.agg.field) {
        $scope.agg.field = 'select field';
      }

      switch($scope.agg.type) {
        case 'moving_avg': {
          $scope.agg.pipelineAgg = $scope.agg.pipelineAgg || 'Metric to apply moving average';
          $scope.settingsLinkText = 'Moving average options';
          $scope.agg.field = $scope.agg.pipelineAgg;
          break;
        }
        case 'percentiles': {
          $scope.agg.settings.percents = $scope.agg.settings.percents || [25,50,75,95,99];
          $scope.settingsLinkText = 'values: ' + $scope.agg.settings.percents.join(',');
          break;
        }
        case 'extended_stats': {
          var stats = _.reduce($scope.agg.meta, function(memo, val, key) {
            if (val) {
              var def = _.findWhere($scope.extendedStats, {value: key});
              memo.push(def.text);
            }
            return memo;
          }, []);
          $scope.settingsLinkText = 'Stats: ' + stats.join(', ');

          if (stats.length === 0)  {
            $scope.agg.meta.std_deviation_bounds_lower = true;
            $scope.agg.meta.std_deviation_bounds_upper = true;
          }
          break;
        }
        case 'raw_document': {
          $scope.target.metrics = [$scope.agg];
          $scope.target.bucketAggs = [];
        }
      }
    };

    $scope.toggleOptions = function() {
      $scope.showOptions = !$scope.showOptions;
      $scope.updatePipelineAggOptions();
    };

    $scope.onChangeInternal = function() {
      $scope.onChange();
    };

    $scope.onTypeChange = function() {
      $scope.agg.settings = {};
      $scope.agg.meta = {};
      $scope.showOptions = false;
      $scope.onChange();
    };

    $scope.getFieldsInternal = function() {
      return $scope.getFields({$fieldType: 'number'});
    };

    $scope.addMetricAgg = function() {
      var addIndex = metricAggs.length;

      var id = _.reduce($scope.target.bucketAggs.concat($scope.target.metrics), function(max, val) {
        return parseInt(val.id) > max ? parseInt(val.id) : max;
      }, 0);

      metricAggs.splice(addIndex, 0, {type: "count", field: "select field", id: (id+1).toString()});
      $scope.onChange();
    };

    $scope.removeMetricAgg = function() {
      metricAggs.splice($scope.index, 1);
      $scope.onChange();
    };

    $scope.init();

  });

});
<commit_msg>move pipeline options outside main switch<commit_after>define([
  'angular',
  'lodash',
  './query_def'
],
function (angular, _, queryDef) {
  'use strict';

  var module = angular.module('grafana.directives');

  module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q, $rootScope) {
    var metricAggs = $scope.target.metrics;

    $scope.metricAggTypes = queryDef.metricAggTypes;
    $scope.extendedStats = queryDef.extendedStats;
    $scope.pipelineAggOptions = [];

    $scope.init = function() {
      $scope.agg = metricAggs[$scope.index];
      $scope.validateModel();
      $scope.updatePipelineAggOptions();
    };

    $scope.updatePipelineAggOptions = function() {
      $scope.pipelineAggOptions = queryDef.getMovingAverageOptions($scope.target);
    };

    $rootScope.onAppEvent('elastic-query-updated', function() {
      $scope.index = _.indexOf(metricAggs, $scope.agg);
      $scope.updatePipelineAggOptions();
      $scope.validateModel();
    }, $scope);

    $scope.validateModel = function() {
      $scope.isFirst = $scope.index === 0;
      $scope.isSingle = metricAggs.length === 1;
      $scope.settingsLinkText = '';
      $scope.aggDef = _.findWhere($scope.metricAggTypes, {value: $scope.agg.type});

      if (!$scope.agg.field) {
        $scope.agg.field = 'select field';
      }

      if (queryDef.isPipelineAgg($scope.agg)) {
        $scope.agg.pipelineAgg = $scope.agg.pipelineAgg || 'select metric';
        $scope.agg.field = $scope.agg.pipelineAgg;
        $scope.settingsLinkText = 'Options';
      }

      switch($scope.agg.type) {
        case 'percentiles': {
          $scope.agg.settings.percents = $scope.agg.settings.percents || [25,50,75,95,99];
          $scope.settingsLinkText = 'values: ' + $scope.agg.settings.percents.join(',');
          break;
        }
        case 'extended_stats': {
          var stats = _.reduce($scope.agg.meta, function(memo, val, key) {
            if (val) {
              var def = _.findWhere($scope.extendedStats, {value: key});
              memo.push(def.text);
            }
            return memo;
          }, []);
          $scope.settingsLinkText = 'Stats: ' + stats.join(', ');

          if (stats.length === 0)  {
            $scope.agg.meta.std_deviation_bounds_lower = true;
            $scope.agg.meta.std_deviation_bounds_upper = true;
          }
          break;
        }
        case 'raw_document': {
          $scope.target.metrics = [$scope.agg];
          $scope.target.bucketAggs = [];
        }
      }
    };

    $scope.toggleOptions = function() {
      $scope.showOptions = !$scope.showOptions;
      $scope.updatePipelineAggOptions();
    };

    $scope.onChangeInternal = function() {
      $scope.onChange();
    };

    $scope.onTypeChange = function() {
      $scope.agg.settings = {};
      $scope.agg.meta = {};
      $scope.showOptions = false;
      $scope.onChange();
    };

    $scope.getFieldsInternal = function() {
      return $scope.getFields({$fieldType: 'number'});
    };

    $scope.addMetricAgg = function() {
      var addIndex = metricAggs.length;

      var id = _.reduce($scope.target.bucketAggs.concat($scope.target.metrics), function(max, val) {
        return parseInt(val.id) > max ? parseInt(val.id) : max;
      }, 0);

      metricAggs.splice(addIndex, 0, {type: "count", field: "select field", id: (id+1).toString()});
      $scope.onChange();
    };

    $scope.removeMetricAgg = function() {
      metricAggs.splice($scope.index, 1);
      $scope.onChange();
    };

    $scope.init();

  });

});
<|endoftext|>


<commit_before>'use strict';

define(['bitcoinjs-lib', 'crypto-js', 'sjcl'],
    function(Bitcoin, CryptoJS, sjcl) {

        function TLCrypto() {
        }

        TLCrypto.wordsToBytes = function(words) {
            var bytes = []
            for (var b = 0; b < words.length * 32; b += 8) {
                bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF)
            }
            return bytes
        };

        TLCrypto.wordArrayToBytes = function(wordArray) {
            return TLCrypto.wordsToBytes(wordArray.words)
        };

        TLCrypto.hexStringToData = function(hexString) {
            return new Bitcoin.Buffer(hexString, 'hex');
        };

        TLCrypto.getPasswordDigest = function(password) {
            var SHA256 = CryptoJS.SHA256;
            var passwordDigest = TLCrypto.wordArrayToBytes(SHA256(SHA256(SHA256(password))));
            return new Bitcoin.Buffer(passwordDigest).toString('hex');
        };

        TLCrypto.getPasswordHash = function(password) {
            var SHA256 = CryptoJS.SHA256;
            var passwordDigest = TLCrypto.wordArrayToBytes(SHA256(SHA256(SHA256(SHA256(SHA256(password))))));
            return new Bitcoin.Buffer(passwordDigest).toString('hex');
        };

        TLCrypto.encrypt = function(plainText, password) {
            var passwordDigest = TLCrypto.getPasswordDigest(password);
            var privData = sjcl.encrypt(passwordDigest, plainText, {ks: 256, ts: 128});
            return privData;
        };

        TLCrypto.decrypt = function(cipherText, password) {
            var passwordDigest = TLCrypto.getPasswordDigest(password);
            var data = sjcl.decrypt(passwordDigest, cipherText);
            return data;
        };

        return TLCrypto;
    });
<commit_msg>add note to TLCrypto<commit_after>'use strict';

define(['bitcoinjs-lib', 'crypto-js', 'sjcl'],
    function(Bitcoin, CryptoJS, sjcl) {

        function TLCrypto() {
        }

        TLCrypto.wordsToBytes = function(words) {
            var bytes = []
            for (var b = 0; b < words.length * 32; b += 8) {
                bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF)
            }
            return bytes
        };

        TLCrypto.wordArrayToBytes = function(wordArray) {
            return TLCrypto.wordsToBytes(wordArray.words)
        };

        TLCrypto.hexStringToData = function(hexString) {
            return new Bitcoin.Buffer(hexString, 'hex');
        };

        TLCrypto.getPasswordDigest = function(password) {
            var SHA256 = CryptoJS.SHA256;
            var passwordDigest = TLCrypto.wordArrayToBytes(SHA256(SHA256(SHA256(password))));
            return new Bitcoin.Buffer(passwordDigest).toString('hex');
            // maybe go with this password digest or something to that effect
            //return sjcl.codec.base64.fromBits(sjcl.misc.pbkdf2(password, email, 1000));
        };

        TLCrypto.getPasswordHash = function(password) {
            var SHA256 = CryptoJS.SHA256;
            var passwordDigest = TLCrypto.wordArrayToBytes(SHA256(SHA256(SHA256(SHA256(SHA256(password))))));
            return new Bitcoin.Buffer(passwordDigest).toString('hex');
        };

        TLCrypto.encrypt = function(plainText, password) {
            var passwordDigest = TLCrypto.getPasswordDigest(password);
            var privData = sjcl.encrypt(passwordDigest, plainText, {ks: 256, ts: 128});
            return privData;
        };

        TLCrypto.decrypt = function(cipherText, password) {
            var passwordDigest = TLCrypto.getPasswordDigest(password);
            var data = sjcl.decrypt(passwordDigest, cipherText);
            return data;
        };

        return TLCrypto;
    });
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const ModuleTransport = require('../lib/ModuleTransport');
const Promise = require('promise');
const declareOpts = require('../lib/declareOpts');
const fs = require('fs');
const temp = require('temp');
const util = require('util');
const workerFarm = require('worker-farm');
const debug = require('debug')('ReactNativePackager:JStransformer');

const readFile = Promise.denodeify(fs.readFile);

// Avoid memory leaks caused in workers. This number seems to be a good enough number
// to avoid any memory leak while not slowing down initial builds.
// TODO(amasad): Once we get bundle splitting, we can drive this down a bit more.
const MAX_CALLS_PER_WORKER = 600;

// Worker will timeout if one of the callers timeout.
const DEFAULT_MAX_CALL_TIME = 301000;

// How may times can we tolerate failures from the worker.
const MAX_RETRIES = 2;

const validateOpts = declareOpts({
  projectRoots: {
    type: 'array',
    required: true,
  },
  blacklistRE: {
    type: 'object', // typeof regex is object
  },
  polyfillModuleNames: {
    type: 'array',
    default: [],
  },
  transformModulePath: {
    type:'string',
    required: false,
  },
  cache: {
    type: 'object',
    required: true,
  },
  transformTimeoutInterval: {
    type: 'number',
    default: DEFAULT_MAX_CALL_TIME,
  },
  disableInternalTransforms: {
    type: 'boolean',
    default: false,
  },
});

class Transformer {
  constructor(options) {
    const opts = this._opts = validateOpts(options);

    this._cache = opts.cache;
    this._transformModulePath = opts.transformModulePath;
    this._projectRoots = opts.projectRoots;

    if (opts.transformModulePath != null) {
      let transformer;

      if (opts.disableInternalTransforms) {
        transformer = opts.transformModulePath;
      } else {
        transformer = this._workerWrapperPath = temp.path();
        fs.writeFileSync(
          this._workerWrapperPath,
          `
          module.exports = require(${JSON.stringify(require.resolve('./worker'))});
          require(${JSON.stringify(String(opts.transformModulePath))});
          `
        );
      }

      this._workers = workerFarm({
        autoStart: true,
        maxConcurrentCallsPerWorker: 1,
        maxCallsPerWorker: MAX_CALLS_PER_WORKER,
        maxCallTime: opts.transformTimeoutInterval,
        maxRetries: MAX_RETRIES,
      }, transformer);

      this._transform = Promise.denodeify(this._workers);
    }
  }

  kill() {
    this._workers && workerFarm.end(this._workers);
    if (this._workerWrapperPath &&
        typeof this._workerWrapperPath === 'string') {
      fs.unlink(this._workerWrapperPath, () => {}); // we don't care about potential errors here
    }
  }

  invalidateFile(filePath) {
    this._cache.invalidate(filePath);
  }

  loadFileAndTransform(filePath, options) {
    if (this._transform == null) {
      return Promise.reject(new Error('No transfrom module'));
    }

    debug('transforming file', filePath);

    const optionsJSON = JSON.stringify(options);

    return this._cache.get(
      filePath,
      'transformedSource-' + optionsJSON,
      // TODO: use fastfs to avoid reading file from disk again
      () => readFile(filePath).then(
        buffer => {
          const sourceCode = buffer.toString('utf8');

          return this._transform({
            sourceCode,
            filename: filePath,
            options: {
              ...options,
              projectRoots: this._projectRoots,
              externalTransformModulePath: this._transformModulePath,
            },
          }).then(res => {
            if (res.error) {
              console.warn(
                'Error property on the result value from the transformer',
                'module is deprecated and will be removed in future versions.',
                'Please pass an error object as the first argument to the callback'
              );
              throw formatError(res.error, filePath);
            }

            debug('done transforming file', filePath);

            return new ModuleTransport({
              code: res.code,
              map: res.map,
              sourcePath: filePath,
              sourceCode: sourceCode,
            });
          }).catch(err => {
            if (err.type === 'TimeoutError') {
              const timeoutErr = new Error(
                `TimeoutError: transforming ${filePath} took longer than ` +
                `${this._opts.transformTimeoutInterval / 1000} seconds.\n` +
                `You can adjust timeout via the 'transformTimeoutInterval' option`
              );
              timeoutErr.type = 'TimeoutError';
              throw timeoutErr;
            } else if (err.type === 'ProcessTerminatedError') {
              const uncaughtError = new Error(
                'Uncaught error in the transformer worker: ' +
                this._opts.transformModulePath
              );
              uncaughtError.type = 'ProcessTerminatedError';
              throw uncaughtError;
            }

            throw formatError(err, filePath);
          });
        })
    );
  }
}

module.exports = Transformer;

Transformer.TransformError = TransformError;

function TransformError() {
  Error.captureStackTrace && Error.captureStackTrace(this, TransformError);
}
util.inherits(TransformError, SyntaxError);

function formatError(err, filename, source) {
  if (err.loc) {
    return formatBabelError(err, filename, source);
  } else {
    return formatGenericError(err, filename, source);
  }
}

function formatGenericError(err, filename) {
  var msg = 'TransformError: ' + filename + ': ' + err.message;
  var error = new TransformError();
  var stack = (err.stack || '').split('\n').slice(0, -1);
  stack.push(msg);
  error.stack = stack.join('\n');
  error.message = msg;
  error.type = 'TransformError';
  return error;
}

function formatBabelError(err, filename) {
  var error = new TransformError();
  error.type = 'TransformError';
  error.message = (err.type || error.type) + ' ' + err.message;
  error.stack = err.stack;
  error.snippet = err.codeFrame;
  error.lineNumber = err.loc.line;
  error.column = err.loc.column;
  error.filename = filename;
  error.description = err.message;
  return error;
}
<commit_msg>limit number of workers<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const ModuleTransport = require('../lib/ModuleTransport');
const Promise = require('promise');
const declareOpts = require('../lib/declareOpts');
const fs = require('fs');
const os = require('os');
const temp = require('temp');
const util = require('util');
const workerFarm = require('worker-farm');
const debug = require('debug')('ReactNativePackager:JStransformer');

const readFile = Promise.denodeify(fs.readFile);

// Avoid memory leaks caused in workers. This number seems to be a good enough number
// to avoid any memory leak while not slowing down initial builds.
// TODO(amasad): Once we get bundle splitting, we can drive this down a bit more.
const MAX_CALLS_PER_WORKER = 600;

// Worker will timeout if one of the callers timeout.
const DEFAULT_MAX_CALL_TIME = 301000;

// How may times can we tolerate failures from the worker.
const MAX_RETRIES = 2;

const validateOpts = declareOpts({
  projectRoots: {
    type: 'array',
    required: true,
  },
  blacklistRE: {
    type: 'object', // typeof regex is object
  },
  polyfillModuleNames: {
    type: 'array',
    default: [],
  },
  transformModulePath: {
    type:'string',
    required: false,
  },
  cache: {
    type: 'object',
    required: true,
  },
  transformTimeoutInterval: {
    type: 'number',
    default: DEFAULT_MAX_CALL_TIME,
  },
  disableInternalTransforms: {
    type: 'boolean',
    default: false,
  },
});

const maxConcurrentWorkers = ((cores, override) => {
  if (override) {
    return Math.min(cores, override);
  }

  if (cores < 3) {
    return cores;
  }
  if (cores < 8) {
    return Math.floor(cores * 0.75);
  }
  if (cores < 24) {
    return Math.floor(3/8 * cores + 3); // between cores *.75 and cores / 2
  }
  return cores / 2;
})(os.cpus().length, process.env.REACT_NATIVE_MAX_WORKERS);

class Transformer {
  constructor(options) {
    const opts = this._opts = validateOpts(options);

    this._cache = opts.cache;
    this._transformModulePath = opts.transformModulePath;
    this._projectRoots = opts.projectRoots;

    if (opts.transformModulePath != null) {
      let transformer;

      if (opts.disableInternalTransforms) {
        transformer = opts.transformModulePath;
      } else {
        transformer = this._workerWrapperPath = temp.path();
        fs.writeFileSync(
          this._workerWrapperPath,
          `
          module.exports = require(${JSON.stringify(require.resolve('./worker'))});
          require(${JSON.stringify(String(opts.transformModulePath))});
          `
        );
      }

      this._workers = workerFarm({
        autoStart: true,
        maxConcurrentCallsPerWorker: 1,
        maxConcurrentWorkers: maxConcurrentWorkers,
        maxCallsPerWorker: MAX_CALLS_PER_WORKER,
        maxCallTime: opts.transformTimeoutInterval,
        maxRetries: MAX_RETRIES,
      }, transformer);

      this._transform = Promise.denodeify(this._workers);
    }
  }

  kill() {
    this._workers && workerFarm.end(this._workers);
    if (this._workerWrapperPath &&
        typeof this._workerWrapperPath === 'string') {
      fs.unlink(this._workerWrapperPath, () => {}); // we don't care about potential errors here
    }
  }

  invalidateFile(filePath) {
    this._cache.invalidate(filePath);
  }

  loadFileAndTransform(filePath, options) {
    if (this._transform == null) {
      return Promise.reject(new Error('No transfrom module'));
    }

    debug('transforming file', filePath);

    const optionsJSON = JSON.stringify(options);

    return this._cache.get(
      filePath,
      'transformedSource-' + optionsJSON,
      // TODO: use fastfs to avoid reading file from disk again
      () => readFile(filePath).then(
        buffer => {
          const sourceCode = buffer.toString('utf8');

          return this._transform({
            sourceCode,
            filename: filePath,
            options: {
              ...options,
              projectRoots: this._projectRoots,
              externalTransformModulePath: this._transformModulePath,
            },
          }).then(res => {
            if (res.error) {
              console.warn(
                'Error property on the result value from the transformer',
                'module is deprecated and will be removed in future versions.',
                'Please pass an error object as the first argument to the callback'
              );
              throw formatError(res.error, filePath);
            }

            debug('done transforming file', filePath);

            return new ModuleTransport({
              code: res.code,
              map: res.map,
              sourcePath: filePath,
              sourceCode: sourceCode,
            });
          }).catch(err => {
            if (err.type === 'TimeoutError') {
              const timeoutErr = new Error(
                `TimeoutError: transforming ${filePath} took longer than ` +
                `${this._opts.transformTimeoutInterval / 1000} seconds.\n` +
                `You can adjust timeout via the 'transformTimeoutInterval' option`
              );
              timeoutErr.type = 'TimeoutError';
              throw timeoutErr;
            } else if (err.type === 'ProcessTerminatedError') {
              const uncaughtError = new Error(
                'Uncaught error in the transformer worker: ' +
                this._opts.transformModulePath
              );
              uncaughtError.type = 'ProcessTerminatedError';
              throw uncaughtError;
            }

            throw formatError(err, filePath);
          });
        })
    );
  }
}

module.exports = Transformer;

Transformer.TransformError = TransformError;

function TransformError() {
  Error.captureStackTrace && Error.captureStackTrace(this, TransformError);
}
util.inherits(TransformError, SyntaxError);

function formatError(err, filename, source) {
  if (err.loc) {
    return formatBabelError(err, filename, source);
  } else {
    return formatGenericError(err, filename, source);
  }
}

function formatGenericError(err, filename) {
  var msg = 'TransformError: ' + filename + ': ' + err.message;
  var error = new TransformError();
  var stack = (err.stack || '').split('\n').slice(0, -1);
  stack.push(msg);
  error.stack = stack.join('\n');
  error.message = msg;
  error.type = 'TransformError';
  return error;
}

function formatBabelError(err, filename) {
  var error = new TransformError();
  error.type = 'TransformError';
  error.message = (err.type || error.type) + ' ' + err.message;
  error.stack = err.stack;
  error.snippet = err.codeFrame;
  error.lineNumber = err.loc.line;
  error.column = err.loc.column;
  error.filename = filename;
  error.description = err.message;
  return error;
}
<|endoftext|>


<commit_before>console.log('Custom array order example:');

function apiCall(callback) {
  const policies = [
    { name: 'reports', readonly: true, editable: false },
    { name: 'dashboard', readonly: true, editable: true },
    { name: 'admin', readonly: false, editable: false }
  ];

  // Simulate an API call
  setTimeout(() => callback(policies), 300);
};

function getListForTable(callback) {
  apiCall((policies) => {
    // Make it ordered like the UI is. In a real application this information
    // could then be displayed in a permission table.
    const uiOrder = ['dashboard', 'reports', 'admin'];
    const orderMap = {};
    uiOrder.forEach((name, index) => orderMap[name] = index);

    const orderedPolicies = [];
    policies.forEach((policy) => {
      const position = orderMap[policy.name];
      orderedPolicies[position] = policy;
    });

    callback(orderedPolicies)
  });
}

getListForTable((orderedPolicies) => {
  console.log('Ordered for the UI:');
  console.log(orderedPolicies);
  // [ { name: 'dashboard', readonly: true, editable: true },
  //   { name: 'reports', readonly: true, editable: false },
  //   { name: 'admin', readonly: false, editable: false } ]
});
<commit_msg>Update customArrayOrder.js<commit_after>console.log('Custom array order example:');

function apiCall(callback) {
  const policies = [
    { name: 'reports', readonly: true, editable: false },
    { name: 'dashboard', readonly: true, editable: true },
    { name: 'admin', readonly: false, editable: false }
  ];

  // Simulate an API call
  setTimeout(() => callback(policies), 300);
};

function getListForTable(callback) {
  apiCall((policies) => {
    // Make it ordered like the UI is. In a real application this information
    // could then be displayed in a permission table.
    const uiOrder = ['dashboard', 'reports', 'admin'];
    //     const orderMap = {};
    //     uiOrder.forEach((name, index) => orderMap[name] = index);

    const orderedPolicies = [];
    policies.forEach((policy) => {
      const position = uiOrder.indexOf(policy.name); // skip orderMap
      orderedPolicies[position] = policy;
    });

    callback(orderedPolicies)
  });
}

getListForTable((orderedPolicies) => {
  console.log('Ordered for the UI:');
  console.log(orderedPolicies);
  // [ { name: 'dashboard', readonly: true, editable: true },
  //   { name: 'reports', readonly: true, editable: false },
  //   { name: 'admin', readonly: false, editable: false } ]
});
<|endoftext|>