<commit_before>goog.provide('ol.geom.Circle');

goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat');

/**
 * @constructor
 * @extends {ol.geom.SimpleGeometry}
 * @param {ol.geom.RawPoint} center Center.
 * @param {number=} opt_radius Radius.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 */
ol.geom.Circle = function(center, opt_radius, opt_layout) {
  goog.base(this);
  var radius = goog.isDef(opt_radius) ? opt_radius : 0;
  this.setCenterAndRadius(center, radius, opt_layout);
};
goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.clone = function() {
  var circle = new ol.geom.Circle(null);
  circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
  return circle;
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.closestPointXY =
    function(x, y, closestPoint, minSquaredDistance) {
  var flatCoordinates = this.flatCoordinates;
  var dx = x - flatCoordinates[0];
  var dy = y - flatCoordinates[1];
  var squaredDistance = dx * dx + dy * dy;
  if (squaredDistance < minSquaredDistance) {
    var i;
    if (squaredDistance === 0) {
      for (i = 0; i < this.stride; ++i) {
        closestPoint[i] = flatCoordinates[i];
      }
    } else {
      var delta = this.getRadius() / Math.sqrt(squaredDistance);
      closestPoint[0] = flatCoordinates[0] + delta * dx;
      closestPoint[1] = flatCoordinates[1] + delta * dy;
      for (i = 2; i < this.stride; ++i) {
        closestPoint[i] = flatCoordinates[i];
      }
    }
    closestPoint.length = this.stride;
    return squaredDistance;
  } else {
    return minSquaredDistance;
  }
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.containsXY = function(x, y) {
  var flatCoordinates = this.flatCoordinates;
  var dx = x - flatCoordinates[0];
  var dy = y - flatCoordinates[1];
  var r = flatCoordinates[this.stride] - flatCoordinates[0];
  return Math.sqrt(dx * dx + dy * dy) <= r;
};

/**
 * @return {ol.geom.RawPoint} Center.
 */
ol.geom.Circle.prototype.getCenter = function() {
  return this.flatCoordinates.slice(0, this.stride);
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getExtent = function(opt_extent) {
  if (this.extentRevision != this.getRevision()) {
    var flatCoordinates = this.flatCoordinates;
    var radius = flatCoordinates[this.stride] - flatCoordinates[0];
    this.extent = ol.extent.createOrUpdate(
        flatCoordinates[0] - radius, flatCoordinates[1] - radius,
        flatCoordinates[0] + radius, flatCoordinates[1] + radius,
        this.extent);
    this.extentRevision = this.getRevision();
  }
  goog.asserts.assert(goog.isDef(this.extent));
  return ol.extent.returnOrUpdate(this.extent, opt_extent);
};

/**
 * @return {number} Radius.
 */
ol.geom.Circle.prototype.getRadius = function() {
  var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
  var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
  return Math.sqrt(dx * dx + dy * dy);
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getSimplifiedGeometry = function(squaredTolerance) {
  return this;
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getType = function() {
  return ol.geom.GeometryType.CIRCLE;
};

/**
 * @param {ol.geom.RawPoint} center Center.
 */
ol.geom.Circle.prototype.setCenter = function(center) {
  var stride = this.stride;
  goog.asserts.assert(center.length == stride);
  var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
  var flatCoordinates = center.slice();
  flatCoordinates[stride] = flatCoordinates[0] + radius;
  var i;
  for (i = 1; i < stride; ++i) {
    flatCoordinates[stride + i] = center[i];
  }
  this.setFlatCoordinates(this.layout, flatCoordinates);
};

/**
 * @param {ol.geom.RawPoint} center Center.
 * @param {number} radius Radius.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 */
ol.geom.Circle.prototype.setCenterAndRadius =
    function(center, radius, opt_layout) {
  if (goog.isNull(center)) {
    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
  } else {
    this.setLayout(opt_layout, center, 0);
    if (goog.isNull(this.flatCoordinates)) {
      this.flatCoordinates = [];
    }
    /** @type {Array.<number>} */
    var flatCoordinates = this.flatCoordinates;
    var offset = ol.geom.flat.deflateCoordinate(
        flatCoordinates, 0, center, this.stride);
    flatCoordinates[offset++] = flatCoordinates[0] + radius;
    var i, ii;
    for (i = 1, ii = this.stride; i < ii; ++i) {
      flatCoordinates[offset++] = flatCoordinates[i];
    }
    flatCoordinates.length = offset;
    this.dispatchChangeEvent();
  }
};

/**
 * @param {ol.geom.GeometryLayout} layout Layout.
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 */
ol.geom.Circle.prototype.setFlatCoordinates =
    function(layout, flatCoordinates) {
  this.setFlatCoordinatesInternal(layout, flatCoordinates);
  this.dispatchChangeEvent();
};

/**
 * @param {number} radius Radius.
 */
ol.geom.Circle.prototype.setRadius = function(radius) {
  goog.asserts.assert(!goog.isNull(this.flatCoordinates));
  this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
  this.dispatchChangeEvent();
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.transform = goog.abstractMethod;
<commit_msg>Add stability annotation to ol.geom.Circle<commit_after>goog.provide('ol.geom.Circle');

goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat');

/**
 * @constructor
 * @extends {ol.geom.SimpleGeometry}
 * @param {ol.geom.RawPoint} center Center.
 * @param {number=} opt_radius Radius.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @todo stability experimental
 */
ol.geom.Circle = function(center, opt_radius, opt_layout) {
  goog.base(this);
  var radius = goog.isDef(opt_radius) ? opt_radius : 0;
  this.setCenterAndRadius(center, radius, opt_layout);
};
goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.clone = function() {
  var circle = new ol.geom.Circle(null);
  circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
  return circle;
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.closestPointXY =
    function(x, y, closestPoint, minSquaredDistance) {
  var flatCoordinates = this.flatCoordinates;
  var dx = x - flatCoordinates[0];
  var dy = y - flatCoordinates[1];
  var squaredDistance = dx * dx + dy * dy;
  if (squaredDistance < minSquaredDistance) {
    var i;
    if (squaredDistance === 0) {
      for (i = 0; i < this.stride; ++i) {
        closestPoint[i] = flatCoordinates[i];
      }
    } else {
      var delta = this.getRadius() / Math.sqrt(squaredDistance);
      closestPoint[0] = flatCoordinates[0] + delta * dx;
      closestPoint[1] = flatCoordinates[1] + delta * dy;
      for (i = 2; i < this.stride; ++i) {
        closestPoint[i] = flatCoordinates[i];
      }
    }
    closestPoint.length = this.stride;
    return squaredDistance;
  } else {
    return minSquaredDistance;
  }
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.containsXY = function(x, y) {
  var flatCoordinates = this.flatCoordinates;
  var dx = x - flatCoordinates[0];
  var dy = y - flatCoordinates[1];
  var r = flatCoordinates[this.stride] - flatCoordinates[0];
  return Math.sqrt(dx * dx + dy * dy) <= r;
};

/**
 * @return {ol.geom.RawPoint} Center.
 * @todo stability experimental
 */
ol.geom.Circle.prototype.getCenter = function() {
  return this.flatCoordinates.slice(0, this.stride);
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getExtent = function(opt_extent) {
  if (this.extentRevision != this.getRevision()) {
    var flatCoordinates = this.flatCoordinates;
    var radius = flatCoordinates[this.stride] - flatCoordinates[0];
    this.extent = ol.extent.createOrUpdate(
        flatCoordinates[0] - radius, flatCoordinates[1] - radius,
        flatCoordinates[0] + radius, flatCoordinates[1] + radius,
        this.extent);
    this.extentRevision = this.getRevision();
  }
  goog.asserts.assert(goog.isDef(this.extent));
  return ol.extent.returnOrUpdate(this.extent, opt_extent);
};

/**
 * @return {number} Radius.
 * @todo stability experimental
 */
ol.geom.Circle.prototype.getRadius = function() {
  var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
  var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
  return Math.sqrt(dx * dx + dy * dy);
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getSimplifiedGeometry = function(squaredTolerance) {
  return this;
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.getType = function() {
  return ol.geom.GeometryType.CIRCLE;
};

/**
 * @param {ol.geom.RawPoint} center Center.
 * @todo stability experimental
 */
ol.geom.Circle.prototype.setCenter = function(center) {
  var stride = this.stride;
  goog.asserts.assert(center.length == stride);
  var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
  var flatCoordinates = center.slice();
  flatCoordinates[stride] = flatCoordinates[0] + radius;
  var i;
  for (i = 1; i < stride; ++i) {
    flatCoordinates[stride + i] = center[i];
  }
  this.setFlatCoordinates(this.layout, flatCoordinates);
};

/**
 * @param {ol.geom.RawPoint} center Center.
 * @param {number} radius Radius.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @todo stability experimental
 */
ol.geom.Circle.prototype.setCenterAndRadius =
    function(center, radius, opt_layout) {
  if (goog.isNull(center)) {
    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
  } else {
    this.setLayout(opt_layout, center, 0);
    if (goog.isNull(this.flatCoordinates)) {
      this.flatCoordinates = [];
    }
    /** @type {Array.<number>} */
    var flatCoordinates = this.flatCoordinates;
    var offset = ol.geom.flat.deflateCoordinate(
        flatCoordinates, 0, center, this.stride);
    flatCoordinates[offset++] = flatCoordinates[0] + radius;
    var i, ii;
    for (i = 1, ii = this.stride; i < ii; ++i) {
      flatCoordinates[offset++] = flatCoordinates[i];
    }
    flatCoordinates.length = offset;
    this.dispatchChangeEvent();
  }
};

/**
 * @param {ol.geom.GeometryLayout} layout Layout.
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 */
ol.geom.Circle.prototype.setFlatCoordinates =
    function(layout, flatCoordinates) {
  this.setFlatCoordinatesInternal(layout, flatCoordinates);
  this.dispatchChangeEvent();
};

/**
 * @param {number} radius Radius.
 * @todo stability experimental
 */
ol.geom.Circle.prototype.setRadius = function(radius) {
  goog.asserts.assert(!goog.isNull(this.flatCoordinates));
  this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
  this.dispatchChangeEvent();
};

/**
 * @inheritDoc
 */
ol.geom.Circle.prototype.transform = goog.abstractMethod;
<|endoftext|>


<commit_before>/**
 * @module ol/interaction
 */
import Collection from './Collection.js';
import DoubleClickZoom from './interaction/DoubleClickZoom.js';
import DragPan from './interaction/DragPan.js';
import DragRotate from './interaction/DragRotate.js';
import DragZoom from './interaction/DragZoom.js';
import KeyboardPan from './interaction/KeyboardPan.js';
import KeyboardZoom from './interaction/KeyboardZoom.js';
import Kinetic from './Kinetic.js';
import MouseWheelZoom from './interaction/MouseWheelZoom.js';
import PinchRotate from './interaction/PinchRotate.js';
import PinchZoom from './interaction/PinchZoom.js';

export {default as DoubleClickZoom} from './interaction/DoubleClickZoom.js';
export {default as DragAndDrop} from './interaction/DragAndDrop.js';
export {default as DragBox} from './interaction/DragBox.js';
export {default as DragPan} from './interaction/DragPan.js';
export {default as DragRotate} from './interaction/DragRotate.js';
export {default as DragRotateAndZoom} from './interaction/DragRotateAndZoom.js';
export {default as DragZoom} from './interaction/DragZoom.js';
export {default as Draw} from './interaction/Draw.js';
export {default as Extent} from './interaction/Extent.js';
export {default as Interaction} from './interaction/Interaction.js';
export {default as KeyboardPan} from './interaction/KeyboardPan.js';
export {default as KeyboardZoom} from './interaction/KeyboardZoom.js';
export {default as Modify} from './interaction/Modify.js';
export {default as MouseWheelZoom} from './interaction/MouseWheelZoom.js';
export {default as PinchRotate} from './interaction/PinchRotate.js';
export {default as PinchZoom} from './interaction/PinchZoom.js';
export {default as Pointer} from './interaction/Pointer.js';
export {default as Select} from './interaction/Select.js';
export {default as Snap} from './interaction/Snap.js';
export {default as Translate} from './interaction/Translate.js';

/**
 * @typedef {Object} DefaultsOptions
 * @property {boolean} [altShiftDragRotate=true] Whether Alt-Shift-drag rotate is
 * desired.
 * @property {boolean} [onFocusOnly=false] Interact only when the map has the
 * focus. This affects the `MouseWheelZoom` and `DragPan` interactions and is
 * useful when page scroll is desired for maps that do not have the browser's
 * focus.
 * @property {boolean} [doubleClickZoom=true] Whether double click zoom is
 * desired.
 * @property {boolean} [keyboard=true] Whether keyboard interaction is desired.
 * @property {boolean} [mouseWheelZoom=true] Whether mousewheel zoom is desired.
 * @property {boolean} [shiftDragZoom=true] Whether Shift-drag zoom is desired.
 * @property {boolean} [dragPan=true] Whether drag pan is desired.
 * @property {boolean} [pinchRotate=true] Whether pinch rotate is desired.
 * @property {boolean} [pinchZoom=true] Whether pinch zoom is desired.
 * @property {number} [zoomDelta] Zoom level delta when using keyboard or double click zoom.
 * @property {number} [zoomDuration] Duration of the zoom animation in
 * milliseconds.
 */

/**
 * Set of interactions included in maps by default. Specific interactions can be
 * excluded by setting the appropriate option to false in the constructor
 * options, but the order of the interactions is fixed.  If you want to specify
 * a different order for interactions, you will need to create your own
 * {@link module:ol/interaction/Interaction~Interaction} instances and insert
 * them into a {@link module:ol/Collection~Collection} in the order you want
 * before creating your {@link module:ol/Map~Map} instance. Changing the order can
 * be of interest if the event propagation needs to be stopped at a point.
 * The default set of interactions, in sequence, is:
 * * {@link module:ol/interaction/DragRotate~DragRotate}
 * * {@link module:ol/interaction/DoubleClickZoom~DoubleClickZoom}
 * * {@link module:ol/interaction/DragPan~DragPan}
 * * {@link module:ol/interaction/PinchRotate~PinchRotate}
 * * {@link module:ol/interaction/PinchZoom~PinchZoom}
 * * {@link module:ol/interaction/KeyboardPan~KeyboardPan}
 * * {@link module:ol/interaction/KeyboardZoom~KeyboardZoom}
 * * {@link module:ol/interaction/MouseWheelZoom~MouseWheelZoom}
 * * {@link module:ol/interaction/DragZoom~DragZoom}
 *
 * @param {DefaultsOptions} [opt_options] Defaults options.
 * @return {import("./Collection.js").default<import("./interaction/Interaction.js").default>}
 * A collection of interactions to be used with the {@link module:ol/Map~Map}
 * constructor's `interactions` option.
 * @api
 */
export function defaults(opt_options) {
  const options = opt_options ? opt_options : {};

  const interactions = new Collection();

  const kinetic = new Kinetic(-0.005, 0.05, 100);

  const altShiftDragRotate =
    options.altShiftDragRotate !== undefined
      ? options.altShiftDragRotate
      : true;
  if (altShiftDragRotate) {
    interactions.push(new DragRotate());
  }

  const doubleClickZoom =
    options.doubleClickZoom !== undefined ? options.doubleClickZoom : true;
  if (doubleClickZoom) {
    interactions.push(
      new DoubleClickZoom({
        delta: options.zoomDelta,
        duration: options.zoomDuration,
      })
    );
  }

  const dragPan = options.dragPan !== undefined ? options.dragPan : true;
  if (dragPan) {
    interactions.push(
      new DragPan({
        onFocusOnly: options.onFocusOnly,
        kinetic: kinetic,
      })
    );
  }

  const pinchRotate =
    options.pinchRotate !== undefined ? options.pinchRotate : true;
  if (pinchRotate) {
    interactions.push(new PinchRotate());
  }

  const pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
  if (pinchZoom) {
    interactions.push(
      new PinchZoom({
        duration: options.zoomDuration,
      })
    );
  }

  const keyboard = options.keyboard !== undefined ? options.keyboard : true;
  if (keyboard) {
    interactions.push(new KeyboardPan());
    interactions.push(
      new KeyboardZoom({
        delta: options.zoomDelta,
        duration: options.zoomDuration,
      })
    );
  }

  const mouseWheelZoom =
    options.mouseWheelZoom !== undefined ? options.mouseWheelZoom : true;
  if (mouseWheelZoom) {
    interactions.push(
      new MouseWheelZoom({
        onFocusOnly: options.onFocusOnly,
        duration: options.zoomDuration,
      })
    );
  }

  const shiftDragZoom =
    options.shiftDragZoom !== undefined ? options.shiftDragZoom : true;
  if (shiftDragZoom) {
    interactions.push(
      new DragZoom({
        duration: options.zoomDuration,
      })
    );
  }

  return interactions;
}
<commit_msg>Re-export the link interaction from the interactions module<commit_after>/**
 * @module ol/interaction
 */
import Collection from './Collection.js';
import DoubleClickZoom from './interaction/DoubleClickZoom.js';
import DragPan from './interaction/DragPan.js';
import DragRotate from './interaction/DragRotate.js';
import DragZoom from './interaction/DragZoom.js';
import KeyboardPan from './interaction/KeyboardPan.js';
import KeyboardZoom from './interaction/KeyboardZoom.js';
import Kinetic from './Kinetic.js';
import MouseWheelZoom from './interaction/MouseWheelZoom.js';
import PinchRotate from './interaction/PinchRotate.js';
import PinchZoom from './interaction/PinchZoom.js';

export {default as DoubleClickZoom} from './interaction/DoubleClickZoom.js';
export {default as DragAndDrop} from './interaction/DragAndDrop.js';
export {default as DragBox} from './interaction/DragBox.js';
export {default as DragPan} from './interaction/DragPan.js';
export {default as DragRotate} from './interaction/DragRotate.js';
export {default as DragRotateAndZoom} from './interaction/DragRotateAndZoom.js';
export {default as DragZoom} from './interaction/DragZoom.js';
export {default as Draw} from './interaction/Draw.js';
export {default as Extent} from './interaction/Extent.js';
export {default as Interaction} from './interaction/Interaction.js';
export {default as KeyboardPan} from './interaction/KeyboardPan.js';
export {default as KeyboardZoom} from './interaction/KeyboardZoom.js';
export {default as Link} from './interaction/Link.js';
export {default as Modify} from './interaction/Modify.js';
export {default as MouseWheelZoom} from './interaction/MouseWheelZoom.js';
export {default as PinchRotate} from './interaction/PinchRotate.js';
export {default as PinchZoom} from './interaction/PinchZoom.js';
export {default as Pointer} from './interaction/Pointer.js';
export {default as Select} from './interaction/Select.js';
export {default as Snap} from './interaction/Snap.js';
export {default as Translate} from './interaction/Translate.js';

/**
 * @typedef {Object} DefaultsOptions
 * @property {boolean} [altShiftDragRotate=true] Whether Alt-Shift-drag rotate is
 * desired.
 * @property {boolean} [onFocusOnly=false] Interact only when the map has the
 * focus. This affects the `MouseWheelZoom` and `DragPan` interactions and is
 * useful when page scroll is desired for maps that do not have the browser's
 * focus.
 * @property {boolean} [doubleClickZoom=true] Whether double click zoom is
 * desired.
 * @property {boolean} [keyboard=true] Whether keyboard interaction is desired.
 * @property {boolean} [mouseWheelZoom=true] Whether mousewheel zoom is desired.
 * @property {boolean} [shiftDragZoom=true] Whether Shift-drag zoom is desired.
 * @property {boolean} [dragPan=true] Whether drag pan is desired.
 * @property {boolean} [pinchRotate=true] Whether pinch rotate is desired.
 * @property {boolean} [pinchZoom=true] Whether pinch zoom is desired.
 * @property {number} [zoomDelta] Zoom level delta when using keyboard or double click zoom.
 * @property {number} [zoomDuration] Duration of the zoom animation in
 * milliseconds.
 */

/**
 * Set of interactions included in maps by default. Specific interactions can be
 * excluded by setting the appropriate option to false in the constructor
 * options, but the order of the interactions is fixed.  If you want to specify
 * a different order for interactions, you will need to create your own
 * {@link module:ol/interaction/Interaction~Interaction} instances and insert
 * them into a {@link module:ol/Collection~Collection} in the order you want
 * before creating your {@link module:ol/Map~Map} instance. Changing the order can
 * be of interest if the event propagation needs to be stopped at a point.
 * The default set of interactions, in sequence, is:
 * * {@link module:ol/interaction/DragRotate~DragRotate}
 * * {@link module:ol/interaction/DoubleClickZoom~DoubleClickZoom}
 * * {@link module:ol/interaction/DragPan~DragPan}
 * * {@link module:ol/interaction/PinchRotate~PinchRotate}
 * * {@link module:ol/interaction/PinchZoom~PinchZoom}
 * * {@link module:ol/interaction/KeyboardPan~KeyboardPan}
 * * {@link module:ol/interaction/KeyboardZoom~KeyboardZoom}
 * * {@link module:ol/interaction/MouseWheelZoom~MouseWheelZoom}
 * * {@link module:ol/interaction/DragZoom~DragZoom}
 *
 * @param {DefaultsOptions} [opt_options] Defaults options.
 * @return {import("./Collection.js").default<import("./interaction/Interaction.js").default>}
 * A collection of interactions to be used with the {@link module:ol/Map~Map}
 * constructor's `interactions` option.
 * @api
 */
export function defaults(opt_options) {
  const options = opt_options ? opt_options : {};

  const interactions = new Collection();

  const kinetic = new Kinetic(-0.005, 0.05, 100);

  const altShiftDragRotate =
    options.altShiftDragRotate !== undefined
      ? options.altShiftDragRotate
      : true;
  if (altShiftDragRotate) {
    interactions.push(new DragRotate());
  }

  const doubleClickZoom =
    options.doubleClickZoom !== undefined ? options.doubleClickZoom : true;
  if (doubleClickZoom) {
    interactions.push(
      new DoubleClickZoom({
        delta: options.zoomDelta,
        duration: options.zoomDuration,
      })
    );
  }

  const dragPan = options.dragPan !== undefined ? options.dragPan : true;
  if (dragPan) {
    interactions.push(
      new DragPan({
        onFocusOnly: options.onFocusOnly,
        kinetic: kinetic,
      })
    );
  }

  const pinchRotate =
    options.pinchRotate !== undefined ? options.pinchRotate : true;
  if (pinchRotate) {
    interactions.push(new PinchRotate());
  }

  const pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
  if (pinchZoom) {
    interactions.push(
      new PinchZoom({
        duration: options.zoomDuration,
      })
    );
  }

  const keyboard = options.keyboard !== undefined ? options.keyboard : true;
  if (keyboard) {
    interactions.push(new KeyboardPan());
    interactions.push(
      new KeyboardZoom({
        delta: options.zoomDelta,
        duration: options.zoomDuration,
      })
    );
  }

  const mouseWheelZoom =
    options.mouseWheelZoom !== undefined ? options.mouseWheelZoom : true;
  if (mouseWheelZoom) {
    interactions.push(
      new MouseWheelZoom({
        onFocusOnly: options.onFocusOnly,
        duration: options.zoomDuration,
      })
    );
  }

  const shiftDragZoom =
    options.shiftDragZoom !== undefined ? options.shiftDragZoom : true;
  if (shiftDragZoom) {
    interactions.push(
      new DragZoom({
        duration: options.zoomDuration,
      })
    );
  }

  return interactions;
}
<|endoftext|>


<commit_before>function sendRequestWithKey(page, key, listview) {
    username = appcan.locStorage.val("username");
    appcan.request.post(search_answer_url, {
        "title" : key,
        "username" : username
    }, function(data) {
        data = dealwithResult(data);

        appcan.locStorage.val("resultlist", data);
        //uexLoadingView.close();
        appcan.openWinWithUrl("searchresult", "searchresult.html");
    });
    /*var jsonstr = {
        "x" : 200,
        "y" : 500,
        "w" : 240,
        "h" : 40,
        "style" : {
            "styleId" : 0,
            "pointNum" : 4,
            "pointColor" : ["#ff4444", "#ffbb33", "#99cc00", "#33b5e5"]
        }
    };

    uexLoadingView.open(jsonstr);
*/
}

function dealwithResult(data) {
    var response,
        object,
        list,
        text = {
        title : "",
        describe : "",
        id : ""
    },
        resultData = [];
    var len = data.length;
    var i,
        j;
    for ( i = 0; i < len; i++)
        if (data[i] == '[')
            break;
    for ( j = len - 1; j >= 0; j--)
        if (data[j] == ']')
            break;
    data = data.substring(i, j + 1);
    var data = eval(data);
    len = data.length;
    for ( i = 0; i < len; i++) {
        var text = {
            title : "",
            describe : "",
            id : ""
        };
        text.title = data[i].title;
        text.describe = data[i].summary;
        text.id = data[i].link;
        if (text["id"].search(/http:\/\/blog.csdn.net/) != -1)
            resultData.push(text);
    }
    return resultData;
}

function sendRequestWithDetailPage(link) {
    link = link.replace(/http:\/\/blog.csdn.net/, "");

    appcan.request.post(get_detail_url, {
        "link" : link
    }, function(data) {
        data = dealwithDetailPage(data);
        appcan.locStorage.val("content", data);
        appcan.openWinWithUrl("details", "details.html");
    });
}

function dealwithDetailPage(data) {
    var len = data.length;
    var i,
        j;
    for ( i = 0; i < len; i++)
        if (data[i] == '<')
            break;
    for ( j = len - 1; j >= 0; j--)
        if (data[j] == '>')
            break;
    data = data.substring(i, j + 1);
    return data;
}<commit_msg>parse<commit_after>function sendRequestWithKey(page, key, listview) {
    username = appcan.locStorage.val("username");
    appcan.request.post(search_answer_url, {
        "title" : key,
        "username" : username
    }, function(data) {
        data = dealwithResult(data);

        appcan.locStorage.val("resultlist", data);
        //uexLoadingView.close();
        appcan.openWinWithUrl("searchresult", "searchresult.html");
    });
    /*var jsonstr = {
        "x" : 200,
        "y" : 500,
        "w" : 240,
        "h" : 40,
        "style" : {
            "styleId" : 0,
            "pointNum" : 4,
            "pointColor" : ["#ff4444", "#ffbb33", "#99cc00", "#33b5e5"]
        }
    };

    uexLoadingView.open(jsonstr);
*/
}

function dealwithResult(data) {
    var response,
        object,
        list,
        text = {
        title : "",
        describe : "",
        id : ""
    },
        resultData = [];
    var len = data.length;
    var i,
        j;
    for ( i = 0; i < len; i++)
        if (data[i] == '[')
            break;
    for ( j = len - 1; j >= 0; j--)
        if (data[j] == ']')
            break;
    data = data.substring(i, j + 1);
    var data = eval(data);
    len = data.length;
    for ( i = 0; i < len; i++) {
        var text = {
            title : "",
            describe : "",
            id : ""
        };
        text.title = data[i].title;
        text.describe = data[i].summary;
        text.id = data[i].link;
        if (text["id"].search(/http:\/\/blog.csdn.net/) != -1)
            resultData.push(text);
    }
    return resultData;
}

function sendRequestWithDetailPage(link) {
    link = link.replace(/http:\/\/blog.csdn.net/, "");

    appcan.request.post(get_detail_url, {
        "link" : link
    }, function(data) {
        data = JSON.parse(data);
        //data = dealwithDetailPage(data.toString());
        appcan.locStorage.val("content", data);
        appcan.openWinWithUrl("details", "details.html");
    });
}

function dealwithDetailPage(data) {
    var len = data.length;
    var i,
        j;
    for ( i = 0; i < len; i++)
        if (data[i] == '<')
            break;
    for ( j = len - 1; j >= 0; j--)
        if (data[j] == '>')
            break;
    data = data.substring(i, j + 1);
    return data;
}<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async');
var t = require('./titanic');
var krun = require('./krun');
var ice = require('./iceberg.js');
var path = require('path');
var Promise = require('bluebird');

/*
 * Init the kbox config.
 */
var config = new Promise(function(fulfill, reject) {

  krun()
  .run('kbox config', 30).ok()
  .call(function(next) {
    var json = JSON.parse(this.output);
    fulfill(json);
  });

}).timeout(30 * 1000, 'loading config');

/*
 * Get app code directory.
 */
var codeDir = config.then(function(config) {
  return path.join(config.appsRoot, 'foo', 'code');
});

/*
 * Take kbox in any state and fix it.
 */
var restore = function(done) {
  krun()
  // Make sure kbox is in a good state.
  .run('kbox status', 30).ok()
  .call(function(next) {
    if (this.output === 'down\n') {
      krun()
      .run('kbox up', 60).ok()
      .run('kbox status', 30).ok().expect('up\n')
      .done(next);
    } else {
      next();
    }
  })
  // Make sure app is in a good state.
  .call(function(next) {
    krun()
    // Install app.
    .run('kbox apps').ok()
    .call(function(cb) {
      var apps = JSON.parse(this.output);
      var notInstalled = apps.foo.total === 0;
      if (notInstalled) {
        krun()
        .run('kbox foo install', 120).ok()
        .done(cb);
      } else {
        cb();
      }
    })
    // Start app.
    .run('kbox apps').ok()
    .call(function(cb) {
      var apps = JSON.parse(this.output);
      if (apps.foo.running === 0) {
        krun()
        .run('kbox foo start', 180).ok()
        .done(cb);
      } else {
        cb();
      }
    })
    .done(next);
  })
  .done(done);
};

// ACTION: kbox down.
t.addAction(function(done) {
  krun()
  .run('kbox down').ok()
  .call(restore)
  .done(done);
});

// ACTION: stop app.
t.addAction(function(done) {
  krun()
  .run('kbox foo stop', 60).ok()
  .call(restore)
  .done(done);
});

// ACTION: restart app.
t.addAction(function(done) {
  krun()
  .run('kbox foo restart', 180).ok()
  .done(done);
});

// ACTION: uninstall app.
t.addAction(function(done) {
  krun()
  .run('kbox foo stop', 60).ok()
  .run('kbox foo uninstall').ok()
  .call(restore)
  .done(done);
});

// CHECK: kbox is up.
t.addCheck(function(done) {
  krun()
  .run('kbox status', 30)
  .ok()
  .expect('up\n')
  .done(done);
});

// CHECK: kbox apps
t.addCheck(function(done) {
  krun().run('kbox apps', 20).ok().done(done);
});

// CHECK: kbox config
t.addCheck(function(done) {
  krun().run('kbox config', 20).ok().done(done);
});

// CHECK: kbox containers
t.addCheck(function(done) {
  krun().run('kbox containers', 20).ok().done(done);
});

// CHECK: kbox ip
t.addCheck(function(done) {
  krun().run('kbox ip', 20).ok().done(done);
});

// CHECK: kbox version
t.addCheck(function(done) {
  krun().run('kbox version', 20).ok().done(done);
});

// CHECK: app is installed and running.
t.addCheck(function(done) {
  krun()
  .run('kbox apps').ok()
  .call(function(next) {
    var apps = JSON.parse(this.output);
    if (apps.foo.total !== 3 || apps.foo.running !== 2) {
      throw new Error(apps);
    } else {
      next();
    }
  })
  .done(done);
});

var addSyncthingCheck = function(inSeries) {

  // CHECK: syncthing test
  t.addCheck(function(done) {

    var tests = _.random(1, 10);

    var shouldContinue = function() {
      tests -= 1;
      return tests === 0;
    };

    var test = function(next) {
      config.then(function(config) {
        var dir = path.join(config.appsRoot, 'foo', 'code');
        return ice.local(dir)
        .init()
        .toRemote('kb_foo_appserver')
        .untilEqual(30)
        .remove()
        .exists()
        .call(function(done) {
          if (this.exists) {
            throw new Error('file still exists!');
          }
          done();
        })
        .promise();
      })
      .timeout(120 * 1000, 'while testing syncthing')
      .done(next, next);
    };

    if (inSeries) {
      async.doUntil(test, shouldContinue, done);
    } else {
      var testsToRun = _.fill(Array(tests), test);
      async.parallel(testsToRun, done);
    }

  });

};

// CHECK: syncthing in series check
addSyncthingCheck(true);

// CHECK: syncthing in parallel check
addSyncthingCheck(false);

// CHECK: file editing
t.addCheck(function(done) {

  var maxTimes = 5;

  var timeout = 15;

  var test = function(next) {
    codeDir.then(function(dir) {
      return ice.local(dir)
      .init()
      .toRemote('kb_foo_appserver')
      .untilEqual(45)
      .edit()
      .untilEqual(timeout)
      .edit()
      .untilEqual(timeout)
      .edit()
      .untilEqual(timeout)
      .remove()
      .exists()
      .call(function(done) {
        if (this.exists) {
          throw new Error('file still exists!');
        }
        done();
      })
      .promise();
    })
    .done(next, next);
  };

  async.timesSeries(_.random(1, maxTimes),
  function(n, next) {
    test(next);
  },
  done);
});

var runs = 1;
var cursor = 0;

var keepGoing = function() {

  cursor += 1;
  return cursor <= runs;

};

restore(function(err) {

  if (err) {
    throw err;
  }

  t.run(keepGoing, function(err) {

    if (err) {
      console.log('there was an error :(');
      throw err;
    }

    console.log('finished testing!!!');

  });

});
<commit_msg>Upping number of runs in functional testing.<commit_after>var _ = require('lodash');
var async = require('async');
var t = require('./titanic');
var krun = require('./krun');
var ice = require('./iceberg.js');
var path = require('path');
var Promise = require('bluebird');

/*
 * Init the kbox config.
 */
var config = new Promise(function(fulfill, reject) {

  krun()
  .run('kbox config', 30).ok()
  .call(function(next) {
    var json = JSON.parse(this.output);
    fulfill(json);
  });

}).timeout(30 * 1000, 'loading config');

/*
 * Get app code directory.
 */
var codeDir = config.then(function(config) {
  return path.join(config.appsRoot, 'foo', 'code');
});

/*
 * Take kbox in any state and fix it.
 */
var restore = function(done) {
  krun()
  // Make sure kbox is in a good state.
  .run('kbox status', 30).ok()
  .call(function(next) {
    if (this.output === 'down\n') {
      krun()
      .run('kbox up', 60).ok()
      .run('kbox status', 30).ok().expect('up\n')
      .done(next);
    } else {
      next();
    }
  })
  // Make sure app is in a good state.
  .call(function(next) {
    krun()
    // Install app.
    .run('kbox apps').ok()
    .call(function(cb) {
      var apps = JSON.parse(this.output);
      var notInstalled = apps.foo.total === 0;
      if (notInstalled) {
        krun()
        .run('kbox foo install', 120).ok()
        .done(cb);
      } else {
        cb();
      }
    })
    // Start app.
    .run('kbox apps').ok()
    .call(function(cb) {
      var apps = JSON.parse(this.output);
      if (apps.foo.running === 0) {
        krun()
        .run('kbox foo start', 180).ok()
        .done(cb);
      } else {
        cb();
      }
    })
    .done(next);
  })
  .done(done);
};

// ACTION: kbox down.
t.addAction(function(done) {
  krun()
  .run('kbox down').ok()
  .call(restore)
  .done(done);
});

// ACTION: stop app.
t.addAction(function(done) {
  krun()
  .run('kbox foo stop', 60).ok()
  .call(restore)
  .done(done);
});

// ACTION: restart app.
t.addAction(function(done) {
  krun()
  .run('kbox foo restart', 180).ok()
  .done(done);
});

// ACTION: uninstall app.
t.addAction(function(done) {
  krun()
  .run('kbox foo stop', 60).ok()
  .run('kbox foo uninstall').ok()
  .call(restore)
  .done(done);
});

// CHECK: kbox is up.
t.addCheck(function(done) {
  krun()
  .run('kbox status', 30)
  .ok()
  .expect('up\n')
  .done(done);
});

// CHECK: kbox apps
t.addCheck(function(done) {
  krun().run('kbox apps', 20).ok().done(done);
});

// CHECK: kbox config
t.addCheck(function(done) {
  krun().run('kbox config', 20).ok().done(done);
});

// CHECK: kbox containers
t.addCheck(function(done) {
  krun().run('kbox containers', 20).ok().done(done);
});

// CHECK: kbox ip
t.addCheck(function(done) {
  krun().run('kbox ip', 20).ok().done(done);
});

// CHECK: kbox version
t.addCheck(function(done) {
  krun().run('kbox version', 20).ok().done(done);
});

// CHECK: app is installed and running.
t.addCheck(function(done) {
  krun()
  .run('kbox apps').ok()
  .call(function(next) {
    var apps = JSON.parse(this.output);
    if (apps.foo.total !== 3 || apps.foo.running !== 2) {
      throw new Error(apps);
    } else {
      next();
    }
  })
  .done(done);
});

var addSyncthingCheck = function(inSeries) {

  // CHECK: syncthing test
  t.addCheck(function(done) {

    var tests = _.random(1, 10);

    var shouldContinue = function() {
      tests -= 1;
      return tests === 0;
    };

    var test = function(next) {
      config.then(function(config) {
        var dir = path.join(config.appsRoot, 'foo', 'code');
        return ice.local(dir)
        .init()
        .toRemote('kb_foo_appserver')
        .untilEqual(30)
        .remove()
        .exists()
        .call(function(done) {
          if (this.exists) {
            throw new Error('file still exists!');
          }
          done();
        })
        .promise();
      })
      .timeout(120 * 1000, 'while testing syncthing')
      .done(next, next);
    };

    if (inSeries) {
      async.doUntil(test, shouldContinue, done);
    } else {
      var testsToRun = _.fill(Array(tests), test);
      async.parallel(testsToRun, done);
    }

  });

};

// CHECK: syncthing in series check
addSyncthingCheck(true);

// CHECK: syncthing in parallel check
addSyncthingCheck(false);

// CHECK: file editing
t.addCheck(function(done) {

  var maxTimes = 5;

  var timeout = 15;

  var test = function(next) {
    codeDir.then(function(dir) {
      return ice.local(dir)
      .init()
      .toRemote('kb_foo_appserver')
      .untilEqual(45)
      .edit()
      .untilEqual(timeout)
      .edit()
      .untilEqual(timeout)
      .edit()
      .untilEqual(timeout)
      .remove()
      .exists()
      .call(function(done) {
        if (this.exists) {
          throw new Error('file still exists!');
        }
        done();
      })
      .promise();
    })
    .done(next, next);
  };

  async.timesSeries(_.random(1, maxTimes),
  function(n, next) {
    test(next);
  },
  done);
});

var runs = 25;
var cursor = 0;

var keepGoing = function() {

  cursor += 1;
  return cursor <= runs;

};

restore(function(err) {

  if (err) {
    throw err;
  }

  t.run(keepGoing, function(err) {

    if (err) {
      console.log('there was an error :(');
      throw err;
    }

    console.log('finished testing!!!');

  });

});
<|endoftext|>


<commit_before>/* global overpassFrontend:false */

var BoundingBox = require('boundingbox')
var twig = require('twig').twig
var OverpassFrontend = require('overpass-frontend')
var escapeHtml = require('html-escape')

function OverpassLayer (query, options) {
  var template

  if (!options) {
    options = {}
  }

  this.options = options

  this.query = query
  this.overpassFrontend = 'overpassFrontend' in this.options ? this.options.overpassFrontend : overpassFrontend
  this.options.style = 'style' in this.options ? this.options.style : {}
  this.options.minZoom = 'minZoom' in this.options ? this.options.minZoom : 16
  this.options.maxZoom = 'maxZoom' in this.options ? this.options.maxZoom : null
  this.options.featureTitle = 'featureTitle' in this.options ? this.options.featureTitle : function (ob) { return escapeHtml(ob.tags.name || ob.tags.operator || ob.tags.ref || ob.id) }
  this.options.featureBody = 'featureBody' in this.options ? this.options.featureBody : ''
  this.options.marker = 'marker' in this.options ? this.options.marker : null
  this.options.markerSign = 'markerSign' in this.options ? this.options.markerSign : null
  if (this.options.marker === null && this.options.markerSign !== null) {
    this.options.marker = {
        iconUrl: 'img/map_pointer.png',
        iconSize: [ 25, 42 ],
        iconAnchor: [ 13, 42 ]
    }
  }

  for (var k in this.options) {
    if (typeof this.options[k] === 'string') {
      template = twig({ data: this.options[k], autoescape: true })
      this.options[k] = function (template, ob) {
        return template.render(ob)
      }.bind(this, template)
    }
  }

  this.visibleFeatures = {}
  this.currentRequest = null
}

OverpassLayer.prototype.addTo = function (map) {
  this.map = map
  this.map.on('moveend', this.check_update_map, this)
  this.check_update_map()
}

OverpassLayer.prototype.remove = function () {
  var k
  var ob

  for (k in this.visibleFeatures) {
    ob = this.visibleFeatures[k]
    this.map.removeLayer(ob.feature)
    if (ob.featureMarker) {
      this.map.removeLayer(ob.featureMarker)
    }
  }

  this.visibleFeatures = {}

  this.map.off('moveend', this.check_update_map, this)
  this.map = null
}

OverpassLayer.prototype.check_update_map = function () {
  var bounds = new BoundingBox(this.map.getBounds())
  var k
  var ob

  if (this.map.getZoom() < this.options.minZoom ||
     (this.options.maxZoom !== null && this.map.getZoom() > this.options.maxZoom)) {
    for (k in this.visibleFeatures) {
      ob = this.visibleFeatures[k]

      if (this.onDisappear) {
        this.onDisappear(ob)
      }

      this.map.removeLayer(ob.feature)
      if (ob.featureMarker) {
        this.map.removeLayer(ob.featureMarker)
      }
    }

    this.visibleFeatures = {}

    // abort remaining request
    if (this.currentRequest) {
      this.currentRequest.abort()
      this.currentRequest = null
    }

    return
  }

  // Hide loaded but non-visible objects
  for (k in this.visibleFeatures) {
    ob = this.visibleFeatures[k]

    if (!ob.object.intersects(bounds)) {
      if (this.onDisappear) {
        this.onDisappear(ob)
      }

      this.map.removeLayer(ob.feature)
      if (ob.featureMarker) {
        this.map.removeLayer(ob.featureMarker)
      }
      delete this.visibleFeatures[k]
    }
  }

  // Abort current requests (in case they are long-lasting - we don't need them
  // anyway). Data which is being submitted will still be loaded to the cache.
  if (this.currentRequest) {
    this.currentRequest.abort()
    this.currentRequest = null
  }

  // Query all trees in the current view
  this.currentRequest = this.overpassFrontend.BBoxQuery(this.query, bounds,
    {
      properties: OverpassFrontend.ALL
    },
    function (err, ob) {
      if (!(ob.id in this.visibleFeatures)) {
        var data = this.processObject(ob)

        this.visibleFeatures[ob.id] = data

        data.feature.addTo(this.map)
        if (data.featureMarker) {
          data.featureMarker.addTo(this.map)
        }

        if (this.onAppear) {
          this.onAppear(data)
        }
      }
    }.bind(this),
    function (err) {
      if (err !== 'abort') {
        this.currentRequest = null
      }
    }.bind(this)
  )
}

OverpassLayer.prototype.processObject = function (ob) {
  var feature

  var objectData = {}
  for (var k in this.options) {
    if (typeof this.options[k] === 'function') {
      objectData[k] = this.options[k](ob)
    } else {
      objectData[k] = this.options[k]
    }
  }

  var style = objectData.style
  if (typeof style === 'string') {
    var str = style.split('\n')
    style = {}

    for (var i = 0; i < str.length; i++) {
      var m
      if ((m = str[i].match(/^\s*([a-zA-Z0-9_]+)\s*:\s*(.*)\s*$/))) {
        var v = m[2].trim()

        if (v.match(/^\-?[0-9]+(\.[0-9]+)?/)) {
          v = parseFloat(v)
        }

        style[m[1]] = v
      }
    }
  }

  feature = ob.leafletFeature(style)

  var featureMarker
  if (objectData.marker) {
    var markerHtml = ''
    if (objectData.markerSign) {
      markerHtml += '
' + objectData.markerSign + '
'
    }

    objectData.marker.html = markerHtml
    objectData.marker.className = 'overpass-layer-icon'
    var icon = L.divIcon(objectData.marker)

    featureMarker = L.marker(ob.center, { icon: icon })
  }

  var popupContent = ''
  popupContent += '
' + objectData.featureTitle + '
'
  popupContent += objectData.featureBody

  feature.bindPopup(popupContent)
  if (featureMarker) {
    featureMarker.bindPopup(popupContent)
  }

  return {
    id: ob.id,
    object: ob,
    data: objectData,
    feature: feature,
    featureMarker: featureMarker
  }
}

module.exports = OverpassLayer
<commit_msg>.get(): get processed object via id (e.g. 'n1234')<commit_after>/* global overpassFrontend:false */

var BoundingBox = require('boundingbox')
var twig = require('twig').twig
var OverpassFrontend = require('overpass-frontend')
var escapeHtml = require('html-escape')

function OverpassLayer (query, options) {
  var template

  if (!options) {
    options = {}
  }

  this.options = options

  this.query = query
  this.overpassFrontend = 'overpassFrontend' in this.options ? this.options.overpassFrontend : overpassFrontend
  this.options.style = 'style' in this.options ? this.options.style : {}
  this.options.minZoom = 'minZoom' in this.options ? this.options.minZoom : 16
  this.options.maxZoom = 'maxZoom' in this.options ? this.options.maxZoom : null
  this.options.featureTitle = 'featureTitle' in this.options ? this.options.featureTitle : function (ob) { return escapeHtml(ob.tags.name || ob.tags.operator || ob.tags.ref || ob.id) }
  this.options.featureBody = 'featureBody' in this.options ? this.options.featureBody : ''
  this.options.marker = 'marker' in this.options ? this.options.marker : null
  this.options.markerSign = 'markerSign' in this.options ? this.options.markerSign : null
  if (this.options.marker === null && this.options.markerSign !== null) {
    this.options.marker = {
        iconUrl: 'img/map_pointer.png',
        iconSize: [ 25, 42 ],
        iconAnchor: [ 13, 42 ]
    }
  }

  for (var k in this.options) {
    if (typeof this.options[k] === 'string') {
      template = twig({ data: this.options[k], autoescape: true })
      this.options[k] = function (template, ob) {
        return template.render(ob)
      }.bind(this, template)
    }
  }

  this.visibleFeatures = {}
  this.currentRequest = null
}

OverpassLayer.prototype.addTo = function (map) {
  this.map = map
  this.map.on('moveend', this.check_update_map, this)
  this.check_update_map()
}

OverpassLayer.prototype.remove = function () {
  var k
  var ob

  for (k in this.visibleFeatures) {
    ob = this.visibleFeatures[k]
    this.map.removeLayer(ob.feature)
    if (ob.featureMarker) {
      this.map.removeLayer(ob.featureMarker)
    }
  }

  this.visibleFeatures = {}

  this.map.off('moveend', this.check_update_map, this)
  this.map = null
}

OverpassLayer.prototype.check_update_map = function () {
  var bounds = new BoundingBox(this.map.getBounds())
  var k
  var ob

  if (this.map.getZoom() < this.options.minZoom ||
     (this.options.maxZoom !== null && this.map.getZoom() > this.options.maxZoom)) {
    for (k in this.visibleFeatures) {
      ob = this.visibleFeatures[k]

      if (this.onDisappear) {
        this.onDisappear(ob)
      }

      this.map.removeLayer(ob.feature)
      if (ob.featureMarker) {
        this.map.removeLayer(ob.featureMarker)
      }
    }

    this.visibleFeatures = {}

    // abort remaining request
    if (this.currentRequest) {
      this.currentRequest.abort()
      this.currentRequest = null
    }

    return
  }

  // Hide loaded but non-visible objects
  for (k in this.visibleFeatures) {
    ob = this.visibleFeatures[k]

    if (!ob.object.intersects(bounds)) {
      if (this.onDisappear) {
        this.onDisappear(ob)
      }

      this.map.removeLayer(ob.feature)
      if (ob.featureMarker) {
        this.map.removeLayer(ob.featureMarker)
      }
      delete this.visibleFeatures[k]
    }
  }

  // Abort current requests (in case they are long-lasting - we don't need them
  // anyway). Data which is being submitted will still be loaded to the cache.
  if (this.currentRequest) {
    this.currentRequest.abort()
    this.currentRequest = null
  }

  // Query all trees in the current view
  this.currentRequest = this.overpassFrontend.BBoxQuery(this.query, bounds,
    {
      properties: OverpassFrontend.ALL
    },
    function (err, ob) {
      if (!(ob.id in this.visibleFeatures)) {
        var data = this.processObject(ob)

        this.visibleFeatures[ob.id] = data

        data.feature.addTo(this.map)
        if (data.featureMarker) {
          data.featureMarker.addTo(this.map)
        }

        if (this.onAppear) {
          this.onAppear(data)
        }
      }
    }.bind(this),
    function (err) {
      if (err !== 'abort') {
        this.currentRequest = null
      }
    }.bind(this)
  )
}

OverpassLayer.prototype.processObject = function (ob) {
  var feature

  var objectData = {}
  for (var k in this.options) {
    if (typeof this.options[k] === 'function') {
      objectData[k] = this.options[k](ob)
    } else {
      objectData[k] = this.options[k]
    }
  }

  var style = objectData.style
  if (typeof style === 'string') {
    var str = style.split('\n')
    style = {}

    for (var i = 0; i < str.length; i++) {
      var m
      if ((m = str[i].match(/^\s*([a-zA-Z0-9_]+)\s*:\s*(.*)\s*$/))) {
        var v = m[2].trim()

        if (v.match(/^\-?[0-9]+(\.[0-9]+)?/)) {
          v = parseFloat(v)
        }

        style[m[1]] = v
      }
    }
  }

  feature = ob.leafletFeature(style)

  var featureMarker
  if (objectData.marker) {
    var markerHtml = ''
    if (objectData.markerSign) {
      markerHtml += '
' + objectData.markerSign + '
'
    }

    objectData.marker.html = markerHtml
    objectData.marker.className = 'overpass-layer-icon'
    var icon = L.divIcon(objectData.marker)

    featureMarker = L.marker(ob.center, { icon: icon })
  }

  var popupContent = ''
  popupContent += '
' + objectData.featureTitle + '
'
  popupContent += objectData.featureBody

  feature.bindPopup(popupContent)
  if (featureMarker) {
    featureMarker.bindPopup(popupContent)
  }

  return {
    id: ob.id,
    object: ob,
    data: objectData,
    feature: feature,
    featureMarker: featureMarker
  }
}

OverpassLayer.prototype.get = function (id, callback) {
  var done = false

  if (id in this.visibleFeatures) {
    callback(this.visibleFeatures[id])
    return
  }

  this.overpassFrontend.get(id,
    {
      properties: OverpassFrontend.ALL
    },
    function (err, ob) {
      if (err === null) {
        callback(err, this.processObject(ob))
      }

      done = true
    }.bind(this),
    function (err) {
      if (!done) {
        callback(err, null)
      }
    }
  )
}

module.exports = OverpassLayer
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-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.
 *
 * @flow
 */

import type { Manifest } from "./types.js";
import type PackageResolver from "./package-resolver.js";
import type { Reporter } from "kreporters";
import type Config from "./config.js";
import * as promise from "./util/promise.js";
import { entries } from "./util/misc.js";
import * as fs from "./util/fs.js";

let invariant = require("invariant");
let cmdShim   = promise.promisify(require("cmd-shim"));
let semver    = require("semver");
let path      = require("path");
let _         = require("lodash");

type DependencyPairs = Array<{
  dep: Manifest,
  loc: string
}>;

export default class PackageLinker {
  constructor(config: Config, resolver: PackageResolver) {
    this.resolver = resolver;
    this.reporter = config.reporter;
    this.config   = config;
  }

  reporter: Reporter;
  resolver: PackageResolver;
  config: Config;

  async linkSelfDependencies(pkg: Manifest, pkgLoc: string, targetBinLoc: string): Promise<void> {
    for (let [scriptName, scriptCmd] of entries(pkg.bin)) {
      let dest = path.join(targetBinLoc, scriptName);
      let src  = path.join(pkgLoc, scriptCmd);

      if (process.platform === "win32") {
        await cmdShim(src, dest);
      } else {
        await fs.symlink(src, dest);
        await fs.chmod(dest, "755");
      }
    }
  }

  async linkBinDependencies(deps: DependencyPairs, pkg: Manifest, dir: string): Promise<void> {
    let ref = pkg.reference;
    invariant(ref, "Package reference is missing");

    let remote = pkg.remote;
    invariant(remote, "Package remote is missing");

    // link up `bin scripts` in `dependencies`
    for (let pattern of ref.dependencies) {
      let dep = this.resolver.getResolvedPattern(pattern);
      if (!_.isEmpty(dep.bin)) {
        deps.push({ dep, loc: this.config.generateHardModulePath(dep.reference) });
      }
    }

    // link up the `bin` scripts in bundled dependencies
    if (pkg.bundleDependencies) {
      for (let depName of pkg.bundleDependencies) {
        let loc = path.join(this.config.generateHardModulePath(ref), await ref.getFolder(), depName);

        let dep = await this.config.readManifest(loc, remote.registry);

        if (!_.isEmpty(dep.bin)) {
          deps.push({ dep, loc });
        }
      }
    }

    // no deps to link
    if (!deps.length) return;

    // ensure our .bin file we're writing these to exists
    let binLoc = path.join(dir, ".bin");
    await fs.mkdirp(binLoc);

    // write the executables
    for (let { dep, loc } of deps) {
      await this.linkSelfDependencies(dep, loc, binLoc);
    }
  }

  async initCopyModules(patterns: Array<string>): Promise<void> {
    // we need to zip up the tree as we we're using it as a hash map and will be actively
    // removing and deleting keys during enumeration
    let zippedTree = [];
    let tree = Object.create(null);
    let self = this;

    let subPairs = new Map;

    //
    function add(pattern, parentParts) {
      if (parentParts.length >= 100) {
        throw new Error("cause we're in too deep");
      }

      let pkg = self.resolver.getResolvedPattern(pattern);
      let loc = self.config.generateHardModulePath(pkg.reference);

      //
      let ownParts = parentParts.slice();
      for (let i = ownParts.length; i >= 0; i--) {
        let checkParts = ownParts.slice(0, i).concat(pkg.name);
        let checkKey = checkParts.join("#");
        let check = tree[checkKey];
        if (check && check.loc === loc) return [];
      }
      ownParts.push(pkg.name);

      let key = ownParts.join("#");
      let info = {
        loc,
        pkg,
      };
      let pair = [key, info];

      zippedTree.push(pair);
      tree[key] = info;

      let results = [];

      // add dependencies
      for (let depPattern of pkg.reference.dependencies) {
        results = results.concat(add(depPattern, ownParts));
      }

      subPairs.set(info, results.slice());

      results.push(pair);

      return results;
    }

    for (let pattern of this.resolver.dedupePatterns(patterns)) {
      add(pattern, []);
    }

    // hoist tree
    hoist: for (let i = 0; i < zippedTree.length; i++) {
      let pair = zippedTree[i];
      let [key, info] = pair;

      let parts = key.split("#");
      let stack = []; // stack of removed parts

      // remove this item from the `tree` map so we can ignore it
      delete tree[key];

      // remove redundant parts that wont collide
      let name = parts.pop();
      while (parts.length) {
        let key = parts.concat(name).join("#");

        let existing = tree[key];
        if (existing) {
          if (existing.loc === info.loc) {
            continue hoist;
          } else {
            break;
          }
        }

        stack.push(parts.pop());
      }

      //
      parts.push(name);

      // we need to special case when we attempt to hoist to the top level as the `existing` logic
      // wont be hit in the above `while` loop
      let existing = tree[parts.join("#")];
      if (existing && existing.loc !== info.loc) {
        parts.pop();
        parts.push(stack.shift(), name);
      }

      // update to the new key
      let oldKey = key;
      let newKey = parts.join("#");
      tree[newKey] = info;
      pair[0] = newKey;

      // go through and update all transitive dependencies and update to new hoisting position
      let pairs = subPairs.get(info) || [];
      for (let pair of pairs) {
        let [subKey] = pair;

        if (subKey === newKey) continue;

        let newSubKey = subKey.replace(new RegExp(`^${oldKey}#`), `${newKey}#`);
        if (newSubKey === subKey) continue;

        tree[newSubKey] = tree[subKey];
        pair[0] = newSubKey;
        delete tree[subKey];
      }
    }

    //
    let flatTree = [];
    for (let key in tree) {
      let info = tree[key];
      let loc  = path.join(this.config.cwd, "node_modules", key.replace(/#/g, "/node_modules/"));
      flatTree.push([loc, info]);
    }

    //
    let tickCopyModule = this.reporter.progress(flatTree.length);
    await promise.queue(flatTree, async function ([dest, { pkg }]) {
      pkg.reference.setLocation(dest);
      await fs.mkdirp(dest);
    }, 4);

    // TODO concurrent copies can interfere when copying master and a sub dependency in parallel
    await promise.queue(flatTree, async function ([dest, { loc: src }]) {
      await fs.copy(src, dest);
      tickCopyModule(dest);
    }, 1);

    //
    let tickBin = this.reporter.progress(flatTree.length);
    await promise.queue(flatTree, async function ([dest, { pkg }]) {
      let binLoc = path.join(dest, "node_modules");
      await self.linkBinDependencies([], pkg, binLoc);
      tickBin(dest);
    }, 4);
  }

  async resolvePeerModules(pkg: Manifest): Promise<DependencyPairs> {
    let ref = pkg.reference;
    invariant(ref, "Package reference is missing");

    let deps = [];

    if (!pkg.peerDependencies) return deps;

    for (let name in pkg.peerDependencies) {
      let range = pkg.peerDependencies[name];

      // find a dependency in the tree above us that matches
      let searchPatterns: Array<string> = [];
      for (let request of ref.requests) {
        do {
          // get resolved pattern for this request
          let dep = this.resolver.getResolvedPattern(request.pattern);
          if (!dep) continue;

          //
          searchPatterns = searchPatterns.concat(dep.reference.dependencies);
        } while (request = request.parentRequest);
      }

      // include root seed patterns last
      searchPatterns = searchPatterns.concat(this.resolver.seedPatterns);

      // find matching dep in search patterns
      let foundDep: ?{ pattern: string, version: string, package: Manifest };
      for (let pattern of searchPatterns) {
        let dep = this.resolver.getResolvedPattern(pattern);
        if (dep && dep.name === name) {
          foundDep = { pattern, version: dep.version, package: dep };
          break;
        }
      }

      // validate found peer dependency
      if (foundDep) {
        if (range === "*" || semver.satisfies(range, foundDep.version)) {
          deps.push({
            pattern: foundDep.pattern,
            dep: foundDep.package,
            loc: this.config.generateHardModulePath(foundDep.package.reference)
          });
        } else {
          this.reporter.warn("TODO not match");
        }
      } else {
        this.reporter.warn("TODO missing dep");
      }
    }

    return deps;
  }

  async init(patterns: Array<string>): Promise<void> {
    await this.initCopyModules(patterns);
    await this.saveAll(patterns);
  }

  async save(pattern: string): Promise<void> {
    let resolved = this.resolver.getResolvedPattern(pattern);
    invariant(resolved, `Couldn't find resolved name/version for ${pattern}`);

    let ref = resolved.reference;
    invariant(ref, "Missing reference");

    //
    let src = this.config.generateHardModulePath(ref);
    // link bins
    if (!_.isEmpty(resolved.bin)) {
      let binLoc = path.join(this.config.cwd, await ref.getFolder(), ".bin");
      await fs.mkdirp(binLoc);
      await this.linkSelfDependencies(resolved, src, binLoc);
    }
  }

  async saveAll(deps: Array<string>): Promise<void> {
    deps = this.resolver.dedupePatterns(deps);
    let self = this;
    await promise.queue(deps, (dep) => self.save(dep));
  }
}
<commit_msg>pop rather than shift last part of tree heirarchy stack - fixes #67<commit_after>/**
 * Copyright (c) 2016-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.
 *
 * @flow
 */

import type { Manifest } from "./types.js";
import type PackageResolver from "./package-resolver.js";
import type { Reporter } from "kreporters";
import type Config from "./config.js";
import * as promise from "./util/promise.js";
import { entries } from "./util/misc.js";
import * as fs from "./util/fs.js";

let invariant = require("invariant");
let cmdShim   = promise.promisify(require("cmd-shim"));
let semver    = require("semver");
let path      = require("path");
let _         = require("lodash");

type DependencyPairs = Array<{
  dep: Manifest,
  loc: string
}>;

export default class PackageLinker {
  constructor(config: Config, resolver: PackageResolver) {
    this.resolver = resolver;
    this.reporter = config.reporter;
    this.config   = config;
  }

  reporter: Reporter;
  resolver: PackageResolver;
  config: Config;

  async linkSelfDependencies(pkg: Manifest, pkgLoc: string, targetBinLoc: string): Promise<void> {
    for (let [scriptName, scriptCmd] of entries(pkg.bin)) {
      let dest = path.join(targetBinLoc, scriptName);
      let src  = path.join(pkgLoc, scriptCmd);

      if (process.platform === "win32") {
        await cmdShim(src, dest);
      } else {
        await fs.symlink(src, dest);
        await fs.chmod(dest, "755");
      }
    }
  }

  async linkBinDependencies(deps: DependencyPairs, pkg: Manifest, dir: string): Promise<void> {
    let ref = pkg.reference;
    invariant(ref, "Package reference is missing");

    let remote = pkg.remote;
    invariant(remote, "Package remote is missing");

    // link up `bin scripts` in `dependencies`
    for (let pattern of ref.dependencies) {
      let dep = this.resolver.getResolvedPattern(pattern);
      if (!_.isEmpty(dep.bin)) {
        deps.push({ dep, loc: this.config.generateHardModulePath(dep.reference) });
      }
    }

    // link up the `bin` scripts in bundled dependencies
    if (pkg.bundleDependencies) {
      for (let depName of pkg.bundleDependencies) {
        let loc = path.join(this.config.generateHardModulePath(ref), await ref.getFolder(), depName);

        let dep = await this.config.readManifest(loc, remote.registry);

        if (!_.isEmpty(dep.bin)) {
          deps.push({ dep, loc });
        }
      }
    }

    // no deps to link
    if (!deps.length) return;

    // ensure our .bin file we're writing these to exists
    let binLoc = path.join(dir, ".bin");
    await fs.mkdirp(binLoc);

    // write the executables
    for (let { dep, loc } of deps) {
      await this.linkSelfDependencies(dep, loc, binLoc);
    }
  }

  async initCopyModules(patterns: Array<string>): Promise<void> {
    // we need to zip up the tree as we we're using it as a hash map and will be actively
    // removing and deleting keys during enumeration
    let zippedTree = [];
    let tree = Object.create(null);
    let self = this;

    let subPairs = new Map;

    //
    function add(pattern, parentParts) {
      if (parentParts.length >= 100) {
        throw new Error("cause we're in too deep");
      }

      let pkg = self.resolver.getResolvedPattern(pattern);
      let loc = self.config.generateHardModulePath(pkg.reference);

      //
      let ownParts = parentParts.slice();
      for (let i = ownParts.length; i >= 0; i--) {
        let checkParts = ownParts.slice(0, i).concat(pkg.name);
        let checkKey = checkParts.join("#");
        let check = tree[checkKey];
        if (check && check.loc === loc) return [];
      }
      ownParts.push(pkg.name);

      let key = ownParts.join("#");
      let info = {
        loc,
        pkg,
      };
      let pair = [key, info];

      zippedTree.push(pair);
      tree[key] = info;

      let results = [];

      // add dependencies
      for (let depPattern of pkg.reference.dependencies) {
        results = results.concat(add(depPattern, ownParts));
      }

      subPairs.set(info, results.slice());

      results.push(pair);

      return results;
    }

    for (let pattern of this.resolver.dedupePatterns(patterns)) {
      add(pattern, []);
    }

    // hoist tree
    hoist: for (let i = 0; i < zippedTree.length; i++) {
      let pair = zippedTree[i];
      let [key, info] = pair;

      let parts = key.split("#");
      let stack = []; // stack of removed parts

      // remove this item from the `tree` map so we can ignore it
      delete tree[key];

      // remove redundant parts that wont collide
      let name = parts.pop();
      while (parts.length) {
        let key = parts.concat(name).join("#");

        let existing = tree[key];
        if (existing) {
          if (existing.loc === info.loc) {
            continue hoist;
          } else {
            break;
          }
        }

        stack.push(parts.pop());
      }

      //
      parts.push(name);

      // we need to special case when we attempt to hoist to the top level as the `existing` logic
      // wont be hit in the above `while` loop
      let existing = tree[parts.join("#")];
      if (existing && existing.loc !== info.loc) {
        parts.pop();
        parts.push(stack.pop(), name);
      }

      // update to the new key
      let oldKey = key;
      let newKey = parts.join("#");
      tree[newKey] = info;
      pair[0] = newKey;

      // go through and update all transitive dependencies and update to new hoisting position
      let pairs = subPairs.get(info) || [];
      for (let pair of pairs) {
        let [subKey] = pair;

        if (subKey === newKey) continue;

        let newSubKey = subKey.replace(new RegExp(`^${oldKey}#`), `${newKey}#`);
        if (newSubKey === subKey) continue;

        tree[newSubKey] = tree[subKey];
        pair[0] = newSubKey;
        delete tree[subKey];
      }
    }

    //
    let flatTree = [];
    for (let key in tree) {
      let info = tree[key];
      let loc  = path.join(this.config.cwd, "node_modules", key.replace(/#/g, "/node_modules/"));
      flatTree.push([loc, info]);
    }

    //
    let tickCopyModule = this.reporter.progress(flatTree.length);
    await promise.queue(flatTree, async function ([dest, { pkg }]) {
      pkg.reference.setLocation(dest);
      await fs.mkdirp(dest);
    }, 4);

    // TODO concurrent copies can interfere when copying master and a sub dependency in parallel
    await promise.queue(flatTree, async function ([dest, { loc: src }]) {
      await fs.copy(src, dest);
      tickCopyModule(dest);
    }, 1);

    //
    let tickBin = this.reporter.progress(flatTree.length);
    await promise.queue(flatTree, async function ([dest, { pkg }]) {
      let binLoc = path.join(dest, "node_modules");
      await self.linkBinDependencies([], pkg, binLoc);
      tickBin(dest);
    }, 4);
  }

  async resolvePeerModules(pkg: Manifest): Promise<DependencyPairs> {
    let ref = pkg.reference;
    invariant(ref, "Package reference is missing");

    let deps = [];

    if (!pkg.peerDependencies) return deps;

    for (let name in pkg.peerDependencies) {
      let range = pkg.peerDependencies[name];

      // find a dependency in the tree above us that matches
      let searchPatterns: Array<string> = [];
      for (let request of ref.requests) {
        do {
          // get resolved pattern for this request
          let dep = this.resolver.getResolvedPattern(request.pattern);
          if (!dep) continue;

          //
          searchPatterns = searchPatterns.concat(dep.reference.dependencies);
        } while (request = request.parentRequest);
      }

      // include root seed patterns last
      searchPatterns = searchPatterns.concat(this.resolver.seedPatterns);

      // find matching dep in search patterns
      let foundDep: ?{ pattern: string, version: string, package: Manifest };
      for (let pattern of searchPatterns) {
        let dep = this.resolver.getResolvedPattern(pattern);
        if (dep && dep.name === name) {
          foundDep = { pattern, version: dep.version, package: dep };
          break;
        }
      }

      // validate found peer dependency
      if (foundDep) {
        if (range === "*" || semver.satisfies(range, foundDep.version)) {
          deps.push({
            pattern: foundDep.pattern,
            dep: foundDep.package,
            loc: this.config.generateHardModulePath(foundDep.package.reference)
          });
        } else {
          this.reporter.warn("TODO not match");
        }
      } else {
        this.reporter.warn("TODO missing dep");
      }
    }

    return deps;
  }

  async init(patterns: Array<string>): Promise<void> {
    await this.initCopyModules(patterns);
    await this.saveAll(patterns);
  }

  async save(pattern: string): Promise<void> {
    let resolved = this.resolver.getResolvedPattern(pattern);
    invariant(resolved, `Couldn't find resolved name/version for ${pattern}`);

    let ref = resolved.reference;
    invariant(ref, "Missing reference");

    //
    let src = this.config.generateHardModulePath(ref);
    // link bins
    if (!_.isEmpty(resolved.bin)) {
      let binLoc = path.join(this.config.cwd, await ref.getFolder(), ".bin");
      await fs.mkdirp(binLoc);
      await this.linkSelfDependencies(resolved, src, binLoc);
    }
  }

  async saveAll(deps: Array<string>): Promise<void> {
    deps = this.resolver.dedupePatterns(deps);
    let self = this;
    await promise.queue(deps, (dep) => self.save(dep));
  }
}
<|endoftext|>


<commit_before>chrome.commands.onCommand.addListener(dispatch);

function dispatch(command, tab) {
  if (command === "movetab") {
    moveTab(tab);
  }
}

function moveTab(tab) {
  chrome.storage.local.get('savedWindow', function(storage) {
    var savedToWindow = storage.savedWindow;
    if (savedToWindow == undefined) {
      alert("You haven't selected a target window yet!");
      return;
    }
    chrome.tabs.query({'active': true, 'windowId': chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
      if (tabs.length > 1) {
        alert('Too many tabs found!');
        return;
      }
      try {
        chrome.tabs.move(tabs[0].id, {
          'windowId': savedToWindow,
          'index': -1
        }, function(tabs) {
          chrome.tabs.update(tabs.id, {'active': true}, function() {
            chrome.windows.update(savedToWindow, {'focused': true}, function() {
              console.log('Done!')
            });
          });
        });
      } catch (e) {
        alert(e);
      }
    });
  });
}<commit_msg>Fix moves across monitors acting funny<commit_after>chrome.commands.onCommand.addListener(dispatch);

function dispatch(command, tab) {
  if (command === "movetab") {
    moveTab(tab);
  }
}

function moveTab(tab) {
  chrome.storage.local.get('savedWindow', function(storage) {
    var savedToWindow = storage.savedWindow;
    if (savedToWindow == undefined) {
      alert("You haven't selected a target window yet!");
      return;
    }
    chrome.tabs.query({'active': true, 'windowId': chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
      if (tabs.length > 1) {
        alert('Too many tabs found!');
        return;
      }
      try {
        chrome.tabs.create({
          'windowId': savedToWindow,
          'url': tabs[0].url,
        });

        chrome.windows.update(savedToWindow, {'focused': true});
        chrome.tabs.remove(tabs[0].id);

      } catch (e) {
        alert(e);
      }
    });
  });
}<|endoftext|>


<commit_before>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * background.js
 */

var flashElements = {}; // :Map<chrome.Tab, Object>

chrome.runtime.onConnect.addListener(function(port)
{
    if(port.sender.tab != null)
    {
        port.onMessage.addListener(function(rep)
        {
            if(rep['stopflashInit'])
            {
            }

            if(rep['stopflashDataUpdate'] && rep['stopflashData'])
            {
                flashElements[port.sender.tab] = rep.stopflashData;

                port.postMessage({succes: true});
            }
        });
    }
    else
    {
        port.onMessage.addListener(function(rep)
        {
            if(rep['stopflashInit'])
            {
                port.postMessage({'stopflashDataSend': true, 'stopflashData': flashElements[port.sender.tab]});
            }

            if(rep['stopflashStillHere'])
            {
            }
        });
    }
});
<commit_msg>Add class BackgroundFlashData + small fix<commit_after>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * background.js
 */

function BackgroundFlashData(id)
{
    this.id = id; // :int
    this.changed = false; // :boolean

    this.data = null; // :Object
}
// function setData(Object data):void
BackgroundFlashData.prototype.setData = function(data)
{
    this.data = data;

    this.changed = true;
};

var flashElements = {}; // :Map<chrome.Tab, Object>

chrome.runtime.onConnect.addListener(function(port)
{
    if(port.name === 'stopflashContentScript')
    {
        port.onMessage.addListener(function(rep)
        {
            if(rep['stopflashInit'])
            {
            }

            if(rep['stopflashDataUpdate'] && rep['stopflashData'])
            {
                flashElements[port.sender.tab] = rep.stopflashData;

                port.postMessage({succes: true});
            }
        });
    }
    else if(port.name === 'stopflashPopup')
    {
        port.onMessage.addListener(function(rep)
        {
            if(rep['stopflashInit'])
            {
                port.postMessage({'stopflashDataSend': true, 'stopflashData': flashElements[port.sender.tab]});
            }

            if(rep['stopflashStillHere'])
            {
            }
        });
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { waitFor } from '@testing-library/react';

/**
 * Internal dependencies
 */
import apiFetcher from '../../../../../../app/media/media3p/api/apiFetcher';
import { Fixture, MEDIA_PER_PAGE } from '../../../../../../karma/fixture';
import { ROOT_MARGIN } from '../../local/mediaPane';

const createMediaResource = (name) => ({
  name,
  provider: 'UNSPLASH',
  imageUrls: [
    {
      imageName: 'full',
      url: 'http://www.img.com/1',
      width: 640,
      height: 480,
      mimeType: 'image/png',
    },
    {
      imageName: 'large',
      url: 'http://www.img.com/2',
      width: 300,
      height: 200,
      mimeType: 'image/png',
    },
    {
      imageName: 'web_stories_thumbnail',
      url: 'http://www.img.com/3',
      width: 200,
      height: 100,
      mimeType: 'image/png',
    },
  ],
  description: 'A cat',
  type: 'IMAGE',
  createTime: '1234',
  updateTime: '5678',
});

const mediaPage1 = [...new Array(20).keys()].map((n) =>
  createMediaResource(`media/unsplash:${n + 1}`)
);
const mediaPage2 = [...new Array(20).keys()].map((n) =>
  createMediaResource(`media/unsplash:${n + 21}`)
);

describe('Media3pPane fetching', () => {
  let fixture;
  let media3pTab;
  let media3pPane;

  beforeEach(async () => {
    fixture = new Fixture();
    fixture.setFlags({ media3pTab: true });

    await fixture.render();

    media3pTab = fixture.querySelector('#library-tab-media3p');
    media3pPane = fixture.querySelector('#library-pane-media3p');
  });

  function mockListMedia() {
    /* eslint-disable-next-line jasmine/no-unsafe-spy */
    spyOn(apiFetcher, 'listMedia').and.callFake(({ pageToken }) => {
      switch (pageToken) {
        case undefined:
          return { media: mediaPage1, nextPageToken: 'page2' };
        case 'page2':
          return { media: mediaPage2, nextPageToken: undefined };
        default:
          throw new Error(`Unexpected pageToken: ${pageToken}`);
      }
    });
  }

  async function expectMediaElements(expectedCount) {
    let mediaElements;
    await waitFor(() => {
      mediaElements = media3pPane.querySelectorAll(
        '[data-testid=mediaElement]'
      );
      if (!mediaElements || mediaElements.length !== expectedCount) {
        throw new Error(
          `Not ready: ${mediaElements?.length} != ${expectedCount}`
        );
      }
    });
    expect(mediaElements.length).toBe(expectedCount);
  }

  it('should render no results message', async () => {
    spyOn(apiFetcher, 'listMedia').and.callFake(() => ({ media: [] }));
    await fixture.events.click(media3pTab);

    await waitFor(() => {
      expect(
        fixture.screen.getByText(new RegExp('^No media found$'))
      ).toBeTruthy();
    });
  });

  it('should fetch media resources', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);
    await expectMediaElements(MEDIA_PER_PAGE);
  });

  it('should fetch 2nd page', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    const mediaGallery = media3pPane.querySelector(
      '[data-testid="media-gallery-container"]'
    );
    await expectMediaElements(MEDIA_PER_PAGE);

    mediaGallery.scrollTo(
      0,
      mediaGallery.scrollHeight - mediaGallery.clientHeight - ROOT_MARGIN
    );
    await expectMediaElements(MEDIA_PER_PAGE * 2);
  });

  it('should handle pressing right when focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(0));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing right when at the end of a row', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(mediaElements.item(2));
  });

  it('should handle pressing right when the last element is focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(mediaElements.length - 1));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(
      mediaElements.item(mediaElements.length - 1)
    );
  });

  it('should handle pressing left when focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing left at the beginning of a row', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(2));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing left when the first element is focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(0));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing down', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowDown');

    expect(document.activeElement).toBe(mediaElements.item(3));
  });

  it('should handle pressing up', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(3));

    await fixture.events.keyboard.press('ArrowUp');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing Home', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(6));

    await fixture.events.keyboard.press('Home');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing End', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(6));

    await fixture.events.keyboard.press('End');

    expect(document.activeElement).toBe(
      mediaElements.item(mediaElements.length - 1)
    );
  });
});
<commit_msg>Make a11y test less flaky by mocking just 1 page.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { waitFor } from '@testing-library/react';

/**
 * Internal dependencies
 */
import apiFetcher from '../../../../../../app/media/media3p/api/apiFetcher';
import { Fixture, MEDIA_PER_PAGE } from '../../../../../../karma/fixture';
import { ROOT_MARGIN } from '../../local/mediaPane';

const createMediaResource = (name) => ({
  name,
  provider: 'UNSPLASH',
  imageUrls: [
    {
      imageName: 'full',
      url: 'http://www.img.com/1',
      width: 640,
      height: 480,
      mimeType: 'image/png',
    },
    {
      imageName: 'large',
      url: 'http://www.img.com/2',
      width: 300,
      height: 200,
      mimeType: 'image/png',
    },
    {
      imageName: 'web_stories_thumbnail',
      url: 'http://www.img.com/3',
      width: 200,
      height: 100,
      mimeType: 'image/png',
    },
  ],
  description: 'A cat',
  type: 'IMAGE',
  createTime: '1234',
  updateTime: '5678',
});

const mediaPage1 = [...new Array(20).keys()].map((n) =>
  createMediaResource(`media/unsplash:${n + 1}`)
);
const mediaPage2 = [...new Array(20).keys()].map((n) =>
  createMediaResource(`media/unsplash:${n + 21}`)
);

describe('Media3pPane fetching', () => {
  let fixture;
  let media3pTab;
  let media3pPane;

  beforeEach(async () => {
    fixture = new Fixture();
    fixture.setFlags({ media3pTab: true });

    await fixture.render();

    media3pTab = fixture.querySelector('#library-tab-media3p');
    media3pPane = fixture.querySelector('#library-pane-media3p');
  });

  function mockListMedia() {
    /* eslint-disable-next-line jasmine/no-unsafe-spy */
    spyOn(apiFetcher, 'listMedia').and.callFake(({ pageToken }) => {
      switch (pageToken) {
        case undefined:
          return { media: mediaPage1, nextPageToken: 'page2' };
        case 'page2':
          return { media: mediaPage2, nextPageToken: undefined };
        default:
          throw new Error(`Unexpected pageToken: ${pageToken}`);
      }
    });
  }

  async function expectMediaElements(expectedCount) {
    let mediaElements;
    await waitFor(() => {
      mediaElements = media3pPane.querySelectorAll(
        '[data-testid=mediaElement]'
      );
      if (!mediaElements || mediaElements.length !== expectedCount) {
        throw new Error(
          `Not ready: ${mediaElements?.length} != ${expectedCount}`
        );
      }
    });
    expect(mediaElements.length).toBe(expectedCount);
  }

  it('should render no results message', async () => {
    spyOn(apiFetcher, 'listMedia').and.callFake(() => ({ media: [] }));
    await fixture.events.click(media3pTab);

    await waitFor(() => {
      expect(
        fixture.screen.getByText(new RegExp('^No media found$'))
      ).toBeTruthy();
    });
  });

  it('should fetch media resources', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);
    await expectMediaElements(MEDIA_PER_PAGE);
  });

  it('should fetch 2nd page', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    const mediaGallery = media3pPane.querySelector(
      '[data-testid="media-gallery-container"]'
    );
    await expectMediaElements(MEDIA_PER_PAGE);

    mediaGallery.scrollTo(
      0,
      mediaGallery.scrollHeight - mediaGallery.clientHeight - ROOT_MARGIN
    );
    await expectMediaElements(MEDIA_PER_PAGE * 2);
  });

  it('should handle pressing right when focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(0));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing right when at the end of a row', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(mediaElements.item(2));
  });

  it('should handle pressing right when the last element is focused', async () => {
    // Only mock 1 page.
    spyOn(apiFetcher, 'listMedia').and.callFake(({ pageToken }) => {
      if (!pageToken) {
        return { media: mediaPage2, nextPageToken: undefined };
      }
      throw new Error(`Unexpected pageToken: ${pageToken}`);
    });

    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(mediaElements.length - 1));

    await fixture.events.keyboard.press('ArrowRight');

    expect(document.activeElement).toBe(
      mediaElements.item(mediaElements.length - 1)
    );
  });

  it('should handle pressing left when focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing left at the beginning of a row', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(2));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing left when the first element is focused', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(0));

    await fixture.events.keyboard.press('ArrowLeft');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing down', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(1));

    await fixture.events.keyboard.press('ArrowDown');

    expect(document.activeElement).toBe(mediaElements.item(3));
  });

  it('should handle pressing up', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(3));

    await fixture.events.keyboard.press('ArrowUp');

    expect(document.activeElement).toBe(mediaElements.item(1));
  });

  it('should handle pressing Home', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(6));

    await fixture.events.keyboard.press('Home');

    expect(document.activeElement).toBe(mediaElements.item(0));
  });

  it('should handle pressing End', async () => {
    mockListMedia();
    await fixture.events.click(media3pTab);

    await expectMediaElements(MEDIA_PER_PAGE);

    let mediaElements = media3pPane.querySelectorAll(
      '[data-testid=mediaElement]'
    );

    await fixture.events.focus(mediaElements.item(6));

    await fixture.events.keyboard.press('End');

    expect(document.activeElement).toBe(
      mediaElements.item(mediaElements.length - 1)
    );
  });
});
<|endoftext|>


