<commit_before>/**
 * @module ol/control/MousePosition
 */

import Control from './Control.js';
import EventType from '../pointer/EventType.js';
import {
  get as getProjection,
  getTransformFromProjections,
  getUserProjection,
  identityTransform,
} from '../proj.js';
import {listen} from '../events.js';

/**
 * @type {string}
 */
const PROJECTION = 'projection';

/**
 * @type {string}
 */
const COORDINATE_FORMAT = 'coordinateFormat';

/***
 * @template Return
 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
 *   import("../Observable").OnSignature<import("../ObjectEventType").Types|
 *     'change:coordinateFormat'|'change:projection', import("../Object").ObjectEvent, Return> &
 *   import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types|
 *     'change:coordinateFormat'|'change:projection', Return>} MousePositionOnSignature
 */

/**
 * @typedef {Object} Options
 * @property {string} [className='ol-mouse-position'] CSS class name.
 * @property {import("../coordinate.js").CoordinateFormat} [coordinateFormat] Coordinate format.
 * @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
 * @property {function(import("../MapEvent.js").default):void} [render] Function called when the
 * control should be re-rendered. This is called in a `requestAnimationFrame`
 * callback.
 * @property {HTMLElement|string} [target] Specify a target if you want the
 * control to be rendered outside of the map's viewport.
 * @property {string|boolean} [placeholder] Markup to show when the mouse position is not
 * available (e.g. when the pointer leaves the map viewport).  By default, a non-breaking space
 * is rendered when the mouse leaves the viewport.  To render something else, provide a string
 * to be used as the text content (e.g. 'no position' or '' for an empty string).  Set the placeholder
 * to `false` to retain the last position when the mouse leaves the viewport.  In a future release, this
 * will be the default behavior.
 * @property {string} [undefinedHTML=' '] This option is deprecated.  Use the `placeholder` option instead.
 */

/**
 * @classdesc
 * A control to show the 2D coordinates of the mouse cursor. By default, these
 * are in the view projection, but can be in any supported projection.
 * By default the control is shown in the top right corner of the map, but this
 * can be changed by using the css selector `.ol-mouse-position`.
 *
 * On touch devices, which usually do not have a mouse cursor, the coordinates
 * of the currently touched position are shown.
 *
 * @api
 */
class MousePosition extends Control {
  /**
   * @param {Options} [opt_options] Mouse position options.
   */
  constructor(opt_options) {
    const options = opt_options ? opt_options : {};

    const element = document.createElement('div');
    element.className =
      options.className !== undefined ? options.className : 'ol-mouse-position';

    super({
      element: element,
      render: options.render,
      target: options.target,
    });

    /***
     * @type {MousePositionOnSignature<import("../Observable.js").OnReturn>}
     */
    this.on;

    /***
     * @type {MousePositionOnSignature<import("../Observable.js").OnReturn>}
     */
    this.once;

    /***
     * @type {MousePositionOnSignature<void>}
     */
    this.un;

    this.addChangeListener(PROJECTION, this.handleProjectionChanged_);

    if (options.coordinateFormat) {
      this.setCoordinateFormat(options.coordinateFormat);
    }
    if (options.projection) {
      this.setProjection(options.projection);
    }

    /**
     * @type {boolean}
     * Change this to `false` when removing the deprecated `undefinedHTML` option.
     */
    let renderOnMouseOut = true;

    /**
     * @type {string}
     */
    let placeholder = ' ';

    if ('undefinedHTML' in options) {
      // deprecated behavior
      if (options.undefinedHTML !== undefined) {
        placeholder = options.undefinedHTML;
      }
      renderOnMouseOut = !!placeholder;
    } else if ('placeholder' in options) {
      if (options.placeholder === false) {
        renderOnMouseOut = false;
      } else {
        placeholder = String(options.placeholder);
      }
    }

    /**
     * @private
     * @type {string}
     */
    this.placeholder_ = placeholder;

    /**
     * @private
     * @type {boolean}
     */
    this.renderOnMouseOut_ = renderOnMouseOut;

    /**
     * @private
     * @type {string}
     */
    this.renderedHTML_ = element.innerHTML;

    /**
     * @private
     * @type {?import("../proj/Projection.js").default}
     */
    this.mapProjection_ = null;

    /**
     * @private
     * @type {?import("../proj.js").TransformFunction}
     */
    this.transform_ = null;
  }

  /**
   * @private
   */
  handleProjectionChanged_() {
    this.transform_ = null;
  }

  /**
   * Return the coordinate format type used to render the current position or
   * undefined.
   * @return {import("../coordinate.js").CoordinateFormat|undefined} The format to render the current
   *     position in.
   * @observable
   * @api
   */
  getCoordinateFormat() {
    return /** @type {import("../coordinate.js").CoordinateFormat|undefined} */ (
      this.get(COORDINATE_FORMAT)
    );
  }

  /**
   * Return the projection that is used to report the mouse position.
   * @return {import("../proj/Projection.js").default|undefined} The projection to report mouse
   *     position in.
   * @observable
   * @api
   */
  getProjection() {
    return /** @type {import("../proj/Projection.js").default|undefined} */ (
      this.get(PROJECTION)
    );
  }

  /**
   * @param {MouseEvent} event Browser event.
   * @protected
   */
  handleMouseMove(event) {
    const map = this.getMap();
    this.updateHTML_(map.getEventPixel(event));
  }

  /**
   * @param {Event} event Browser event.
   * @protected
   */
  handleMouseOut(event) {
    this.updateHTML_(null);
  }

  /**
   * Remove the control from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../PluggableMap.js").default} map Map.
   * @api
   */
  setMap(map) {
    super.setMap(map);
    if (map) {
      const viewport = map.getViewport();
      this.listenerKeys.push(
        listen(viewport, EventType.POINTERMOVE, this.handleMouseMove, this)
      );
      if (this.renderOnMouseOut_) {
        this.listenerKeys.push(
          listen(viewport, EventType.POINTEROUT, this.handleMouseOut, this)
        );
      }
      this.updateHTML_(null);
    }
  }

  /**
   * Set the coordinate format type used to render the current position.
   * @param {import("../coordinate.js").CoordinateFormat} format The format to render the current
   *     position in.
   * @observable
   * @api
   */
  setCoordinateFormat(format) {
    this.set(COORDINATE_FORMAT, format);
  }

  /**
   * Set the projection that is used to report the mouse position.
   * @param {import("../proj.js").ProjectionLike} projection The projection to report mouse
   *     position in.
   * @observable
   * @api
   */
  setProjection(projection) {
    this.set(PROJECTION, getProjection(projection));
  }

  /**
   * @param {?import("../pixel.js").Pixel} pixel Pixel.
   * @private
   */
  updateHTML_(pixel) {
    let html = this.placeholder_;
    if (pixel && this.mapProjection_) {
      if (!this.transform_) {
        const projection = this.getProjection();
        if (projection) {
          this.transform_ = getTransformFromProjections(
            this.mapProjection_,
            projection
          );
        } else {
          this.transform_ = identityTransform;
        }
      }
      const map = this.getMap();
      const coordinate = map.getCoordinateFromPixelInternal(pixel);
      if (coordinate) {
        const userProjection = getUserProjection();
        if (userProjection) {
          this.transform_ = getTransformFromProjections(
            this.mapProjection_,
            userProjection
          );
        }
        this.transform_(coordinate, coordinate);
        const coordinateFormat = this.getCoordinateFormat();
        if (coordinateFormat) {
          html = coordinateFormat(coordinate);
        } else {
          html = coordinate.toString();
        }
      }
    }
    if (!this.renderedHTML_ || html !== this.renderedHTML_) {
      this.element.innerHTML = html;
      this.renderedHTML_ = html;
    }
  }

  /**
   * Update the projection. Rendering of the coordinates is done in
   * `handleMouseMove` and `handleMouseUp`.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @override
   */
  render(mapEvent) {
    const frameState = mapEvent.frameState;
    if (!frameState) {
      this.mapProjection_ = null;
    } else {
      if (this.mapProjection_ != frameState.viewState.projection) {
        this.mapProjection_ = frameState.viewState.projection;
        this.transform_ = null;
      }
    }
  }
}

export default MousePosition;
<commit_msg>Move description above type tag<commit_after>/**
 * @module ol/control/MousePosition
 */

import Control from './Control.js';
import EventType from '../pointer/EventType.js';
import {
  get as getProjection,
  getTransformFromProjections,
  getUserProjection,
  identityTransform,
} from '../proj.js';
import {listen} from '../events.js';

/**
 * @type {string}
 */
const PROJECTION = 'projection';

/**
 * @type {string}
 */
const COORDINATE_FORMAT = 'coordinateFormat';

/***
 * @template Return
 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
 *   import("../Observable").OnSignature<import("../ObjectEventType").Types|
 *     'change:coordinateFormat'|'change:projection', import("../Object").ObjectEvent, Return> &
 *   import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types|
 *     'change:coordinateFormat'|'change:projection', Return>} MousePositionOnSignature
 */

/**
 * @typedef {Object} Options
 * @property {string} [className='ol-mouse-position'] CSS class name.
 * @property {import("../coordinate.js").CoordinateFormat} [coordinateFormat] Coordinate format.
 * @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
 * @property {function(import("../MapEvent.js").default):void} [render] Function called when the
 * control should be re-rendered. This is called in a `requestAnimationFrame`
 * callback.
 * @property {HTMLElement|string} [target] Specify a target if you want the
 * control to be rendered outside of the map's viewport.
 * @property {string|boolean} [placeholder] Markup to show when the mouse position is not
 * available (e.g. when the pointer leaves the map viewport).  By default, a non-breaking space
 * is rendered when the mouse leaves the viewport.  To render something else, provide a string
 * to be used as the text content (e.g. 'no position' or '' for an empty string).  Set the placeholder
 * to `false` to retain the last position when the mouse leaves the viewport.  In a future release, this
 * will be the default behavior.
 * @property {string} [undefinedHTML=' '] This option is deprecated.  Use the `placeholder` option instead.
 */

/**
 * @classdesc
 * A control to show the 2D coordinates of the mouse cursor. By default, these
 * are in the view projection, but can be in any supported projection.
 * By default the control is shown in the top right corner of the map, but this
 * can be changed by using the css selector `.ol-mouse-position`.
 *
 * On touch devices, which usually do not have a mouse cursor, the coordinates
 * of the currently touched position are shown.
 *
 * @api
 */
class MousePosition extends Control {
  /**
   * @param {Options} [opt_options] Mouse position options.
   */
  constructor(opt_options) {
    const options = opt_options ? opt_options : {};

    const element = document.createElement('div');
    element.className =
      options.className !== undefined ? options.className : 'ol-mouse-position';

    super({
      element: element,
      render: options.render,
      target: options.target,
    });

    /***
     * @type {MousePositionOnSignature<import("../Observable.js").OnReturn>}
     */
    this.on;

    /***
     * @type {MousePositionOnSignature<import("../Observable.js").OnReturn>}
     */
    this.once;

    /***
     * @type {MousePositionOnSignature<void>}
     */
    this.un;

    this.addChangeListener(PROJECTION, this.handleProjectionChanged_);

    if (options.coordinateFormat) {
      this.setCoordinateFormat(options.coordinateFormat);
    }
    if (options.projection) {
      this.setProjection(options.projection);
    }

    /**
     * Change this to `false` when removing the deprecated `undefinedHTML` option.
     * @type {boolean}
     */
    let renderOnMouseOut = true;

    /**
     * @type {string}
     */
    let placeholder = ' ';

    if ('undefinedHTML' in options) {
      // deprecated behavior
      if (options.undefinedHTML !== undefined) {
        placeholder = options.undefinedHTML;
      }
      renderOnMouseOut = !!placeholder;
    } else if ('placeholder' in options) {
      if (options.placeholder === false) {
        renderOnMouseOut = false;
      } else {
        placeholder = String(options.placeholder);
      }
    }

    /**
     * @private
     * @type {string}
     */
    this.placeholder_ = placeholder;

    /**
     * @private
     * @type {boolean}
     */
    this.renderOnMouseOut_ = renderOnMouseOut;

    /**
     * @private
     * @type {string}
     */
    this.renderedHTML_ = element.innerHTML;

    /**
     * @private
     * @type {?import("../proj/Projection.js").default}
     */
    this.mapProjection_ = null;

    /**
     * @private
     * @type {?import("../proj.js").TransformFunction}
     */
    this.transform_ = null;
  }

  /**
   * @private
   */
  handleProjectionChanged_() {
    this.transform_ = null;
  }

  /**
   * Return the coordinate format type used to render the current position or
   * undefined.
   * @return {import("../coordinate.js").CoordinateFormat|undefined} The format to render the current
   *     position in.
   * @observable
   * @api
   */
  getCoordinateFormat() {
    return /** @type {import("../coordinate.js").CoordinateFormat|undefined} */ (
      this.get(COORDINATE_FORMAT)
    );
  }

  /**
   * Return the projection that is used to report the mouse position.
   * @return {import("../proj/Projection.js").default|undefined} The projection to report mouse
   *     position in.
   * @observable
   * @api
   */
  getProjection() {
    return /** @type {import("../proj/Projection.js").default|undefined} */ (
      this.get(PROJECTION)
    );
  }

  /**
   * @param {MouseEvent} event Browser event.
   * @protected
   */
  handleMouseMove(event) {
    const map = this.getMap();
    this.updateHTML_(map.getEventPixel(event));
  }

  /**
   * @param {Event} event Browser event.
   * @protected
   */
  handleMouseOut(event) {
    this.updateHTML_(null);
  }

  /**
   * Remove the control from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../PluggableMap.js").default} map Map.
   * @api
   */
  setMap(map) {
    super.setMap(map);
    if (map) {
      const viewport = map.getViewport();
      this.listenerKeys.push(
        listen(viewport, EventType.POINTERMOVE, this.handleMouseMove, this)
      );
      if (this.renderOnMouseOut_) {
        this.listenerKeys.push(
          listen(viewport, EventType.POINTEROUT, this.handleMouseOut, this)
        );
      }
      this.updateHTML_(null);
    }
  }

  /**
   * Set the coordinate format type used to render the current position.
   * @param {import("../coordinate.js").CoordinateFormat} format The format to render the current
   *     position in.
   * @observable
   * @api
   */
  setCoordinateFormat(format) {
    this.set(COORDINATE_FORMAT, format);
  }

  /**
   * Set the projection that is used to report the mouse position.
   * @param {import("../proj.js").ProjectionLike} projection The projection to report mouse
   *     position in.
   * @observable
   * @api
   */
  setProjection(projection) {
    this.set(PROJECTION, getProjection(projection));
  }

  /**
   * @param {?import("../pixel.js").Pixel} pixel Pixel.
   * @private
   */
  updateHTML_(pixel) {
    let html = this.placeholder_;
    if (pixel && this.mapProjection_) {
      if (!this.transform_) {
        const projection = this.getProjection();
        if (projection) {
          this.transform_ = getTransformFromProjections(
            this.mapProjection_,
            projection
          );
        } else {
          this.transform_ = identityTransform;
        }
      }
      const map = this.getMap();
      const coordinate = map.getCoordinateFromPixelInternal(pixel);
      if (coordinate) {
        const userProjection = getUserProjection();
        if (userProjection) {
          this.transform_ = getTransformFromProjections(
            this.mapProjection_,
            userProjection
          );
        }
        this.transform_(coordinate, coordinate);
        const coordinateFormat = this.getCoordinateFormat();
        if (coordinateFormat) {
          html = coordinateFormat(coordinate);
        } else {
          html = coordinate.toString();
        }
      }
    }
    if (!this.renderedHTML_ || html !== this.renderedHTML_) {
      this.element.innerHTML = html;
      this.renderedHTML_ = html;
    }
  }

  /**
   * Update the projection. Rendering of the coordinates is done in
   * `handleMouseMove` and `handleMouseUp`.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @override
   */
  render(mapEvent) {
    const frameState = mapEvent.frameState;
    if (!frameState) {
      this.mapProjection_ = null;
    } else {
      if (this.mapProjection_ != frameState.viewState.projection) {
        this.mapProjection_ = frameState.viewState.projection;
        this.transform_ = null;
      }
    }
  }
}

export default MousePosition;
<|endoftext|>


<commit_before>goog.provide('olcs.SynchronizedOverlay');

goog.require('ol');
goog.require('ol.Overlay');
goog.require('ol.proj');
goog.require('ol.dom');
goog.require('ol.Observable');

/**
 * @constructor
 * @param {olcsx.SynchronizedOverlayOptions} options SynchronizedOverlay Options.
 * @extends {ol.Overlay}
 * @api
 */
olcs.SynchronizedOverlay = function(options) {
  /**
   * @private
   * @type {?Function}
   */
  this.scenePostRenderListenerRemover_ = null;

  /**
   * @private
   * @type {!Cesium.Scene}
   */
  this.scene_ = options.scene;

  /**
   * @private
   * @type {!olcs.OverlaySynchronizer}
   */
  this.synchronizer_ = options.synchronizer;

  /**
   * @private
   * @type {!ol.Overlay}
   */
  this.parent_ = options.parent;

  /**
   * @private
   * @type {ol.Coordinate|null}
   */
  this.positionWGS84_ = null;

  /**
   * @private
   * @type {MutationObserver}
   */
  this.observer_ = new MutationObserver(this.handleElementChanged.bind(this));

  /**
   * @private
   * @type {Array<ol.EventsKey>}
   */
  this.listenerKeys_ = [];
  // synchronize our Overlay with the parent Overlay
  this.listenerKeys_.push(this.parent_.on('change:position', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:element', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:offset', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:position', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:positioning', this.setPropertyFromEvent_.bind(this)));

  ol.Overlay.call(this, this.parent_.getOptions());
  this.setProperties(this.parent_.getProperties());

  this.handleMapChanged();
};
ol.inherits(olcs.SynchronizedOverlay, ol.Overlay);

/**
 * @param {Node} target
 * @private
 */
olcs.SynchronizedOverlay.prototype.observeTarget_ = function(target) {
  this.observer_.disconnect();
  this.observer_.observe(target, {
    attributes: false,
    childList: true,
    characterData: false,
    subtree: true
  });
};

/**
 *
 * @param {ol.Object.Event} event
 * @private
 */
olcs.SynchronizedOverlay.prototype.setPropertyFromEvent_ = function(event) {
  this.set(event.key, event.target.get(event.key));
};
/**
 * Get the scene associated with this overlay.
 * @see ol.Overlay.prototype.getMap
 * @return {!Cesium.Scene} The scene that the overlay is part of.
 * @api
 */