<commit_before>// Copyright (c) 2014 Allan Costa.

function sciHubFy(link, sciHubDomain) {
  // Append Sci-Hub domain to link's domain
  var matches = link.match(/:\/\/(?:www\.)?(.[^/]+)(.*)/);
  return "http://" + matches[1] + "." + sciHubDomain + matches[2];
}

function newTabSciHubFy(tab, link) {
  // Tab is the current tab and link is the link to append sci-hub.io
  chrome.storage.sync.get({
    domain: 'sci-hub.cc'  // Default domain
  }, function(items) {
    chrome.tabs.query({
        active: true
      }, tabs => {
        let index = tabs[0].index;
        chrome.tabs.create({index: index + 1, url: sciHubFy(link, items.domain)});
      }
    );
  });
}

function sameTabSciHubFy(tab, link) {
  // Tab is the current tab and link is the link to append sci-hub.io
  chrome.storage.sync.get({
    domain: 'sci-hub.cc' // Default domain
  }, function(items) {
    chrome.tabs.update(tab.id, {url: sciHubFy(link, items.domain)});
  });
}

function openOptions(){
  if (chrome.runtime.openOptionsPage) {
  // New way to open options pages, if supported (Chrome 42+).
  chrome.runtime.openOptionsPage();
  } else {
    // Reasonable fallback.
    window.open(chrome.runtime.getURL('options.html'));
  }
}
// Setup extension click action
chrome.browserAction.onClicked.addListener(function(tab) {
  sameTabSciHubFy(tab, tab.url);
});