olcs.SynchronizedOverlay.prototype.getScene = function() {
  return this.scene_;
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handleMapChanged = function() {
  if (this.scenePostRenderListenerRemover_) {
    this.scenePostRenderListenerRemover_();
    ol.dom.removeNode(this.element_);
  }
  this.scenePostRenderListenerRemover_ = null;
  const scene = this.getScene();
  if (scene) {
    this.scenePostRenderListenerRemover_ = scene.postRender.addEventListener(this.updatePixelPosition.bind(this));
    this.updatePixelPosition();
    const container = this.stopEvent_ ?
      this.synchronizer_.getOverlayContainerStopEvent() : this.synchronizer_.getOverlayContainer();
    if (this.insertFirst_) {
      container.insertBefore(this.element_, container.childNodes[0] || null);
    } else {
      container.appendChild(this.element_);
    }
  }
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handlePositionChanged = function() {
  // transform position to WGS84
  const position = this.getPosition();
  if (position) {
    const sourceProjection = this.parent_.getMap().getView().getProjection();
    this.positionWGS84_ = ol.proj.transform(position, sourceProjection, 'EPSG:4326');
  }
  this.updatePixelPosition();
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handleElementChanged = function() {
  function cloneNode(node, parent) {
    const clone = node.cloneNode();
    if (parent) {
      parent.appendChild(clone);
    }
    if (node.nodeType != Node.TEXT_NODE) {
      clone.addEventListener('click', (event) => {
        node.dispatchEvent(new MouseEvent('click', event));
        event.stopPropagation();
      });
    }
    const nodes = node.childNodes;
    for (let i = 0; i < nodes.length; i++) {
      if (!nodes[i]) {
        continue;
      }
      cloneNode(nodes[i], clone);
    }
    return clone;
  }
  ol.dom.removeChildren(this.element_);
  const element = this.getElement();
  if (element) {
    if (element.parentNode) {
      element.parentNode.childNodes.forEach((node) => {
        const clonedNode = cloneNode(node, null);
        this.element_.appendChild(clonedNode);
      });
    }
  }
  if (element.parentNode) {
    // set new Observer
    this.observeTarget_(element.parentNode);
  }
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.updatePixelPosition = function() {
  const position = this.positionWGS84_;
  if (!this.scene_ || !position) {
    this.setVisible(false);
    return;
  }
  let cartesian;
  if (position.length === 2) {
    cartesian = Cesium.Cartesian3.fromDegreesArray(position)[0];
  } else {
    cartesian = Cesium.Cartesian3.fromDegreesArrayHeights(position)[0];
  }
  const camera = this.scene_.camera;
  const ellipsoidBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(), 6356752);
  const occluder = new Cesium.Occluder(ellipsoidBoundingSphere, camera.position);
  // check if overlay position is behind the horizon
  if (!occluder.isPointVisible(cartesian)) {
    this.setVisible(false);
    return;
  }
  const cullingVolume = camera.frustum.computeCullingVolume(camera.position, camera.direction, camera.up);
  // check if overlay position is visible from the camera
  if (cullingVolume.computeVisibility(new Cesium.BoundingSphere(cartesian)) !== 1) {
    this.setVisible(false);
    return;
  }
  this.setVisible(true);

  const pixelCartesian = this.scene_.cartesianToCanvasCoordinates(cartesian);
  const pixel = [pixelCartesian.x, pixelCartesian.y];
  const mapSize = [this.scene_.canvas.width, this.scene_.canvas.height];
  this.updateRenderedPosition(pixel, mapSize);
};

/**
 * Destroys the overlay, removing all its listeners and elements
 * @api
 */
olcs.SynchronizedOverlay.prototype.destroy = function() {
  if (this.scenePostRenderListenerRemover_) {
    this.scenePostRenderListenerRemover_();
  }
  if (this.observer_) {
    this.observer_.disconnect();
  }
  ol.Observable.unByKey(this.listenerKeys_);
  this.listenerKeys_.splice(0);
  if (this.element_.removeNode) {
    this.element_.removeNode(true);
  } else {
    this.element_.remove();
  }
  this.element_ = null;
};
<commit_msg>fixed position undefined bug added Attribute observer to see all attribute changes on children of the observed dom element<commit_after>goog.provide('olcs.SynchronizedOverlay');

goog.require('ol');
goog.require('ol.Overlay');
goog.require('ol.proj');
goog.require('ol.dom');
goog.require('ol.Observable');

/**
 * @constructor
 * @param {olcsx.SynchronizedOverlayOptions} options SynchronizedOverlay Options.
 * @extends {ol.Overlay}
 * @api
 */
olcs.SynchronizedOverlay = function(options) {
  /**
   * @private
   * @type {?Function}
   */
  this.scenePostRenderListenerRemover_ = null;

  /**
   * @private
   * @type {!Cesium.Scene}
   */
  this.scene_ = options.scene;

  /**
   * @private
   * @type {!olcs.OverlaySynchronizer}
   */
  this.synchronizer_ = options.synchronizer;

  /**
   * @private
   * @type {!ol.Overlay}
   */
  this.parent_ = options.parent;

  /**
   * @private
   * @type {ol.Coordinate|undefined}
   */
  this.positionWGS84_ = undefined;

  /**
   * @private
   * @type {MutationObserver}
   */
  this.observer_ = new MutationObserver(this.handleElementChanged.bind(this));
  /**
   * @private
   * @type {Array.<MutationObserver>}
   */
  this.attributeObserver_ = [];

  /**
   * @private
   * @type {Array<ol.EventsKey>}
   */
  this.listenerKeys_ = [];
  // synchronize our Overlay with the parent Overlay
  this.listenerKeys_.push(this.parent_.on('change:position', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:element', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:offset', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:position', this.setPropertyFromEvent_.bind(this)));
  this.listenerKeys_.push(this.parent_.on('change:positioning', this.setPropertyFromEvent_.bind(this)));

  ol.Overlay.call(this, this.parent_.getOptions());
  this.setProperties(this.parent_.getProperties());

  this.handleMapChanged();
};
ol.inherits(olcs.SynchronizedOverlay, ol.Overlay);

/**
 * @param {Node} target
 * @private
 */
olcs.SynchronizedOverlay.prototype.observeTarget_ = function(target) {
  this.observer_.disconnect();
  this.observer_.observe(target, {
    attributes: false,
    childList: true,
    characterData: true,
    subtree: true
  });
  this.attributeObserver_.forEach((observer) => {
    observer.disconnect();
  });
  this.attributeObserver_.length = 0;
  for (let i = 0; i < target.childNodes.length; i++) {
    const node = target.childNodes[i];
    if (node.nodeType === 1) {
      const observer = new MutationObserver(this.handleElementChanged.bind(this));
      observer.observe(node, {
        attributes: true,
        subtree: true
      });
      this.attributeObserver_.push(observer);
    }
  }
};

/**
 *
 * @param {ol.Object.Event} event
 * @private
 */
olcs.SynchronizedOverlay.prototype.setPropertyFromEvent_ = function(event) {
  this.set(event.key, event.target.get(event.key));
};
/**
 * Get the scene associated with this overlay.
 * @see ol.Overlay.prototype.getMap
 * @return {!Cesium.Scene} The scene that the overlay is part of.
 * @api
 */
olcs.SynchronizedOverlay.prototype.getScene = function() {
  return this.scene_;
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handleMapChanged = function() {
  if (this.scenePostRenderListenerRemover_) {
    this.scenePostRenderListenerRemover_();
    ol.dom.removeNode(this.element_);
  }
  this.scenePostRenderListenerRemover_ = null;
  const scene = this.getScene();
  if (scene) {
    this.scenePostRenderListenerRemover_ = scene.postRender.addEventListener(this.updatePixelPosition.bind(this));
    this.updatePixelPosition();
    const container = this.stopEvent_ ?
      this.synchronizer_.getOverlayContainerStopEvent() : this.synchronizer_.getOverlayContainer();
    if (this.insertFirst_) {
      container.insertBefore(this.element_, container.childNodes[0] || null);
    } else {
      container.appendChild(this.element_);
    }
  }
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handlePositionChanged = function() {
  // transform position to WGS84
  const position = this.getPosition();
  if (position) {
    const sourceProjection = this.parent_.getMap().getView().getProjection();
    this.positionWGS84_ = ol.proj.transform(position, sourceProjection, 'EPSG:4326');
  } else {
    this.positionWGS84_ = undefined;
  }
  this.updatePixelPosition();
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.handleElementChanged = function() {
  function cloneNode(node, parent) {
    const clone = node.cloneNode();
    if (parent) {
      parent.appendChild(clone);
    }
    if (node.nodeType != Node.TEXT_NODE) {
      clone.addEventListener('click', (event) => {
        node.dispatchEvent(new MouseEvent('click', event));
        event.stopPropagation();
      });
    }
    const nodes = node.childNodes;
    for (let i = 0; i < nodes.length; i++) {
      if (!nodes[i]) {
        continue;
      }
      cloneNode(nodes[i], clone);
    }
    return clone;
  }
  ol.dom.removeChildren(this.element_);
  const element = this.getElement();
  if (element) {
    if (element.parentNode) {
      element.parentNode.childNodes.forEach((node) => {
        const clonedNode = cloneNode(node, null);
        this.element_.appendChild(clonedNode);
      });
    }
  }
  if (element.parentNode) {
    // set new Observer
    this.observeTarget_(element.parentNode);
  }
};

/**
 * @override
 */
olcs.SynchronizedOverlay.prototype.updatePixelPosition = function() {
  const position = this.positionWGS84_;
  if (!this.scene_ || !position) {
    this.setVisible(false);
    return;
  }
  let cartesian;
  if (position.length === 2) {
    cartesian = Cesium.Cartesian3.fromDegreesArray(position)[0];
  } else {
    cartesian = Cesium.Cartesian3.fromDegreesArrayHeights(position)[0];
  }
  const camera = this.scene_.camera;
  const ellipsoidBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(), 6356752);
  const occluder = new Cesium.Occluder(ellipsoidBoundingSphere, camera.position);
  // check if overlay position is behind the horizon
  if (!occluder.isPointVisible(cartesian)) {
    this.setVisible(false);
    return;
  }
  const cullingVolume = camera.frustum.computeCullingVolume(camera.position, camera.direction, camera.up);
  // check if overlay position is visible from the camera
  if (cullingVolume.computeVisibility(new Cesium.BoundingSphere(cartesian)) !== 1) {
    this.setVisible(false);
    return;
  }
  this.setVisible(true);

  const pixelCartesian = this.scene_.cartesianToCanvasCoordinates(cartesian);
  const pixel = [pixelCartesian.x, pixelCartesian.y];
  const mapSize = [this.scene_.canvas.width, this.scene_.canvas.height];
  this.updateRenderedPosition(pixel, mapSize);
};

/**
 * Destroys the overlay, removing all its listeners and elements
 * @api
 */
olcs.SynchronizedOverlay.prototype.destroy = function() {
  if (this.scenePostRenderListenerRemover_) {
    this.scenePostRenderListenerRemover_();
  }
  if (this.observer_) {
    this.observer_.disconnect();
  }
  ol.Observable.unByKey(this.listenerKeys_);
  this.listenerKeys_.splice(0);
  if (this.element_.removeNode) {
    this.element_.removeNode(true);
  } else {
    this.element_.remove();
  }
  this.element_ = null;
};
<|endoftext|>


<commit_before>var express = require('express')
var app = express()
app.get('/', function(rq, res) {
  res.render('trainControls.jade', { layout: false });
});
var server = app.listen(8080, function() {
});
<commit_msg>actually serve the static files for the web page<commit_after>var express = require('express')
var app = express()
app.set('view engine', 'jade')
app.use('/bower_components', express.static(__dirname + '/bower_components'));
app.use('/js', express.static(__dirname + '/js'));
app.use('/trainControlImages', express.static(__dirname + '/trainControlImages'));
app.get('/', function(req, res) {
  res.render('trainControls.jade', { layout: false });
});
app.listen(8080)
<|endoftext|>


<commit_before>define(['angular', 'angular-mocks', 'user/user-module-inc'], function (angular, mocks, damageTypeModule) {

    'use strict';

    var controllerName = 'UserCreateCtrl';

    var userNameMissingError = 'Username is required';  // TODO use error code

    describe('Controller: ' + controllerName, function () {
        //var controller;
        var $scope;

        var UserServiceMock;

        // TODO fake roles
        var roles = [
            {'id': '1', 'rolename': 'user'},
            {'id': '2', 'rolename': 'admin'}
        ];

        // load the module
        beforeEach(module('userModule'));

        // Initialize the controller and a mock scope
        beforeEach(inject(function ($controller, $rootScope, $q, _UserService_) {
            $scope = $rootScope.$new();
            UserServiceMock = _UserService_;

            //spyOn(UserServiceMock, 'create').and.returnValue($q.when({name: 'foo'}));
            spyOn(UserServiceMock, 'create').and.callFake(function (user) {
                var deferred = $q.defer();

                // fail if there is no username provided
                if (user.username === undefined) {
                    var error = {
                        status: 422,
                        data: {
                            username: userNameMissingError
                        }
                    };
                    deferred.reject(error);
                }
                else {
                    deferred.resolve(user);
                }

                return deferred.promise;
            });

            spyOn(UserServiceMock, 'showList').and.returnValue();

            $controller(controllerName, {
                $scope: $scope,
                roles: roles
            });
        }));

        it('should create an emoty user upon creation', function () {
            expect($scope.user).not.toBe(undefined);
        });

        it('should attach userRoles upon creation', function () {
            expect($scope.userRoles.length).toEqual(roles.length);
            expect($scope.userRoles).toContain({id: '1', rolename: 'user', selected: false});
            expect($scope.userRoles).toContain({id: '2', rolename: 'admin', selected: false});
        });

        it('should add selected user roles to the user roles list', function () {
            expect($scope.user.roles.length).toEqual(0);
            $scope.userRoles[0].selected = true;

            // invoke save function on controller
            $scope.save();

            expect($scope.user.roles.length).toEqual(1);
            expect($scope.user.roles).toContain({id: '1', rolename: 'user'});
        });

        it('should show the user list after successfully creating a new user', function () {
            $scope.user.username = 'axton';
            // invoke save function on controller
            $scope.save();

            expect(UserServiceMock.create).toHaveBeenCalled();
            $scope.$digest();
            expect(UserServiceMock.showList).toHaveBeenCalled();
            expect($scope.errors).toEqual(null);
        });

        it('should stay on the same page and show validation errors', function () {
            // invoke action on controller
            $scope.save();

            expect(UserServiceMock.create).toHaveBeenCalled();
            $scope.$digest();

            // userlist won't be shown
            expect(UserServiceMock.showList).not.toHaveBeenCalled();

            // errors needs to be added to scaope
            expect($scope.errors).not.toEqual(null);
            expect($scope.errors.username).toEqual(userNameMissingError);
        });

        it ('should show the user list when executing the cancel action', function(){
            // invoke action on controller
            $scope.cancel();

            expect(UserServiceMock.showList).toHaveBeenCalled();
        });

    });

});
<commit_msg>create unit test for UserCreateCtrl<commit_after>define(['angular', 'angular-mocks', 'user/user-module-inc'], function (angular, mocks, damageTypeModule) {

    'use strict';

    var controllerName = 'UserCreateCtrl';

    var userNameMissingError = 'Username is required';  // TODO use error code

    describe('Controller: ' + controllerName, function () {
        var $scope;

        var UserServiceMock;

        // TODO fake roles
        var roles = [
            {'id': '1', 'rolename': 'user'},
            {'id': '2', 'rolename': 'admin'}
        ];

        // load the module
        beforeEach(module('userModule'));

        // Initialize the controller and a mock scope
        beforeEach(inject(function ($controller, $rootScope, $q, _UserService_) {
            $scope = $rootScope.$new();
            UserServiceMock = _UserService_;

            //spyOn(UserServiceMock, 'create').and.returnValue($q.when({name: 'foo'}));
            spyOn(UserServiceMock, 'create').and.callFake(function (user) {
                var deferred = $q.defer();

                // fail if there is no username provided
                if (user.username === undefined) {
                    var error = {
                        status: 422,
                        data: {
                            username: userNameMissingError
                        }
                    };
                    deferred.reject(error);
                }
                else {
                    deferred.resolve(user);
                }

                return deferred.promise;
            });

            spyOn(UserServiceMock, 'showList').and.returnValue();

            $controller(controllerName, {
                $scope: $scope,
                roles: roles
            });
        }));

        it('should create an emoty user upon creation', function () {
            expect($scope.user).not.toBe(undefined);
        });

        it('should attach userRoles upon creation', function () {
            expect($scope.userRoles.length).toEqual(roles.length);
            expect($scope.userRoles).toContain({id: '1', rolename: 'user', selected: false});
            expect($scope.userRoles).toContain({id: '2', rolename: 'admin', selected: false});
        });

        it('should add selected user roles to the user roles list', function () {
            expect($scope.user.roles.length).toEqual(0);
            $scope.userRoles[0].selected = true;

            // invoke save function on controller
            $scope.save();

            expect($scope.user.roles.length).toEqual(1);
            expect($scope.user.roles).toContain({id: '1', rolename: 'user'});
        });

        it('should show the user list after successfully creating a new user', function () {
            $scope.user.username = 'axton';
            // invoke save function on controller
            $scope.save();

            expect(UserServiceMock.create).toHaveBeenCalled();
            $scope.$digest();
            expect(UserServiceMock.showList).toHaveBeenCalled();
            expect($scope.errors).toEqual(null);
        });

        it('should stay on the same page and show validation errors', function () {
            // invoke action on controller
            $scope.save();

            expect(UserServiceMock.create).toHaveBeenCalled();
            $scope.$digest();

            // userlist won't be shown
            expect(UserServiceMock.showList).not.toHaveBeenCalled();

            // errors needs to be added to scaope
            expect($scope.errors).not.toEqual(null);
            expect($scope.errors.username).toEqual(userNameMissingError);
        });

        it ('should show the user list when executing the cancel action', function(){
            // invoke action on controller
            $scope.cancel();

            expect(UserServiceMock.showList).toHaveBeenCalled();
        });

    });

});
<|endoftext|>


<commit_before>import { Tile } from "./tile";
import { TileArea } from "./tilearea";

/**
 * A tile layer object containing tiles and other properties.
 */
export class TileLayer extends TileArea {
	/**
	 * TileLayer constructor.
	 *
	 * @param {TileMap} parentMap - The parent map for this layer.
	 * @param {object} options - Options for the layer. Can also be layer data you loaded from JSON or similar.
	 * @param {string} [options.name="Tilelayer"] - {@link TileLayer#name}
	 * @param {Tile[]} options.tiles=[] - {@link TileLayer#tiles}
	 * @param {Map<string, *>} options.properties=Map - {@link TileLayer#properties}
	 */
	constructor(parentMap, options) {
		super(parentMap.width, parentMap.height);

		/** The name of the tile layer.
		 * @type {string} */
		this.name = options.name || "Tilelayer";

		/** The tiles of the layer.
		 * @type {Tile[]} */
		this.tiles = [];
		for (let y = 0; y < parentMap.height; y++) {
			for (let x = 0; x < parentMap.width; x++) {
				const tile = new Tile(
					options.tiles
					? options.tiles[x % parentMap.width + y * parentMap.width]
					: {}
				);
				this.tiles.push(tile);
			}
		}

		/** Custom properties of the layer.
		 * @type {Map<string, *>} */
		this.properties = options.properties || new Map();
	}
}
<commit_msg>Change default tile values<commit_after>import { Tile } from "./tile";
import { TileArea } from "./tilearea";

/**
 * A tile layer object containing tiles and other properties.
 */
export class TileLayer extends TileArea {
	/**
	 * TileLayer constructor.
	 *
	 * @param {TileMap} parentMap - The parent map for this layer.
	 * @param {object} options - Options for the layer. Can also be layer data you loaded from JSON or similar.
	 * @param {string} [options.name="Tilelayer"] - {@link TileLayer#name}
	 * @param {Tile[]} options.tiles=[] - {@link TileLayer#tiles}
	 * @param {Map<string, *>} options.properties=Map - {@link TileLayer#properties}
	 */
	constructor(parentMap, options) {
		super(parentMap.width, parentMap.height);

		/** The name of the tile layer.
		 * @type {string} */
		this.name = options.name || "Tilelayer";

		/** The tiles of the layer.
		 * @type {Tile[]} */
		this.tiles = [];
		for (let y = 0; y < parentMap.height; y++) {
			for (let x = 0; x < parentMap.width; x++) {
				const tile = new Tile(
					options.tiles
					? options.tiles[x % parentMap.width + y * parentMap.width]
					: { tileId: -1, tilesetId: 0 }
				);
				this.tiles.push(tile);
			}
		}

		/** Custom properties of the layer.
		 * @type {Map<string, *>} */
		this.properties = options.properties || new Map();
	}
}
<|endoftext|>


<commit_before>const slugify = require('slugify')
const { getDesigners, getProjects, resetDesignerFile, resetProjectFile } = require('./data')

module.exports = main

const slugifyLower = str => slugify(str, {
  lower: true,
  remove: /[$*+~.()'"!\:@]/g
})

async function main () {
  await processProjects()
  await processDesigners()
}

async function processProjects () {
  const projects = await getProjects()

  const impureProjects = projects.filter(project =>
    project.slug !== slugifyLower(project.slug)
  )

  await Promise.all(impureProjects.map(project => {
    const pureProject = Object.assign({}, project, {
      slug: slugifyLower(project.slug)
    })

    return resetProjectFile(pureProject)
  }))
}

async function processDesigners () {
  const designers = await getDesigners()

  const impureDesigners = designers.filter(designer =>
    designer.slug !== slugifyLower(designer.slug) ||
    (designer.works || []).filter(work =>
      work && work.slug !== slugifyLower(work.slug)
    ).length > 0
  )

  await Promise.all(impureDesigners.map(designer => {
    const pureDesigner = Object.assign({}, designer, {
      slug: slugifyLower(designer.slug),
      works: (designer.works || []).map(work => Object.assign({}, work, {
        slug: slugifyLower(work.slug)
      }))
    })

    return resetDesignerFile(pureDesigner)
  }))
}
<commit_msg>bugfix: better missing work fix<commit_after>const slugify = require('slugify')
const { getDesigners, getProjects, resetDesignerFile, resetProjectFile } = require('./data')

module.exports = main

const slugifyLower = str => slugify(str, {
  lower: true,
  remove: /[$*+~.()'"!\:@]/g
})

async function main () {
  await processProjects()
  await processDesigners()
}

async function processProjects () {
  const projects = await getProjects()

  const impureProjects = projects.filter(project =>
    project.slug !== slugifyLower(project.slug)
  )

  await Promise.all(impureProjects.map(project => {
    const pureProject = Object.assign({}, project, {
      slug: slugifyLower(project.slug)
    })

    return resetProjectFile(pureProject)
  }))
}

async function processDesigners () {
  const designers = await getDesigners()

  const impureDesigners = designers.filter(designer =>
    designer.slug !== slugifyLower(designer.slug) ||
    (designer.works || []).filter(work =>
      work.slug && work.slug !== slugifyLower(work.slug)
    ).length > 0
  )

  await Promise.all(impureDesigners.map(designer => {
    const pureDesigner = Object.assign({}, designer, {
      slug: slugifyLower(designer.slug),
      works: (designer.works || []).map(work => Object.assign({}, work, {
        slug: slugifyLower(work.slug)
      }))
    })

    return resetDesignerFile(pureDesigner)
  }))
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { incrementCounter, decrementCounter } from 'modules/counter/ducks'

export const CounterContainer = ({ increment, decrement, counterValue }) => (

Redux Counter

      Lorem ipsum dolor sit amet, an eius aeque est, vel vidisse fuisset rationibus an. Eu nam
      ullum consul. Te putant scripta albucius pri, vim oblique scriptorem in. Eos te mazim
      aliquip, ea erat utinam oblique cum, has simul scripta tractatos et.

      Current counter value is: {counterValue}

    <button onClick={increment}>Increment</button>
    <button onClick={decrement}>Decrement</button>

)

CounterContainer.propTypes = {
  increment: PropTypes.func.isRequired,
  decrement: PropTypes.func.isRequired,
  counterValue: PropTypes.number.isRequired,
}

const mapStateToProps = state => ({
  counterValue: state.counter.value,
})

const mapDispatchToProps = dispatch => ({
  increment: () => dispatch(incrementCounter()),
  decrement: () => dispatch(decrementCounter()),
})

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(CounterContainer)
<commit_msg>Polish source code<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { incrementCounter, decrementCounter } from 'modules/counter/ducks'

export const CounterContainer = ({ increment, decrement, counterValue }) => (

Redux Counter

      Lorem ipsum dolor sit amet, an eius aeque est, vel vidisse fuisset rationibus an. Eu nam
      ullum consul. Te putant scripta albucius pri, vim oblique scriptorem in. Eos te mazim
      aliquip, ea erat utinam oblique cum, has simul scripta tractatos et.

      Current counter value is: {counterValue}

    <button onClick={increment}>Increment</button>
    <button onClick={decrement}>Decrement</button>

)

CounterContainer.propTypes = {
  increment: PropTypes.func.isRequired,
  decrement: PropTypes.func.isRequired,
  counterValue: PropTypes.number.isRequired,
}

const mapStateToProps = state => ({
  counterValue: state.counter.value,
})

const mapDispatchToProps = {
  increment: incrementCounter,
  decrement: decrementCounter,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(CounterContainer)
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Tool = this.Tool = ToolHandler.extend(new function() {
	function viewToArtwork(event, document) {
		// TODO: always the active view?
		return document.activeView.viewToArtwork(DomEvent.getOffset(event));
	};

	return {
		beans: true,

		initialize: function(handlers, doc) {
			this.base(handlers, doc._scope);
			this._document = doc;

			var curPoint;
			var dragging = false;
			var that = this;
			// TODO: Move event handling to DocumentView
			var events = {
				mousedown: function(event) {
					curPoint = viewToArtwork(event, that._document);
					that.onHandleEvent('mousedown', curPoint, event);
					if (that.onMouseDown) {
						that._document.redraw();
					}
					if (that.eventInterval != null) {
						this.timer = setInterval(events.mousemove,
								that.eventInterval);
					}
					dragging = true;
				},

				mousemove: function(event) {
					// If the event was triggered by a touch screen device,
					// prevent the default behaviour, as it will otherwise
					// scroll the page:
					var touchDevice = event && event.targetTouches;
					if (touchDevice) {
						DomEvent.preventDefault(event);
					}
					var point = event && viewToArtwork(event, that._document);
					// If there is only an onMouseMove handler, call it when
					// the user is dragging
					var onlyMove = !!(!that.onMouseDrag && that.onMouseMove);
					if (dragging && !onlyMove) {
						curPoint = point || curPoint;
						if (curPoint) {
							that.onHandleEvent('mousedrag', curPoint, event);
						}
					} else if (!dragging || onlyMove) {
						that.onHandleEvent('mousemove', point, event);
					}
					if (that.onMouseMove || touchDevice && that.onMouseDrag) {
						that._document.redraw();
					}
				},

				mouseup: function(event) {
					if (dragging) {
						curPoint = null;
						if (that.eventInterval != null) {
							clearInterval(this.timer);
						}
						that.onHandleEvent('mouseup',
								viewToArtwork(event, that._document), event);
						if (that.onMouseUp) {
							that._document.redraw();
						}
						dragging = false;
					}
				},

				touchmove: function(event) {
					events.mousemove(event);
				},

				touchstart: function(event) {
					events.mousedown(event);
				},

				touchend: function(event) {
					events.mouseup(event);
				}
			};

			DomEvent.add(doc.canvas, events);
		},

		getDocument: function() {
			return this._document;
		},

		/**
		 * The fixed time delay between each call to the {@link #onMouseDrag}
		 * event. Setting this to an interval means the {@link #onMouseDrag}
		 * event is called repeatedly after the initial {@link #onMouseDown}
		 * until the user releases the mouse.
		 *
		 * Sample code:
		 *
		 * // Fire the onMouseDrag event once a second,
		 * // while the mouse button is down
		 * tool.eventInterval = 1000;
		 *
		 *
		 * @return the interval time in milliseconds
		 */
		eventInterval: null
	};
});
<commit_msg>Fix bug where document wasn't being redrawn after onMouseDrag events.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Tool = this.Tool = ToolHandler.extend(new function() {
	function viewToArtwork(event, document) {
		// TODO: always the active view?
		return document.activeView.viewToArtwork(DomEvent.getOffset(event));
	};

	return {
		beans: true,

		initialize: function(handlers, doc) {
			this.base(handlers, doc._scope);
			this._document = doc;

			var curPoint;
			var dragging = false;
			var that = this;
			// TODO: Move event handling to DocumentView
			var events = {
				mousedown: function(event) {
					curPoint = viewToArtwork(event, that._document);
					that.onHandleEvent('mousedown', curPoint, event);
					if (that.onMouseDown) {
						that._document.redraw();
					}
					if (that.eventInterval != null) {
						this.timer = setInterval(events.mousemove,
								that.eventInterval);
					}
					dragging = true;
				},

				mousemove: function(event) {
					// If the event was triggered by a touch screen device,
					// prevent the default behaviour, as it will otherwise
					// scroll the page:
					if (event && event.targetTouches) {
						DomEvent.preventDefault(event);
					}
					var point = event && viewToArtwork(event, that._document);
					var onlyMove = !!(!that.onMouseDrag && that.onMouseMove);
					if (dragging && !onlyMove) {
						curPoint = point || curPoint;
						if (curPoint) {
							that.onHandleEvent('mousedrag', curPoint, event);
						}
						if (that.onMouseDrag)
							that._document.redraw();
					// PORT: If there is only an onMouseMove handler, also
					// call it when the user is dragging:
					} else if (!dragging || onlyMove) {
						that.onHandleEvent('mousemove', point, event);
						if (that.onMouseMove)
							that._document.redraw();
					}
				},

				mouseup: function(event) {
					if (dragging) {
						curPoint = null;
						if (that.eventInterval != null) {
							clearInterval(this.timer);
						}
						that.onHandleEvent('mouseup',
								viewToArtwork(event, that._document), event);
						if (that.onMouseUp) {
							that._document.redraw();
						}
						dragging = false;
					}
				},

				touchmove: function(event) {
					events.mousemove(event);
				},

				touchstart: function(event) {
					events.mousedown(event);
				},

				touchend: function(event) {
					events.mouseup(event);
				}
			};

			DomEvent.add(doc.canvas, events);
		},

		getDocument: function() {
			return this._document;
		},

		/**
		 * The fixed time delay between each call to the {@link #onMouseDrag}
		 * event. Setting this to an interval means the {@link #onMouseDrag}
		 * event is called repeatedly after the initial {@link #onMouseDown}
		 * until the user releases the mouse.
		 *
		 * Sample code:
		 *
		 * // Fire the onMouseDrag event once a second,
		 * // while the mouse button is down
		 * tool.eventInterval = 1000;
		 *
		 *
		 * @return the interval time in milliseconds
		 */
		eventInterval: null
	};
});
<|endoftext|>


<commit_before>// This is the performance API.
// Golden Rule: everything starts with `var self = this` and ends with `return self`.

function _joinArgs(args) {
  args = Array.prototype.slice.call(args);
  for(var i = 1; i < args.length; i++) {
    args[0] = args[0].concat(args[i]);
  }
  return args[0];
}

// _parseArguments takes multiple array arguments and stitches them into a one-dimensional array.
// function _parseArguments(args) {
//   if(Array.isArray(args[0])) {
//     args = _joinArgs(args);
//   }
//   return args;
// }

// new method of array flattening
function _parseArguments(args) {
  args = Array.prototype.slice.call(args);
  var flattened = [];
  args.forEach( function(item) {
    flattened = flattened.concat(item);
  });
  return flattened;
}

track.prototype.beat = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._beatPattern.set(arguments, 16);
  return self;
};

track.prototype.beat32 = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._beatPattern.set(arguments, 32);
  return self;
};

track.prototype.notes = function() {
  var self = this;
  // let's allow an array of notes as well
  var arguments = _parseArguments(arguments);
  self._notesSequencer.set(arguments);
  if(arguments.length == 0) {
    self._currentNote = 64;
  }
  return self;
};

track.prototype.nl = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._noteLengthSequencer.set(arguments);
  if(arguments.length) {
    // nl will be 16th notes, so we need to multiply everything by 2
    for(var i = 0; i < arguments.length; i++) {
      arguments[i] *= 2;
    }
  } else {
    // reasonable default -> nl = 16th note
    self._currentNoteLength = 2;
  }
  return self;
};

track.prototype.nl32 = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._noteLengthSequencer.set(arguments);
  if(arguments.length == 0) {
    // reasonable default -> nl = 16th note
    self._currentNoteLength = 2;
  }
  return self;
};

track.prototype.trans = function(semitones) {
  var self = this;
  for(var i = 0; i < self._notesSequencer.pattern.length; i++) {
    if(typeof self._notesSequencer.pattern[i] !== 'function') {
      self._notesSequencer.pattern[i] = self._notesSequencer.pattern[i] + semitones;
    }
  }
  return self;
};

track.prototype.shift = function(amount) {
  var self = this;
  self._schedulers[0].untilNextBeat += amount;
  if(self._schedulers[0].untilNextBeat < 0) {
    self._schedulers[0].untilNextBeat = 0;
  }
  return self;
};

// -1 is left, 1 is right, 0 is center
track.prototype.pan = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._panSequencer.set(arguments);
  if(arguments.length == 0) {
    self._panSequencer.set([0]);
  }
  return self;
};

// ------------------------------------------------------------------ OSCILLATORS

var SINE = "sine";
var SQUARE = "square";
var SAWTOOTH = "sawtooth";
var TRIANGLE = "triangle";

track.prototype.sine = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SINE;
  return self;
};

track.prototype.square = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SQUARE;
  return self;
};

track.prototype.saw = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SAWTOOTH;
  return self;
};

track.prototype.tri = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = TRIANGLE;
  return self;
};

// oscillator type sequencer! 0 to 3 or SINE, SQUARE, TRIANGLE, SAWTOOTH
track.prototype.type = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._oscTypeSequencer.set(arguments);
  if(arguments.length == 0) {
    self._oscType = SINE;
  }
  return self;
};

// ------------------------------------------------------------------ ENVELOPE

track.prototype.vol = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._volumeSequencer.set(arguments);
  if(arguments.length == 0) {
    self._volume = 0;
  }
  return self;
};

track.prototype.adsr = function() {
  var self = this;
  var resolutionModifier = clock.bpmResolution / 16;
  // arguments isn't really an array so we have to turn it into one
  var arguments = Array.prototype.slice.call(arguments);
  // arguments = _parseArguments(arguments);
  self._applyAdsrArguments(arguments, resolutionModifier);
  return self;
};

track.prototype.adsr32 = function() {
  var self = this;
  var resolutionModifier = clock.bpmResolution / 32;
  // arguments isn't really an array so we have to turn it into one
  var arguments = Array.prototype.slice.call(arguments);
  // arguments = _parseArguments(arguments);
  self._applyAdsrArguments(arguments, resolutionModifier);
  return self;
};

track.prototype._applyAdsrArguments = function(args, resolutionModifier) {
  var self = this;

  // a helper function
  function modify(arg) {
    if(typeof(arg) === 'number') {
      return arg * resolutionModifier;
    } else if(typeof(arg) === 'function') {
      // wrap the callback in our own that multiplies it by the res modifier
      return function() {
        return arg() * resolutionModifier;
      };
    }
  }

  // if we get an array as a first argument, we will assume all args are arrays.
  if(args.length > 0 && Array.isArray(args[0])) {
    args = args.map( function(arg) {
      // for some reason these were refs to the same array or something?
      arg = Array.prototype.slice.call(arg);
      // we don't want silly errors
      if(arg.length < 4) {
        return [0, 0, 1 * resolutionModifier, 0];
      }
      arg[0] = modify(arg[0]);
      arg[1] = modify(arg[1]);
      // sustain does not get modified
      arg[3] = modify(arg[3]);
      return arg;
    });
    self._adsrSequencer.set(args);
  }
  // ...or it's just four values.
  else if(args.length == 4) {
    args[0] = modify(args[0]);
    args[1] = modify(args[1]);
    // sustain does not get modified
    args[3] = modify(args[3]);
    self._adsrSequencer.set([args]);
  }
  // back to the defaults
  else {
    self._attack = self._decay = self._release = 0;
    self._sustain = 1;
    self._adsrSequencer.set([]);
  }
};