// Setup context menu actions
chrome.runtime.onInstalled.addListener(function() {
    chrome.contextMenus.create({
        title: 'Sci-Hub-Fy',
        id: 'page', // you'll use this in the handler function to identify this context menu item
        contexts: ['page'],
    });
    chrome.contextMenus.create({
        title: 'Sci-Hub-Fy',
        id: 'link', // you'll use this in the handler function to identify this context menu item
        contexts: ['link'],
    });
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId === "page") { // here's where you'll need the ID
      sameTabSciHubFy(tab, tab.url);
    } else if (info.menuItemId === "link") {
      newTabSciHubFy(tab, info.linkUrl);
    }
});
<commit_msg>Updating background.js with the Updated Sci-Hub domain <commit_after>// Copyright (c) 2014 Allan Costa.

function sciHubFy(link, sciHubDomain) {
  // Append Sci-Hub domain to link's domain
  var matches = link.match(/:\/\/(?:www\.)?(.[^/]+)(.*)/);
  return "http://" + matches[1] + "." + sciHubDomain + matches[2];
}

function newTabSciHubFy(tab, link) {
  // Tab is the current tab and link is the link to append sci-hub.io
  chrome.storage.sync.get({
    domain: 'sci-hub.bz // Updated default domain ( As of DEC 03 - 2017 )
  }, function(items) {
    chrome.tabs.query({
        active: true
      }, tabs => {
        let index = tabs[0].index;
        chrome.tabs.create({index: index + 1, url: sciHubFy(link, items.domain)});
      }
    );
  });
}