// ------------------------------------------------------------------ SAMPLER

// sample buffers
track.prototype.sample = function() {
  var self = this;
  self._samples = [];
  var arguments = Array.prototype.slice.call(arguments);
  arguments = _parseArguments(arguments);
  arguments.forEach( function(buffer) {
    self._samples.push( new Sample(buffer) );
  });
  if(arguments.length) {
    self._currentSample = self._samples[0];
    self._editingSample = self._samples[0];
  }
  return self;
};

track.prototype.play = function(overflow) {
  var self = this;
  if(self._currentSample) {
    // reset the current sample
    self._currentSample.defaultParams();
    // reset the beat, note length, adsr
    var beatLength = self._currentSample.getBeatLength(overflow);
    self.beat32(beatLength);
    self.nl(beatLength);
    self.adsr();
  }
  return self;
};

track.prototype.addsamples = function() {
  var self = this;
  var arguments = Array.prototype.slice.call(arguments);
  arguments.forEach( function(buffer) {
    self._samples.push( new Sample(buffer) );
  });
  return self;
};

track.prototype.select = function(index) {
  var self = this;
  if(index < self._samples.length) {
    self._editingSample = self._samples[index];
  }
  return self;
};

// sample sequence
track.prototype.sseq = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  // safeguard against errors for indices past the available length
  for(var i = 0; i < arguments.length; i++) {
    if(arguments[i] >= self._samples.length) {
      arguments[i] = self._samples.length - 1;
    }
  }
  self._currentSampleSequencer.set(arguments);
  return self;
};

track.prototype.clamp = function(start, end) {
  var self = this;
  if(self._editingSample) {
    if(end == null) {
      self._editingSample.loopStart = (0);
      self._editingSample.loopEnd = (start);
    } else {
      self._editingSample.loopStart = (start || 0);
      self._editingSample.loopEnd = (end || 1);
    }
  }
  return self;
};

track.prototype.cs = track.prototype.clshift = function() {
  var self = this;
  if(self._editingSample) {
    var arguments = _parseArguments(arguments);
    self._editingSample.clampShiftSequencer.set(arguments);
  }
  return self;
};

track.prototype.loop = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length && arguments[0]) {
      self._editingSample.looping = true;
    } else {
      self._editingSample.looping = false;
    }
  }
  return self;
};

track.prototype.stretch = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length) {
      // self._editingSample.stretchToFit = arguments[0] * (clock.bpmResolution / 16);
      var arguments = _parseArguments(arguments);
      for(var i = 0; i < arguments.length; i++) {
        arguments[i] = arguments[i] * (clock.bpmResolution / 16);
      }
      self._editingSample.stretchSequencer.set(arguments);
    } else {
      self._editingSample.speed = 1;
      self._editingSample.stretchToFit = null;
      self._editingSample.stretchSequencer.set([]);
    }
  }
  return self;
};

track.prototype.speed = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length) {
      self._editingSample.speedSequencer.set(arguments);
      // self._editingSample.speed = arguments[0];
      self._editingSample.stretchToFit = null;
    } else {
      self._editingSample.speed = 1;
      self._editingSample.stretchToFit = null;
    }
  }
  return self;
};

track.prototype.reverse = function() {
  var self = this;
  if(self._editingSample) {
    // need to make a new buffer to perform this operation on so we don't scuff the original.
    var oldBuffer = self._editingSample.buffer;
    var newBuffer = context.createBuffer(oldBuffer.numberOfChannels, oldBuffer.length, oldBuffer.sampleRate);
    for(var i = 0; i < oldBuffer.numberOfChannels; i++) {
      newBuffer.getChannelData(i).set(Array.prototype.reverse.call( new Float32Array(oldBuffer.getChannelData(i)) ));
    }
    self._editingSample.buffer = newBuffer;
  }
  return self;
};

track.prototype.root = function(note) {
  var self = this;
  if(self._editingSample) {
    self._editingSample.rootNote = note;
  }
  return self;
};

track.prototype.render = function(length) {
  var self = this;
  self._render(length, 16);
  return self;
};

track.prototype.render32 = function(length) {
  var self = this;
  self._render(length, 32);
  return self;
};