function sameTabSciHubFy(tab, link) {
  // Tab is the current tab and link is the link to append sci-hub.io
  chrome.storage.sync.get({
    domain: 'sci-hub.bz' // Updated default domain ( As of DEC 03 - 2017 )
  }, function(items) {
    chrome.tabs.update(tab.id, {url: sciHubFy(link, items.domain)});
  });
}

function openOptions(){
  if (chrome.runtime.openOptionsPage) {
  // New way to open options pages, if supported (Chrome 42+).
  chrome.runtime.openOptionsPage();
  } else {
    // Reasonable fallback.
    window.open(chrome.runtime.getURL('options.html'));
  }
}
// Setup extension click action
chrome.browserAction.onClicked.addListener(function(tab) {
  sameTabSciHubFy(tab, tab.url);
});

// Setup context menu actions
chrome.runtime.onInstalled.addListener(function() {
    chrome.contextMenus.create({
        title: 'Sci-Hub-Fy',
        id: 'page', // you'll use this in the handler function to identify this context menu item
        contexts: ['page'],
    });
    chrome.contextMenus.create({
        title: 'Sci-Hub-Fy',
        id: 'link', // you'll use this in the handler function to identify this context menu item
        contexts: ['link'],
    });
});

chrome.contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId === "page") { // here's where you'll need the ID
      sameTabSciHubFy(tab, tab.url);
    } else if (info.menuItemId === "link") {
      newTabSciHubFy(tab, info.linkUrl);
    }
});
<|endoftext|>