// reset event, which should be used by effects to quickly turn everything off
track.prototype.reset = function() {
  var self = this;
  self._emit('reset');
  return self;
};

track.prototype.eval = function() {
  var self = this;
  arguments = _parseArguments(arguments);
  self._evalSequencer.set(arguments);
  return self;
};

// ------------------------------------------------------------------ WEIRD

track.prototype.in = function(count) {
  var self = this;
  // return an instance of the _in queue,
  // which allows us to stage changes
  // for later.
  return new self._in(count);
};

track.prototype.log = function() {
  console.log(arguments);
  return this;
};<commit_msg>fixed a bug where `nl` was coming through in half-time<commit_after>// This is the performance API.
// Golden Rule: everything starts with `var self = this` and ends with `return self`.

function _joinArgs(args) {
  args = Array.prototype.slice.call(args);
  for(var i = 1; i < args.length; i++) {
    args[0] = args[0].concat(args[i]);
  }
  return args[0];
}

// _parseArguments takes multiple array arguments and stitches them into a one-dimensional array.
// function _parseArguments(args) {
//   if(Array.isArray(args[0])) {
//     args = _joinArgs(args);
//   }
//   return args;
// }

// new method of array flattening
function _parseArguments(args) {
  args = Array.prototype.slice.call(args);
  var flattened = [];
  args.forEach( function(item) {
    flattened = flattened.concat(item);
  });
  return flattened;
}

track.prototype.beat = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._beatPattern.set(arguments, 16);
  return self;
};

track.prototype.beat32 = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._beatPattern.set(arguments, 32);
  return self;
};

track.prototype.notes = function() {
  var self = this;
  // let's allow an array of notes as well
  var arguments = _parseArguments(arguments);
  self._notesSequencer.set(arguments);
  if(arguments.length == 0) {
    self._currentNote = 64;
  }
  return self;
};

track.prototype.nl = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  if(arguments.length) {
    // nl will be 16th notes, so we need to multiply everything by 2
    for(var i = 0; i < arguments.length; i++) {
      arguments[i] *= 2;
    }
  } else {
    // reasonable default -> nl = 16th note
    self._currentNoteLength = 2;
  }
  self._noteLengthSequencer.set(arguments);
  return self;
};

track.prototype.nl32 = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._noteLengthSequencer.set(arguments);
  if(arguments.length == 0) {
    // reasonable default -> nl = 16th note
    self._currentNoteLength = 2;
  }
  return self;
};

track.prototype.trans = function(semitones) {
  var self = this;
  for(var i = 0; i < self._notesSequencer.pattern.length; i++) {
    if(typeof self._notesSequencer.pattern[i] !== 'function') {
      self._notesSequencer.pattern[i] = self._notesSequencer.pattern[i] + semitones;
    }
  }
  return self;
};

track.prototype.shift = function(amount) {
  var self = this;
  self._schedulers[0].untilNextBeat += amount;
  if(self._schedulers[0].untilNextBeat < 0) {
    self._schedulers[0].untilNextBeat = 0;
  }
  return self;
};

// -1 is left, 1 is right, 0 is center
track.prototype.pan = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._panSequencer.set(arguments);
  if(arguments.length == 0) {
    self._panSequencer.set([0]);
  }
  return self;
};

// ------------------------------------------------------------------ OSCILLATORS

var SINE = "sine";
var SQUARE = "square";
var SAWTOOTH = "sawtooth";
var TRIANGLE = "triangle";

track.prototype.sine = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SINE;
  return self;
};

track.prototype.square = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SQUARE;
  return self;
};

track.prototype.saw = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = SAWTOOTH;
  return self;
};

track.prototype.tri = function() {
  var self = this;
  if(self._oscTypeSequencer.pattern.length) {
    // clear the oscType sequencer if it had a pattern
    self._oscTypeSequencer.set([]);
  }
  self._oscType = TRIANGLE;
  return self;
};

// oscillator type sequencer! 0 to 3 or SINE, SQUARE, TRIANGLE, SAWTOOTH
track.prototype.type = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._oscTypeSequencer.set(arguments);
  if(arguments.length == 0) {
    self._oscType = SINE;
  }
  return self;
};

// ------------------------------------------------------------------ ENVELOPE

track.prototype.vol = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  self._volumeSequencer.set(arguments);
  if(arguments.length == 0) {
    self._volume = 0;
  }
  return self;
};

track.prototype.adsr = function() {
  var self = this;
  var resolutionModifier = clock.bpmResolution / 16;
  // arguments isn't really an array so we have to turn it into one
  var arguments = Array.prototype.slice.call(arguments);
  // arguments = _parseArguments(arguments);
  self._applyAdsrArguments(arguments, resolutionModifier);
  return self;
};

track.prototype.adsr32 = function() {
  var self = this;
  var resolutionModifier = clock.bpmResolution / 32;
  // arguments isn't really an array so we have to turn it into one
  var arguments = Array.prototype.slice.call(arguments);
  // arguments = _parseArguments(arguments);
  self._applyAdsrArguments(arguments, resolutionModifier);
  return self;
};

track.prototype._applyAdsrArguments = function(args, resolutionModifier) {
  var self = this;

  // a helper function
  function modify(arg) {
    if(typeof(arg) === 'number') {
      return arg * resolutionModifier;
    } else if(typeof(arg) === 'function') {
      // wrap the callback in our own that multiplies it by the res modifier
      return function() {
        return arg() * resolutionModifier;
      };
    }
  }

  // if we get an array as a first argument, we will assume all args are arrays.
  if(args.length > 0 && Array.isArray(args[0])) {
    args = args.map( function(arg) {
      // for some reason these were refs to the same array or something?
      arg = Array.prototype.slice.call(arg);
      // we don't want silly errors
      if(arg.length < 4) {
        return [0, 0, 1 * resolutionModifier, 0];
      }
      arg[0] = modify(arg[0]);
      arg[1] = modify(arg[1]);
      // sustain does not get modified
      arg[3] = modify(arg[3]);
      return arg;
    });
    self._adsrSequencer.set(args);
  }
  // ...or it's just four values.
  else if(args.length == 4) {
    args[0] = modify(args[0]);
    args[1] = modify(args[1]);
    // sustain does not get modified
    args[3] = modify(args[3]);
    self._adsrSequencer.set([args]);
  }
  // back to the defaults
  else {
    self._attack = self._decay = self._release = 0;
    self._sustain = 1;
    self._adsrSequencer.set([]);
  }
};

// ------------------------------------------------------------------ SAMPLER

// sample buffers
track.prototype.sample = function() {
  var self = this;
  self._samples = [];
  var arguments = Array.prototype.slice.call(arguments);
  arguments = _parseArguments(arguments);
  arguments.forEach( function(buffer) {
    self._samples.push( new Sample(buffer) );
  });
  if(arguments.length) {
    self._currentSample = self._samples[0];
    self._editingSample = self._samples[0];
  }
  return self;
};

track.prototype.play = function(overflow) {
  var self = this;
  if(self._currentSample) {
    // reset the current sample
    self._currentSample.defaultParams();
    // reset the beat, note length, adsr
    var beatLength = self._currentSample.getBeatLength(overflow);
    self.beat32(beatLength);
    self.nl(beatLength);
    self.adsr();
  }
  return self;
};

track.prototype.addsamples = function() {
  var self = this;
  var arguments = Array.prototype.slice.call(arguments);
  arguments.forEach( function(buffer) {
    self._samples.push( new Sample(buffer) );
  });
  return self;
};

track.prototype.select = function(index) {
  var self = this;
  if(index < self._samples.length) {
    self._editingSample = self._samples[index];
  }
  return self;
};

// sample sequence
track.prototype.sseq = function() {
  var self = this;
  var arguments = _parseArguments(arguments);
  // safeguard against errors for indices past the available length
  for(var i = 0; i < arguments.length; i++) {
    if(arguments[i] >= self._samples.length) {
      arguments[i] = self._samples.length - 1;
    }
  }
  self._currentSampleSequencer.set(arguments);
  return self;
};

track.prototype.clamp = function(start, end) {
  var self = this;
  if(self._editingSample) {
    if(end == null) {
      self._editingSample.loopStart = (0);
      self._editingSample.loopEnd = (start);
    } else {
      self._editingSample.loopStart = (start || 0);
      self._editingSample.loopEnd = (end || 1);
    }
  }
  return self;
};

track.prototype.cs = track.prototype.clshift = function() {
  var self = this;
  if(self._editingSample) {
    var arguments = _parseArguments(arguments);
    self._editingSample.clampShiftSequencer.set(arguments);
  }
  return self;
};

track.prototype.loop = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length && arguments[0]) {
      self._editingSample.looping = true;
    } else {
      self._editingSample.looping = false;
    }
  }
  return self;
};

track.prototype.stretch = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length) {
      // self._editingSample.stretchToFit = arguments[0] * (clock.bpmResolution / 16);
      var arguments = _parseArguments(arguments);
      for(var i = 0; i < arguments.length; i++) {
        arguments[i] = arguments[i] * (clock.bpmResolution / 16);
      }
      self._editingSample.stretchSequencer.set(arguments);
    } else {
      self._editingSample.speed = 1;
      self._editingSample.stretchToFit = null;
      self._editingSample.stretchSequencer.set([]);
    }
  }
  return self;
};

track.prototype.speed = function() {
  var self = this;
  if(self._editingSample) {
    if(arguments.length) {
      self._editingSample.speedSequencer.set(arguments);
      // self._editingSample.speed = arguments[0];
      self._editingSample.stretchToFit = null;
    } else {
      self._editingSample.speed = 1;
      self._editingSample.stretchToFit = null;
    }
  }
  return self;
};

track.prototype.reverse = function() {
  var self = this;
  if(self._editingSample) {
    // need to make a new buffer to perform this operation on so we don't scuff the original.
    var oldBuffer = self._editingSample.buffer;
    var newBuffer = context.createBuffer(oldBuffer.numberOfChannels, oldBuffer.length, oldBuffer.sampleRate);
    for(var i = 0; i < oldBuffer.numberOfChannels; i++) {
      newBuffer.getChannelData(i).set(Array.prototype.reverse.call( new Float32Array(oldBuffer.getChannelData(i)) ));
    }
    self._editingSample.buffer = newBuffer;
  }
  return self;
};

track.prototype.root = function(note) {
  var self = this;
  if(self._editingSample) {
    self._editingSample.rootNote = note;
  }
  return self;
};

track.prototype.render = function(length) {
  var self = this;
  self._render(length, 16);
  return self;
};

track.prototype.render32 = function(length) {
  var self = this;
  self._render(length, 32);
  return self;
};

// reset event, which should be used by effects to quickly turn everything off
track.prototype.reset = function() {
  var self = this;
  self._emit('reset');
  return self;
};

track.prototype.eval = function() {
  var self = this;
  arguments = _parseArguments(arguments);
  self._evalSequencer.set(arguments);
  return self;
};

// ------------------------------------------------------------------ WEIRD

track.prototype.in = function(count) {
  var self = this;
  // return an instance of the _in queue,
  // which allows us to stage changes
  // for later.
  return new self._in(count);
};

track.prototype.log = function() {
  console.log(arguments);
  return this;
};<|endoftext|>


<commit_before>create_table = function(tableId="trait_table", tableData = [], columnDefs = [], customSettings = {}) {

    loadDataTable(tableId=tableId, tableData=tableData, customSettings, firstRun=true)

    var widthChange = 0; // For storing the change in width so overall table width can be adjusted by that amount
    function loadDataTable(tableId, tableData, customSettings, firstRun=false){
        if (!firstRun){
            columnDefs = setUserColumnsDefWidths(tableId, columnDefs);
        }

        tableSettings = {
            "drawCallback": function( settings ) {
                $('#' + tableId + ' tr').off().on("click", function(event) {
                  if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
                    var obj =$(this).find('input');
                    obj.prop('checked', !obj.is(':checked'));
                  }
                  if ($(this).hasClass("selected") && event.target.tagName.toLowerCase() !== 'a'){
                    $(this).removeClass("selected")
                  } else if (event.target.tagName.toLowerCase() !== 'a') {
                    $(this).addClass("selected")
                  }
                  change_buttons()
                });
            },
            "columns": columnDefs,
            "sDom": "iti",
            "destroy": true,
            "autoWidth": false,
            "bSortClasses": false,
            "scrollY": "100vh",
            "scrollCollapse": true,
            "scroller":  true,
            "iDisplayLength": -1,
            "initComplete": function (settings) {
                // Add JQueryUI resizable functionality to each th in the ScrollHead table
                $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({
                    handles: "e",
                    alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother
                    resize: function( event, ui ) {
                        widthChange = ui.size.width - ui.originalSize.width;
                    },
                    stop: function () {
                        saveColumnSettings(tableId, theTable);
                        loadDataTable(tableId, tableData, customSettings, firstRun=false);
                    }
                });
            }
        }

        if (tableData.length > 0){
            tableSettings["data"] = tableData
        }

        // Replace default settings with custom settings or add custom settings if not already set in default settings
        $.each(customSettings, function(key, value) {
            tableSettings[key] = value
        });

        if (!firstRun){
            $('#' + tableId + '_container').css("width", String($('#' + tableId).width() + widthChange + 17) + "px"); // Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly

            let checkedRows = getCheckedRows(tableId);
            theTable = $('#' + tableId).DataTable(tableSettings);
            if (checkedRows.length > 0){
                recheckRows(theTable, checkedRows);
            }
        } else {
            theTable = $('#' + tableId).DataTable(tableSettings);
            theTable.draw();
        }

        if (firstRun){
            $('#' + tableId + '_container').css("width", String($('#' + tableId).width() + 17) + "px");
        }
    }

    theTable.on( 'order.dt search.dt draw.dt', function () {
        theTable.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
        cell.innerHTML = i+1;
        } );
    } ).draw();

    window.addEventListener('resize', function(){
        theTable.columns.adjust();
    });

    $('#' + tableId + '_searchbox').on( 'keyup', function () {
        theTable.search($(this).val()).draw();
    } );

    $('.toggle-vis').on('click', function (e) {
        e.preventDefault();

        function toggleColumn(column) {
            // Toggle column visibility
            column.visible( ! column.visible() );
            if (column.visible()){
                $(this).removeClass("active");
            } else {
                $(this).addClass("active");
            }
        }

        // Get the column API object
        var targetCols = $(this).attr('data-column').split(",")
        for (let i = 0; i < targetCols.length; i++){
            var column = theTable.column( target_cols[i] );
            toggleColumn(column);
        }
    } );
}
<commit_msg>Add table redraw function to create_datatable.js since it applies to multiple tables<commit_after>create_table = function(tableId="trait_table", tableData = [], columnDefs = [], customSettings = {}) {

    loadDataTable(tableId=tableId, tableData=tableData, customSettings, firstRun=true)

    var widthChange = 0; // For storing the change in width so overall table width can be adjusted by that amount
    function loadDataTable(tableId, tableData, customSettings, firstRun=false){
        if (!firstRun){
            columnDefs = setUserColumnsDefWidths(tableId, columnDefs);
        }

        tableSettings = {
            "drawCallback": function( settings ) {
                $('#' + tableId + ' tr').off().on("click", function(event) {
                  if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
                    var obj =$(this).find('input');
                    obj.prop('checked', !obj.is(':checked'));
                  }
                  if ($(this).hasClass("selected") && event.target.tagName.toLowerCase() !== 'a'){
                    $(this).removeClass("selected")
                  } else if (event.target.tagName.toLowerCase() !== 'a') {
                    $(this).addClass("selected")
                  }
                  change_buttons()
                });
            },
            "columns": columnDefs,
            "sDom": "iti",
            "destroy": true,
            "autoWidth": false,
            "bSortClasses": false,
            "scrollY": "100vh",
            "scrollCollapse": true,
            "scroller":  true,
            "iDisplayLength": -1,
            "initComplete": function (settings) {
                // Add JQueryUI resizable functionality to each th in the ScrollHead table
                $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({
                    handles: "e",
                    alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother
                    resize: function( event, ui ) {
                        widthChange = ui.size.width - ui.originalSize.width;
                    },
                    stop: function () {
                        saveColumnSettings(tableId, theTable);
                        loadDataTable(tableId, tableData, customSettings, firstRun=false);
                    }
                });
            }
        }

        if (tableData.length > 0){
            tableSettings["data"] = tableData
        }

        // Replace default settings with custom settings or add custom settings if not already set in default settings
        $.each(customSettings, function(key, value) {
            tableSettings[key] = value
        });

        if (!firstRun){
            $('#' + tableId + '_container').css("width", String($('#' + tableId).width() + widthChange + 17) + "px"); // Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly

            let checkedRows = getCheckedRows(tableId);
            theTable = $('#' + tableId).DataTable(tableSettings);
            if (checkedRows.length > 0){
                recheckRows(theTable, checkedRows);
            }
        } else {
            theTable = $('#' + tableId).DataTable(tableSettings);
            theTable.draw();
        }

        if (firstRun){
            $('#' + tableId + '_container').css("width", String($('#' + tableId).width() + 17) + "px");
        }
    }

    theTable.on( 'order.dt search.dt draw.dt', function () {
        theTable.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
        cell.innerHTML = i+1;
        } );
    } ).draw();

    window.addEventListener('resize', function(){
        theTable.columns.adjust();
    });

    $('#' + tableId + '_searchbox').on( 'keyup', function () {
        theTable.search($(this).val()).draw();
    } );

    $('.toggle-vis').on('click', function (e) {
        e.preventDefault();

        function toggleColumn(column) {
            // Toggle column visibility
            column.visible( ! column.visible() );
            if (column.visible()){
                $(this).removeClass("active");
            } else {
                $(this).addClass("active");
            }
        }

        // Get the column API object
        var targetCols = $(this).attr('data-column').split(",")
        for (let i = 0; i < targetCols.length; i++){
            var column = theTable.column( target_cols[i] );
            toggleColumn(column);
        }
    } );

    $('#redraw').on('click', function (e) {
        e.preventDefault();
        trait_table.columns().visible( true );
        $('.toggle-vis.active').removeClass('active');
    });
}
<|endoftext|>


<commit_before>module.exports = function checkAndSetPost (req, res, next) {
  var postId = req.param('postId')

  var fail = function (log, responseType) {
    sails.log.debug(`policy: checkAndSetPost: ${log}`)
    res[responseType || 'forbidden']()
  }

  return Post.find(req.param('postId'), {withRelated: 'communities'})
  .then(post => {
    if (!post) return fail(`post ${postId} not found`, 'notFound')

    res.locals.post = post

    var ok = Admin.isSignedIn(req) ||
      (res.locals.publicAccessAllowed && post.isPublic())

    return (ok ? Promise.resolve(true)
      : Post.isVisibleToUser(post.id, req.session.userId))
    .then(allowed => allowed ? next() : fail('not allowed'))
  })
  .catch(err => fail(err.message, 'serverError'))
}
<commit_msg>avoid bluebird's "promise not returned" warning<commit_after>module.exports = function checkAndSetPost (req, res, next) {
  var postId = req.param('postId')

  var fail = function (log, responseType) {
    sails.log.debug(`policy: checkAndSetPost: ${log}`)
    res[responseType || 'forbidden']()
  }

  return Post.find(req.param('postId'), {withRelated: 'communities'})
  .then(post => {
    if (!post) return fail(`post ${postId} not found`, 'notFound')

    res.locals.post = post

    var ok = Admin.isSignedIn(req) ||
      (res.locals.publicAccessAllowed && post.isPublic())

    return (ok ? Promise.resolve(true)
      : Post.isVisibleToUser(post.id, req.session.userId))
    .then(allowed => {
      if (allowed) {
        next()
      } else {
        fail('not allowed')
      }
      return null
    })
  })
  .catch(err => fail(err.message, 'serverError'))
}
<|endoftext|>