<commit_before>/**
 *
 */

import Ember from 'ember';

export default Ember.Service.extend(Ember.Evented, {

  googleMap: null,

  component: null,

  markerMap: null,

  markerClusterer: null,

  isLoaded: false,

  config: null,

  setup: Ember.on('init', function () {
    var container = this.get('container');
    var MAPKIT_ENV = container.lookup('application:main').MAPKIT;
    var MarkerClusterer = container.lookup('google:marker-clusterer');

    this.setProperties({
      config: MAPKIT_ENV,
      markerClusterer: new MarkerClusterer(null, [], MAPKIT_ENV.MARKER_CLUSTERER),
      markerMap: Ember.Map.create()
    });
  }),

  /**
   * Create map, and add handlers etc.
   * @param component
   */
  register(component) {
    this.set('component', component);

    var props = this.getProperties('config', 'googleApi', 'markerClusterer');

    var MAPKIT_ENV = props.config;
    var googleApi = props.googleApi;
    var markerClusterer = props.markerClusterer;
    var self = this;
    var googleMap;
    var options;

    options = {
      zoom: MAPKIT_ENV.MAP_DEFAULT_ZOOM,
      center: {
        lat: MAPKIT_ENV.MAP_DEFAULT_LAT,
        lng: MAPKIT_ENV.MAP_DEFAULT_LNG
      }
    };

    googleMap = new googleApi.maps.Map(component.$()[0], options);

    this.setProperties({
      googleMap: googleMap,
      mapTypeId: MAPKIT_ENV.MAP_TYPE
    });

    MAPKIT_ENV.MAP_EVENTS.forEach((eventName) => {
      this.addListener(eventName);
    });

    //fixes bug where fromLatLnToContainerPixel returns undefined.
    var overlay = new googleApi.maps.OverlayView();
    overlay.draw = function () {
    };
    overlay.setMap(googleMap);

    markerClusterer.setMap(googleMap);

    //this part runs when the map object is created and rendered
    googleApi.maps.event.addListenerOnce(googleMap, 'tilesloaded', () => {
      this.set('isLoaded', true);

      this.trigger('readyAction');
    });
  },

  /**
   * Removes handlers etc.
   */
  unregister() {
    var props = this.getProperties('googleApi', 'googleMap', 'markerMap', 'markerClusterer');
    var markerMap = props.markerMap;
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;
    var markerClusterer = props.markerClusterer;

    // clean up all listeners
    markerMap.forEach((googleMarker) => {
      googleApi.maps.event.clearInstanceListeners(googleMarker);
    });

    googleApi.maps.event.clearInstanceListeners(googleMap);

    markerClusterer.clearMarkers();
    markerMap.clear();
  },

  /**
   * Add a listener to the map.
   */
  addListener(eventName) {
    var props = this.getProperties('googleApi', 'googleMap');
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;

    googleApi.maps.event.addListener(googleMap, eventName, (event) => {
      var component = this.get('component');
      var position;
      var data = {};
      if (event) {
        position = component.$().position();
        data = {
          pixel: {
            x: position.left + event.pixel.x,
            y: position.top + event.pixel.y
          },
          position: {
            lat: event.latLng.lat(),
            lng: event.latLng.lng()
          }
        };
      }

      this.trigger('action', eventName, data);
    });
  },

  /**
   * Remove a listener from the map
   * @param eventName
   */
  removeListener(eventName) {
    var props = this.getProperties('googleApi', 'googleMap');

    props.googleApi.maps.event.clearInstanceListeners(props.googleMap, eventName);
  },

  /**
   * The maps center property
   */
  center: function (key, position) {
    var center;
    var googleMap = this.get('googleMap');
    if (arguments.length > 1) {
      googleMap.setCenter(position);
    }

    center = googleMap.getCenter();
    return {
      lat: center.lat(),
      lng: center.lng()
    };
  }.property('googleMap').volatile(),

  /**
   * Pans the map to a specified position
   * @param position
   */
  panTo(position) {
    this.get('googleMap').panTo(position);
  },

  /**
   *
   */
  zoom: function (key, zoom) {
    var googleMap = this.get('googleMap');
    if (arguments.length > 1) {
      googleMap.setZoom(zoom);
    }

    return googleMap.getZoom();
  }.property('googleMap').volatile(),

  /**
   *
   */
  tilt: function () {
    return this.get('googleMap').getTilt();
  }.property('googleMap').volatile(),

  /**
   * The current map bounds
   */
  bounds: function () {
    var bounds = this.get('googleMap').getBounds();
    var sw = bounds.getSouthWest();
    var ne = bounds.getNorthEast();

    return {
      sw: {
        lat: sw.lat(),
        lng: sw.lng()
      },
      ne: {
        lat: ne.lat(),
        lng: ne.lng()
      }
    };
  }.property('googleMap').volatile(),

  /**
   * Type of map used for display (ex roadmap, hybrid)
   */
  mapTypeId: function (key, value) {
    var type;
    var props = this.getProperties('googleApi', 'googleMap');
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;

    var SATELLITE = googleApi.maps.MapTypeId.SATELLITE;
    var ROADMAP = googleApi.maps.MapTypeId.ROADMAP;
    var TERRAIN = googleApi.maps.MapTypeId.TERRAIN;
    var HYBRID = googleApi.maps.MapTypeId.HYBRID;

    if (arguments.length > 1) {
      switch (value) {
        case "roadmap":
          type = ROADMAP;
          break;
        case "satellite":
          type = SATELLITE;
          break;
        case "terrain":
          type = TERRAIN;
          break;
        case "hybrid":
          type = HYBRID;
          break;
        default:
          type = ROADMAP;
      }

      googleMap.setMapTypeId(type);
    }

    return googleMap.getMapTypeId();
  }.property('googleMap').volatile(),

  /**
   * Set map options
   */
  options: function (key, value) {
    if (arguments.length > 1) {
      this.get('googleMap').setOptions(value);
    }
  }.property('googleMap'),

  /* Marker Specific */

  /**
   *
   * @param id
   */
  hasMarker(id) {
    var markerMap = this.get('markerMap');

    return markerMap.has(id);
  },

  /**
   *
   * @param markers
   */
  addMarkers(markers) {
    markers.forEach((marker) => {
      this.addMarker(marker);
    });
  },

  /**
   * Add a marker to the map
   * @param marker
   */
  addMarker(marker) {
    // force POJO for standardized processing, and because passing an Ember Object as params to a new google marker does not work.
    marker = JSON.parse(JSON.stringify(marker));

    var self = this;
    var props = this.getProperties('config', 'googleApi', 'markerMap', 'markerClusterer');

    var MAPKIT_ENV = props.config;
    var googleApi = props.googleApi;
    var markerMap = props.markerMap;
    var markerClusterer = props.markerClusterer;
    var googleMarker = new googleApi.maps.Marker(marker);

    markerMap.set(marker.id, googleMarker);

    markerClusterer.addMarker(googleMarker);

    // apply default marker events
    MAPKIT_ENV.MARKER_EVENTS.forEach(function (eventName) {
      self.addMarkerListener(marker.id, eventName);
    }, googleMarker);
  },

  /**
   * Add an event listener for a given marker event
   * @param id
   * @param eventName
   */
  addMarkerListener(id, eventName) {
    var data = {};
    var props = this.getProperties('googleApi', 'markerMap', 'component');

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    var googleMarker = props.markerMap.get(id);

    props.googleApi.maps.event.addListener(googleMarker, eventName, () => {
      data = {
        id: id,
        position: {
          lat: googleMarker.getPosition().lat(),
          lng: googleMarker.getPosition().lng()
        },
        pixel: this._getMarkerPixel(googleMarker)
      };

      this.trigger('markerAction', eventName, Ember.Object.create(data));
    });
  },

  /**
   * Remove a listener from a given marker
   */
  removeMarkerListener(id, eventName) {
    var props = this.getProperties('googleApi', 'markerMap');

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    props.googleApi.maps.event.clearInstanceListeners(props.markerMap.get(id), eventName);
  },

  /**
   * Remove a marker from the map
   * @param marker
   */
  removeMarker(id) {
    var props = this.getProperties('googleApi', 'markerMap', 'markerClusterer');
    var googleMarker;

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    googleMarker = props.markerMap.get(id);

    props.googleApi.maps.event.clearInstanceListeners(googleMarker);

    markerClusterer.removeMarker(googleMarker);

    props.markerMap.delete(id);
  },

  /**
   *
   */
  setMarkerIcon(id, icon) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setIcon(icon);
  },

  /**
   *
   */
  setMarkerPosition(id, position) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setPosition(position);
  },

  getMarkerPosition(id) {
    var position;
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    position = markerMap.get(id).getPosition();

    return {
      lat: position.lat(),
      lng: position.lng()
    };
  },

  /**
   *
   * @param id
   */
  getMarkerPixel(id) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    return this._getMarkerPixel(markerMap.get(id));
  },

  /**
   * Retrieve a given markers pixel values. Useful for placement of context menus etc.
   * @private
   */
  _getMarkerPixel(googleMarker) {
    var props = this.getProperties('googleApi', 'googleMap', 'component');

    // Calculate the position of the marker click-style event
    var overlay = new props.googleApi.maps.OverlayView();
    overlay.draw = function () {
    };
    overlay.setMap(props.googleMap);

    var proj = overlay.getProjection();
    var pos = googleMarker.getPosition();
    var p = proj.fromLatLngToContainerPixel(pos);

    var position = props.component.$().position();

    return {
      x: parseInt(position.left + p.x, 10),
      y: parseInt(position.top + p.y, 10)
    };
  },

  /**
   *
   * @param id
   * @param isDraggable
   */
  setMarkerDraggable(id, draggable) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setDraggable(draggable);
  },

  /**
   *
   * @param id
   * @param visible
   */
  setMarkerVisible(id, visible) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setVisible(visible);
  },

  /**
   *
   */
  setMarkerTitle(id, title) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setTitle(title);
  }
});
<commit_msg>converting to es6 style using babel for transpilation<commit_after>/**
 *
 */

import Ember from 'ember';

export default Ember.Service.extend(Ember.Evented, {

  googleMap: null,

  component: null,

  markerMap: null,

  markerClusterer: null,

  isLoaded: false,

  config: null,

  setup: Ember.on('init', function () {
    var container = this.get('container');
    var MAPKIT_ENV = container.lookup('application:main').MAPKIT;
    var MarkerClusterer = container.lookup('google:marker-clusterer');

    this.setProperties({
      config: MAPKIT_ENV,
      markerClusterer: new MarkerClusterer(null, [], MAPKIT_ENV.MARKER_CLUSTERER),
      markerMap: Ember.Map.create()
    });
  }),

  /**
   * Create map, and add handlers etc.
   * @param component
   */
  register(component) {
    this.set('component', component);

    var props = this.getProperties('config', 'googleApi', 'markerClusterer');

    var MAPKIT_ENV = props.config;
    var googleApi = props.googleApi;
    var markerClusterer = props.markerClusterer;
    var self = this;
    var googleMap;
    var options;

    options = {
      zoom: MAPKIT_ENV.MAP_DEFAULT_ZOOM,
      center: {
        lat: MAPKIT_ENV.MAP_DEFAULT_LAT,
        lng: MAPKIT_ENV.MAP_DEFAULT_LNG
      }
    };

    googleMap = new googleApi.maps.Map(component.$()[0], options);

    this.setProperties({
      googleMap: googleMap,
      mapTypeId: MAPKIT_ENV.MAP_TYPE
    });

    MAPKIT_ENV.MAP_EVENTS.forEach((eventName) => {
      this.addListener(eventName);
    });

    //fixes bug where fromLatLnToContainerPixel returns undefined.
    var overlay = new googleApi.maps.OverlayView();
    overlay.draw = function () {
    };
    overlay.setMap(googleMap);

    markerClusterer.setMap(googleMap);

    //this part runs when the map object is created and rendered
    googleApi.maps.event.addListenerOnce(googleMap, 'tilesloaded', () => {
      this.set('isLoaded', true);

      this.trigger('readyAction');
    });
  },

  /**
   * Removes handlers etc.
   */
  unregister() {
    var props = this.getProperties('googleApi', 'googleMap', 'markerMap', 'markerClusterer');
    var markerMap = props.markerMap;
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;
    var markerClusterer = props.markerClusterer;

    // clean up all listeners
    markerMap.forEach((googleMarker) => {
      googleApi.maps.event.clearInstanceListeners(googleMarker);
    });

    googleApi.maps.event.clearInstanceListeners(googleMap);

    markerClusterer.clearMarkers();
    markerMap.clear();
  },

  /**
   * Add a listener to the map.
   */
  addListener(eventName) {
    var props = this.getProperties('googleApi', 'googleMap');
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;

    googleApi.maps.event.addListener(googleMap, eventName, (event) => {
      var component = this.get('component');
      var position;
      var data = {};
      if (event) {
        position = component.$().position();
        data = {
          pixel: {
            x: position.left + event.pixel.x,
            y: position.top + event.pixel.y
          },
          position: {
            lat: event.latLng.lat(),
            lng: event.latLng.lng()
          }
        };
      }

      this.trigger('action', eventName, data);
    });
  },

  /**
   * Remove a listener from the map
   * @param eventName
   */
  removeListener(eventName) {
    var props = this.getProperties('googleApi', 'googleMap');

    props.googleApi.maps.event.clearInstanceListeners(props.googleMap, eventName);
  },

  /**
   * The maps center property
   */
  center: function (key, position) {
    var center;
    var googleMap = this.get('googleMap');
    if (arguments.length > 1) {
      googleMap.setCenter(position);
    }

    center = googleMap.getCenter();
    return {
      lat: center.lat(),
      lng: center.lng()
    };
  }.property('googleMap').volatile(),

  /**
   * Pans the map to a specified position
   * @param position
   */
  panTo(position) {
    this.get('googleMap').panTo(position);
  },

  /**
   *
   */
  zoom: function (key, zoom) {
    var googleMap = this.get('googleMap');
    if (arguments.length > 1) {
      googleMap.setZoom(zoom);
    }

    return googleMap.getZoom();
  }.property('googleMap').volatile(),

  /**
   *
   */
  tilt: function () {
    return this.get('googleMap').getTilt();
  }.property('googleMap').volatile(),

  /**
   * The current map bounds
   */
  bounds: function () {
    var bounds = this.get('googleMap').getBounds();
    var sw = bounds.getSouthWest();
    var ne = bounds.getNorthEast();

    return {
      sw: {
        lat: sw.lat(),
        lng: sw.lng()
      },
      ne: {
        lat: ne.lat(),
        lng: ne.lng()
      }
    };
  }.property('googleMap').volatile(),

  /**
   * Type of map used for display (ex roadmap, hybrid)
   */
  mapTypeId: function (key, value) {
    var type;
    var props = this.getProperties('googleApi', 'googleMap');
    var googleApi = props.googleApi;
    var googleMap = props.googleMap;

    var SATELLITE = googleApi.maps.MapTypeId.SATELLITE;
    var ROADMAP = googleApi.maps.MapTypeId.ROADMAP;
    var TERRAIN = googleApi.maps.MapTypeId.TERRAIN;
    var HYBRID = googleApi.maps.MapTypeId.HYBRID;

    if (arguments.length > 1) {
      switch (value) {
        case "roadmap":
          type = ROADMAP;
          break;
        case "satellite":
          type = SATELLITE;
          break;
        case "terrain":
          type = TERRAIN;
          break;
        case "hybrid":
          type = HYBRID;
          break;
        default:
          type = ROADMAP;
      }

      googleMap.setMapTypeId(type);
    }

    return googleMap.getMapTypeId();
  }.property('googleMap').volatile(),

  /**
   * Set map options
   */
  options: Ember.computed ('googleMap' ,function (key, value) {
    if (arguments.length > 1) {
      this.get('googleMap').setOptions(value);
    }
  }),

  /* Marker Specific */

  /**
   *
   * @param id
   */
  hasMarker(id) {
    var markerMap = this.get('markerMap');

    return markerMap.has(id);
  },

  /**
   *
   * @param markers
   */
  addMarkers(markers) {
    markers.forEach((marker) => {
      this.addMarker(marker);
    });
  },

  /**
   * Add a marker to the map
   * @param marker
   */
  addMarker(marker) {
    // force POJO for standardized processing, and because passing an Ember Object as params to a new google marker does not work.
    marker = JSON.parse(JSON.stringify(marker));

    var self = this;
    var props = this.getProperties('config', 'googleApi', 'markerMap', 'markerClusterer');

    var MAPKIT_ENV = props.config;
    var googleApi = props.googleApi;
    var markerMap = props.markerMap;
    var markerClusterer = props.markerClusterer;
    var googleMarker = new googleApi.maps.Marker(marker);

    markerMap.set(marker.id, googleMarker);

    markerClusterer.addMarker(googleMarker);

    // apply default marker events
    MAPKIT_ENV.MARKER_EVENTS.forEach(function (eventName) {
      self.addMarkerListener(marker.id, eventName);
    }, googleMarker);
  },

  /**
   * Add an event listener for a given marker event
   * @param id
   * @param eventName
   */
  addMarkerListener(id, eventName) {
    var data = {};
    var props = this.getProperties('googleApi', 'markerMap', 'component');

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    var googleMarker = props.markerMap.get(id);

    props.googleApi.maps.event.addListener(googleMarker, eventName, () => {
      data = {
        id: id,
        position: {
          lat: googleMarker.getPosition().lat(),
          lng: googleMarker.getPosition().lng()
        },
        pixel: this._getMarkerPixel(googleMarker)
      };

      this.trigger('markerAction', eventName, Ember.Object.create(data));
    });
  },

  /**
   * Remove a listener from a given marker
   */
  removeMarkerListener(id, eventName) {
    var props = this.getProperties('googleApi', 'markerMap');

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    props.googleApi.maps.event.clearInstanceListeners(props.markerMap.get(id), eventName);
  },

  /**
   * Remove a marker from the map
   * @param marker
   */
  removeMarker(id) {
    var props = this.getProperties('googleApi', 'markerMap', 'markerClusterer');
    var googleMarker;

    Ember.assert('This marker has no mapping', props.markerMap.has(id));

    googleMarker = props.markerMap.get(id);

    props.googleApi.maps.event.clearInstanceListeners(googleMarker);

    markerClusterer.removeMarker(googleMarker);

    props.markerMap.delete(id);
  },

  /**
   *
   */
  setMarkerIcon(id, icon) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setIcon(icon);
  },

  /**
   *
   */
  setMarkerPosition(id, position) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setPosition(position);
  },

  getMarkerPosition(id) {
    var position;
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    position = markerMap.get(id).getPosition();

    return {
      lat: position.lat(),
      lng: position.lng()
    };
  },

  /**
   *
   * @param id
   */
  getMarkerPixel(id) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    return this._getMarkerPixel(markerMap.get(id));
  },

  /**
   * Retrieve a given markers pixel values. Useful for placement of context menus etc.
   * @private
   */
  _getMarkerPixel(googleMarker) {
    var props = this.getProperties('googleApi', 'googleMap', 'component');

    // Calculate the position of the marker click-style event
    var overlay = new props.googleApi.maps.OverlayView();
    overlay.draw = function () {
    };
    overlay.setMap(props.googleMap);

    var proj = overlay.getProjection();
    var pos = googleMarker.getPosition();
    var p = proj.fromLatLngToContainerPixel(pos);

    var position = props.component.$().position();

    return {
      x: parseInt(position.left + p.x, 10),
      y: parseInt(position.top + p.y, 10)
    };
  },

  /**
   *
   * @param id
   * @param isDraggable
   */
  setMarkerDraggable(id, draggable) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setDraggable(draggable);
  },

  /**
   *
   * @param id
   * @param visible
   */
  setMarkerVisible(id, visible) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setVisible(visible);
  },

  /**
   *
   */
  setMarkerTitle(id, title) {
    var markerMap = this.get('markerMap');

    Ember.assert('This marker has no mapping', markerMap.has(id));

    markerMap.get(id).setTitle(title);
  }
});
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     152
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v153 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     153
// ==/UserScript==
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Promise = require('bluebird');

const Facebook = require('./facebook');
const sessions = require('./sessions');
const keepr = require('./keepr');
const config = require('../../config');

module.exports = {
  actions: {
    send: (request, response) => {
      const sessionId = request.sessionId;
      const context = request.context;
      const entities = request.entities;
      const recipientId = sessions.getSessions()[sessionId].fbid;
      if (recipientId) {
          return Facebook.sendTextMessage(recipientId, message);
      } else {
        return Promise.reject('Oops! Couldn\'t find user for session: ' + sessionId);
      }
    },
    ['fetch_latest_news_by_keyword'](request) {
      const entities = request.entities;
      const sessionId = request.sessionId;
      const context = require.context;
      const recipientId = sessions.getSessions()[sessionId].fbid;
      if (recipientId) {
        return keepr.latestNewsByKeyword(entities.keyword).then((response) => {
          const numbers = response.numbers;
          const firstBreakingNews = numbers[1].urls[0].expanded_url;

          return Facebook.sendTextMessage(recipientId, firstBreakingNews);
        });
      }
      return Promise.reject('Oops! Couldn\'t find user for session: ' + sessionId);
    },
  }
};
<commit_msg>Print error<commit_after>'use strict';

const _ = require('lodash');
const Promise = require('bluebird');

const Facebook = require('./facebook');
const sessions = require('./sessions');
const keepr = require('./keepr');
const config = require('../../config');

module.exports = {
  actions: {
    send: (request, response) => {
      const sessionId = request.sessionId;
      const context = request.context;
      const entities = request.entities;
      const recipientId = sessions.getSessions()[sessionId].fbid;
      if (recipientId) {
          return Facebook.sendTextMessage(recipientId, message);
      } else {
        return Promise.reject('Oops! Couldn\'t find user for session: ' + sessionId);
      }
    },
    ['fetch_latest_news_by_keyword'](request) {
      const entities = request.entities;
      const sessionId = request.sessionId;
      const context = require.context;
      const recipientId = sessions.getSessions()[sessionId].fbid;
      if (recipientId) {
        return keepr.latestNewsByKeyword(entities.keyword).then((response) => {
          const numbers = response.numbers;
          const firstBreakingNews = numbers[1].urls[0].expanded_url;

          return Facebook.sendTextMessage(recipientId, firstBreakingNews).catch((error) => {
            console.log(error);
          });
        });
      }
      return Promise.reject('Oops! Couldn\'t find user for session: ' + sessionId);
    },
  }
};
<|endoftext|>


<commit_before>import { LOCATION_CHANGE, push } from "react-router-redux";
import { takeLatest, throttle, put, takeEvery } from "redux-saga/effects";

import * as referenceAPI from "./api";
import { apiCall, apiFind, setPending } from "../sagaUtils";
import {
    CREATE_REFERENCE,
    GET_REFERENCE,
    LIST_REFERENCES,
    REMOVE_REFERENCE,
    EDIT_REFERENCE,
    IMPORT_REFERENCE,
    CLONE_REFERENCE,
    REMOTE_REFERENCE,
    ADD_REFERENCE_USER,
    EDIT_REFERENCE_USER,
    REMOVE_REFERENCE_USER,
    ADD_REFERENCE_GROUP,
    EDIT_REFERENCE_GROUP,
    REMOVE_REFERENCE_GROUP
} from "../actionTypes";

export function* listReferences (action) {
    yield apiFind("/refs", referenceAPI.list, action, LIST_REFERENCES);
}

export function* getReference (action) {
    yield apiCall(referenceAPI.get, action, GET_REFERENCE);
}

export function* createReference (action) {
    yield apiCall(referenceAPI.create, action, CREATE_REFERENCE);
    yield put(push({state: {createReference: false}}));
}

export function* editReference (action) {
    yield apiCall(referenceAPI.edit, action, EDIT_REFERENCE);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.referenceId
    });
}

export function* removeReference (action) {
    yield setPending(apiCall(referenceAPI.remove, action, REMOVE_REFERENCE));
    yield put(push("/refs"));
}

export function* importReference (action) {
    yield setPending(apiCall(referenceAPI.importReference, action, IMPORT_REFERENCE));
    yield put(push({state: {importReference: false}}));
}

export function* cloneReference (action) {
    yield setPending(apiCall(referenceAPI.cloneReference, action, CLONE_REFERENCE));
    yield put(push({state: {cloneReference: false}}));
}

export function* remoteReference () {
    yield setPending(apiCall(
        referenceAPI.remoteReference,
        { remote_from: "virtool/virtool-database" },
        REMOTE_REFERENCE
    ));
    yield put(push({pathname: "/refs"}));
}

export function* addRefUser (action) {
    yield apiCall(referenceAPI.addUser, action, ADD_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* editRefUser (action) {
    yield apiCall(referenceAPI.editUser, action, EDIT_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* removeRefUser (action) {
    yield apiCall(referenceAPI.removeUser, action, REMOVE_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* addRefGroup (action) {
    yield apiCall(referenceAPI.addGroup, action, ADD_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* editRefGroup (action) {
    yield apiCall(referenceAPI.editGroup, action, EDIT_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* removeRefGroup (action) {
    yield apiCall(referenceAPI.removeGroup, action, REMOVE_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* watchReferences () {
    yield throttle(300, CREATE_REFERENCE.REQUESTED, createReference);
    yield takeEvery(EDIT_REFERENCE.REQUESTED, editReference);
    yield takeLatest(GET_REFERENCE.REQUESTED, getReference);
    yield throttle(300, LOCATION_CHANGE, listReferences);
    yield takeEvery(REMOVE_REFERENCE.REQUESTED, removeReference);
    yield takeLatest(IMPORT_REFERENCE.REQUESTED, importReference);
    yield takeLatest(CLONE_REFERENCE.REQUESTED, cloneReference);
    yield takeLatest(REMOTE_REFERENCE.REQUESTED, remoteReference);
    yield takeEvery(ADD_REFERENCE_USER.REQUESTED, addRefUser);
    yield takeEvery(EDIT_REFERENCE_USER.REQUESTED, editRefUser);
    yield takeEvery(REMOVE_REFERENCE_USER.REQUESTED, removeRefUser);
    yield takeEvery(ADD_REFERENCE_GROUP.REQUESTED, addRefGroup);
    yield takeEvery(EDIT_REFERENCE_GROUP.REQUESTED, editRefGroup);
    yield takeEvery(REMOVE_REFERENCE_GROUP.REQUESTED, removeRefGroup);
}
<commit_msg>Update remote ref saga<commit_after>import { LOCATION_CHANGE, push } from "react-router-redux";
import { takeLatest, throttle, put, takeEvery } from "redux-saga/effects";

import * as referenceAPI from "./api";
import { apiCall, apiFind, setPending } from "../sagaUtils";
import {
    CREATE_REFERENCE,
    GET_REFERENCE,
    LIST_REFERENCES,
    REMOVE_REFERENCE,
    EDIT_REFERENCE,
    IMPORT_REFERENCE,
    CLONE_REFERENCE,
    REMOTE_REFERENCE,
    ADD_REFERENCE_USER,
    EDIT_REFERENCE_USER,
    REMOVE_REFERENCE_USER,
    ADD_REFERENCE_GROUP,
    EDIT_REFERENCE_GROUP,
    REMOVE_REFERENCE_GROUP
} from "../actionTypes";

export function* listReferences (action) {
    yield apiFind("/refs", referenceAPI.list, action, LIST_REFERENCES);
}

export function* getReference (action) {
    yield apiCall(referenceAPI.get, action, GET_REFERENCE);
}

export function* createReference (action) {
    yield apiCall(referenceAPI.create, action, CREATE_REFERENCE);
    yield put(push({state: {createReference: false}}));
}

export function* editReference (action) {
    yield apiCall(referenceAPI.edit, action, EDIT_REFERENCE);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.referenceId
    });
}

export function* removeReference (action) {
    yield setPending(apiCall(referenceAPI.remove, action, REMOVE_REFERENCE));
    yield put(push("/refs"));
}

export function* importReference (action) {
    yield setPending(apiCall(referenceAPI.importReference, action, IMPORT_REFERENCE));
    yield put(push({state: {importReference: false}}));
}

export function* cloneReference (action) {
    yield setPending(apiCall(referenceAPI.cloneReference, action, CLONE_REFERENCE));
    yield put(push({state: {cloneReference: false}}));
}

export function* remoteReference () {
    yield setPending(apiCall(
        referenceAPI.remoteReference,
        { remote_from: "virtool/ref-plant-viruses" },
        REMOTE_REFERENCE
    ));
    yield put(push({pathname: "/refs"}));
}

export function* addRefUser (action) {
    yield apiCall(referenceAPI.addUser, action, ADD_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* editRefUser (action) {
    yield apiCall(referenceAPI.editUser, action, EDIT_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* removeRefUser (action) {
    yield apiCall(referenceAPI.removeUser, action, REMOVE_REFERENCE_USER);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* addRefGroup (action) {
    yield apiCall(referenceAPI.addGroup, action, ADD_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* editRefGroup (action) {
    yield apiCall(referenceAPI.editGroup, action, EDIT_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* removeRefGroup (action) {
    yield apiCall(referenceAPI.removeGroup, action, REMOVE_REFERENCE_GROUP);
    yield getReference({
        type: GET_REFERENCE.REQUESTED,
        referenceId: action.refId
    });
}

export function* watchReferences () {
    yield throttle(300, CREATE_REFERENCE.REQUESTED, createReference);
    yield takeEvery(EDIT_REFERENCE.REQUESTED, editReference);
    yield takeLatest(GET_REFERENCE.REQUESTED, getReference);
    yield throttle(300, LOCATION_CHANGE, listReferences);
    yield takeEvery(REMOVE_REFERENCE.REQUESTED, removeReference);
    yield takeLatest(IMPORT_REFERENCE.REQUESTED, importReference);
    yield takeLatest(CLONE_REFERENCE.REQUESTED, cloneReference);
    yield takeLatest(REMOTE_REFERENCE.REQUESTED, remoteReference);
    yield takeEvery(ADD_REFERENCE_USER.REQUESTED, addRefUser);
    yield takeEvery(EDIT_REFERENCE_USER.REQUESTED, editRefUser);
    yield takeEvery(REMOVE_REFERENCE_USER.REQUESTED, removeRefUser);
    yield takeEvery(ADD_REFERENCE_GROUP.REQUESTED, addRefGroup);
    yield takeEvery(EDIT_REFERENCE_GROUP.REQUESTED, editRefGroup);
    yield takeEvery(REMOVE_REFERENCE_GROUP.REQUESTED, removeRefGroup);
}
<|endoftext|>


<commit_before>'use strict';

module.exports = function(appname, type) {
  var common = [
    {
      type: 'input',
      name: 'componentName',
      message: '组件名称',
      default: appname.split(' ').join('-')
    },
    {
      type: 'input',
      name: 'version',
      message: '版本号',
      default: '0.0.1'
    },
    {
      type: 'input',
      name: 'author',
      message: '作者',
      default: 'name@gamil.com'
    },
    {
      type: 'input',
      name: 'description',
      message: '详细描述',
      default: '组件说明'
    },
    {
      type: 'input',
      name: 'license',
      message: '证书类型',
      default: 'MIT'
    },
    {
      type: 'input',
      name: 'repositoryUrl',
      message: '仓库地址',
      default: ''
    }
  ];
  return {
    prompt: common,
    fn: function(ctx, done) {
    return function(data) {
      var dirs = ['demo', 'src'];
      dirs.forEach(function(val) {
        ctx.directory(val, val);
      });
      ctx.template('package.json', 'package.json', data);
      ctx.template('server.js', 'server.js');
      ctx.template('index.html', 'index.html');
      ctx.template('LICENSE', 'LICENSE');
      ctx.template('.babelrc', '.babelrc');
      ctx.template('.eslintrc', '.eslintrc');
      ctx.template('.gitignore', '.gitignore');
      ctx.template('webpack.config.js', 'webpack.config.js');
      done();
    };
  }
  };
};
<commit_msg>format<commit_after>'use strict';

module.exports = function(appname, type) {
  var common = [{
    type: 'input',
    name: 'componentName',
    message: '组件名称',
    default: appname.split(' ').join('-')
  }, {
    type: 'input',
    name: 'version',
    message: '版本号',
    default: '0.0.1'
  }, {
    type: 'input',
    name: 'author',
    message: '作者',
    default: 'name@gamil.com'
  }, {
    type: 'input',
    name: 'description',
    message: '详细描述',
    default: '组件说明'
  }, {
    type: 'input',
    name: 'license',
    message: '证书类型',
    default: 'MIT'
  }, {
    type: 'input',
    name: 'repositoryUrl',
    message: '仓库地址',
    default: ''
  }];
  return {
    prompt: common,
    fn: function(ctx, done) {
      return function(data) {
        ['demo', 'src'].forEach(function(val) {
          ctx.directory(val, val);
        });
        ctx.template('package.json', 'package.json', data);
        [
          'server.js',
          'index.html',
          'LICENSE',
          '.babelrc',
          '.eslintrc',
          '.gitignore',
          'webpack.config.js'
        ].forEach(function(name) {
          ctx.template(name, name);
        });
        done();
      };
    }
  };
};
<|endoftext|>


<commit_before>/**
* Copyright 2012-2019, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');

module.exports = function clean2dArray(zOld, transpose, trace, xa, ya) {
    var rowlen, collen, getCollen, old2new, i, j;

    function cleanZvalue(v) {
        if(!isNumeric(v)) return undefined;
        return +v;
    }

    if(transpose) {
        rowlen = 0;
        for(i = 0; i < zOld.length; i++) rowlen = Math.max(rowlen, zOld[i].length);
        if(rowlen === 0) return false;
        getCollen = function(zOld) { return zOld.length; };
        old2new = function(zOld, i, j) { return zOld[j][i]; };
    } else {
        rowlen = zOld.length;
        getCollen = function(zOld, i) { return zOld[i].length; };
        old2new = function(zOld, i, j) { return zOld[i][j]; };
    }

    var xMap = function(i) {return i;};
    var yMap = function(i) {return i;};
    if(ya.type === 'category') {
        yMap = function(i) {return ya._categoriesMap[trace.y[i]];};
    }
    if(xa.type === 'category') {
        xMap = function(i) {return xa._categoriesMap[trace.x[i]];};
    }

    var zNew = new Array(rowlen);

    for(i = 0; i < rowlen; i++) {
        collen = getCollen(zOld, i);
        zNew[i] = new Array(collen);
        for(j = 0; j < collen; j++) zNew[i][j] = cleanZvalue(old2new(zOld, yMap(i), xMap(j)));
    }

    return zNew;
};
<commit_msg>heatmap: handle undefined axes in clean_2d_array<commit_after>/**
* Copyright 2012-2019, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');

module.exports = function clean2dArray(zOld, transpose, trace, xa, ya) {
    var rowlen, collen, getCollen, old2new, i, j;

    function cleanZvalue(v) {
        if(!isNumeric(v)) return undefined;
        return +v;
    }

    if(transpose) {
        rowlen = 0;
        for(i = 0; i < zOld.length; i++) rowlen = Math.max(rowlen, zOld[i].length);
        if(rowlen === 0) return false;
        getCollen = function(zOld) { return zOld.length; };
        old2new = function(zOld, i, j) { return zOld[j][i]; };
    } else {
        rowlen = zOld.length;
        getCollen = function(zOld, i) { return zOld[i].length; };
        old2new = function(zOld, i, j) { return zOld[i][j]; };
    }

    var xMap = function(i) {return i;};
    var yMap = function(i) {return i;};
    if(ya && ya.type === 'category') {
        yMap = function(i) {return ya._categoriesMap[trace.y[i]];};
    }
    if(xa && xa.type === 'category') {
        xMap = function(i) {return xa._categoriesMap[trace.x[i]];};
    }

    var zNew = new Array(rowlen);

    for(i = 0; i < rowlen; i++) {
        collen = getCollen(zOld, i);
        zNew[i] = new Array(collen);
        for(j = 0; j < collen; j++) zNew[i][j] = cleanZvalue(old2new(zOld, yMap(i), xMap(j)));
    }

    return zNew;
};
<|endoftext|>


<commit_before>/*!
 * Storyboard
 *
 * End-to-end, hierarchical, real-time, colorful logs and stories
 *
 * @copyright Guillermo Grau Panea 2016
 * @license MIT
 */

// Chalk is disabled by default in the browser. Override
// this default (we'll handle ANSI code conversion ourselves
// when needed)
import chalk from 'chalk';
import mainStory from './gral/stories';
import filters from './gral/filters';
import {
  init as hubInit,
  configure as hubConfigure,
  getListeners, addListener, removeListener, removeAllListeners,
} from './gral/hub';

chalk.enabled = true;

hubInit({ mainStory });

const config = (options = {}) => {
  Object.keys(options).forEach(key => {
    const val = options[key];
    switch (key) {
      case 'filter':
        filters.config(val);
        break;
      case 'bufSize':
        hubConfigure({ bufSize: val });
        break;
      /* istanbul ignore next */
      default:
        break;
    }
  });
};

const gracefulExit = () => {
  mainStory.close();
  removeAllListeners();
};
/* istanbul ignore next */
try {
  window.addEventListener('beforeunload', gracefulExit);
} catch (err) { /* ignore */ }
try {
  process.on('exit', gracefulExit);
} catch (err) { /* ignore */ }

// -------------------------------------
// API
// -------------------------------------
export {
  mainStory,
  chalk,
  config,
  getListeners, addListener, removeListener, removeAllListeners,
};
<commit_msg>Storyboard (main): add default export<commit_after>/*!
 * Storyboard
 *
 * End-to-end, hierarchical, real-time, colorful logs and stories
 *
 * @copyright Guillermo Grau Panea 2016
 * @license MIT
 */

// Chalk is disabled by default in the browser. Override
// this default (we'll handle ANSI code conversion ourselves
// when needed)
import chalk from 'chalk';
import mainStory from './gral/stories';
import filters from './gral/filters';
import {
  init as hubInit,
  configure as hubConfigure,
  getListeners, addListener, removeListener, removeAllListeners,
} from './gral/hub';

chalk.enabled = true;

hubInit({ mainStory });

const config = (options = {}) => {
  Object.keys(options).forEach(key => {
    const val = options[key];
    switch (key) {
      case 'filter':
        filters.config(val);
        break;
      case 'bufSize':
        hubConfigure({ bufSize: val });
        break;
      /* istanbul ignore next */
      default:
        break;
    }
  });
};

const gracefulExit = () => {
  mainStory.close();
  removeAllListeners();
};
/* istanbul ignore next */
try {
  window.addEventListener('beforeunload', gracefulExit);
} catch (err) { /* ignore */ }
try {
  process.on('exit', gracefulExit);
} catch (err) { /* ignore */ }

// -------------------------------------
// API
// -------------------------------------
export {
  mainStory,
  chalk,
  config,
  getListeners, addListener, removeListener, removeAllListeners,
};

export default {
  mainStory,
  chalk,
  config,
  getListeners, addListener, removeListener, removeAllListeners,
};
<|endoftext|>


<commit_before>var options = require('./peg.json');
var fs = require('fs');
var grammar = fs.readFileSync('./src/Grammar/src/Grammar.pegjs').toString();
var PEG = require('pegjs');
var Grammar = PEG.buildParser(grammar, options);

module.exports = Grammar;
<commit_msg>src/Grammar/index.js: fix path to Grammar.pegjs<commit_after>var options = require('./peg.json');
var fs = require('fs');
var path = require('path').join(__dirname, './src/Grammar.pegjs');
var grammar = fs.readFileSync(path).toString();
var PEG = require('pegjs');
var Grammar = PEG.buildParser(grammar, options);

module.exports = Grammar;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 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
 *
 *   http://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.
 */

/**
 * @fileoverview An object that owns a block's rendering SVG elements.
 * @author fenichel@google.com (Rachel Fenichel)
 */

'use strict';

goog.provide('Blockly.blockRendering.PathObject');

goog.require('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.Theme');
goog.require('Blockly.utils.dom');

/**
 * An object that handles creating and setting each of the SVG elements
 * used by the renderer.
 * @param {!SVGElement} root The root SVG element.
 * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's
 *     constants.
 * @constructor
 * @implements {Blockly.blockRendering.IPathObject}
 * @package
 */
Blockly.blockRendering.PathObject = function(root, constants) {
  /**
   * The renderer's constant provider.
   * @type {!Blockly.blockRendering.ConstantProvider}
   * @protected
   */
  this.constants_ = constants;

  this.svgRoot = root;

  /**
   * The primary path of the block.
   * @type {SVGElement}
   * @package
   */
  this.svgPath = Blockly.utils.dom.createSvgElement('path',
      {'class': 'blocklyPath'}, this.svgRoot);

  // The light and dark paths need to exist (for now) because there is colouring
  // code in block_svg that depends on them.  But we will always set them to
  // display: none, and eventually we want to remove them entirely.

  /**
   * The light path of the block.
   * @type {SVGElement}
   * @package
   */
  this.svgPathLight = Blockly.utils.dom.createSvgElement('path',
      {'class': 'blocklyPathLight'}, this.svgRoot);

  /**
   * The style object to use when colouring block paths.
   * @type {!Blockly.Theme.BlockStyle}
   * @package
   */
  this.style = Blockly.Theme.createBlockStyle('#000000');
};

/**
 * Set the path generated by the renderer onto the respective SVG element.
 * @param {string} pathString The path.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) {
  this.svgPath.setAttribute('d', pathString);
  this.svgPathLight.style.display = 'none';
};

/**
 * Flip the SVG paths in RTL.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.flipRTL = function() {
  // Mirror the block's path.
  this.svgPath.setAttribute('transform', 'scale(-1 1)');
};

/**
 * Apply the stored colours to the block's path, taking into account whether
 * the paths belong to a shadow block.
 * @param {boolean} isShadow True if the block is a shadow block.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) {
  if (isShadow) {
    this.svgPath.setAttribute('stroke', 'none');
    this.svgPath.setAttribute('fill', this.style.colourSecondary);
  } else {
    this.svgPath.setAttribute('stroke', this.style.colourTertiary);
    this.svgPath.setAttribute('fill', this.style.colourPrimary);
  }
};

/**
 * Set the style.
 * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) {
  this.style = blockStyle;
};

/**
 * Add or remove the given CSS class on the path object's root SVG element.
 * @param {string} className The name of the class to add or remove
 * @param {boolean} add True if the class should be added.  False if it should
 *     be removed.
 * @protected
 */
Blockly.blockRendering.PathObject.prototype.setClass_ = function(
    className, add) {
  if (add) {
    Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgRoot),
        className);
  } else {
    Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgRoot),
        className);
  }
};

/**
 * Set whether the block shows a highlight or not.  Block highlighting is
 * often used to visually mark blocks currently being executed.
 * @param {boolean} enable True if highlighted.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateHighlighted = function(
    enable) {
  if (enable) {
    this.svgPath.setAttribute('filter',
        'url(#' + this.constants_.embossFilterId + ')');
  } else {
    this.svgPath.setAttribute('filter', 'none');
  }
};

/**
 * Set whether the block shows a disable pattern or not.
 * @param {boolean} disabled True if disabled.
 * @param {boolean} isShadow True if the block is a shadow block.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled,
    isShadow) {

  this.setClass_('blocklyDisabled', disabled);
  if (disabled) {
    this.svgPath.setAttribute('fill',
        'url(#' + this.constants_.disabledPatternId + ')');
  } else {
    this.applyColour(isShadow);
  }
};

/**
 * Add or remove styling showing that a block is selected.
 * @param {boolean} enable True if selection is enabled, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) {
  this.setClass_('blocklySelected', enable);
  if (enable) {
    this.svgPath.setAttribute('stroke', '#fc3');
    this.svgPath.setAttribute('stroke-width', '3px');
  } else {
    this.svgPath.setAttribute('stroke', '');
    this.svgPath.setAttribute('stroke-width', '');
  }
};

/**
 * Add or remove styling showing that a block is dragged over a delete area.
 * @param {boolean} enable True if the block is being dragged over a delete
 *     area, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function(
    enable) {
  this.setClass_('blocklyDraggingDelete', enable);
};

/**
 * Add or remove styling showing that a block is an insertion marker.
 * @param {boolean} enable True if the block is an insertion marker, false
 *     otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function(
    enable) {
  this.setClass_('blocklyInsertionMarker', enable);
};

/**
 * Add or remove styling showing that a block is movable.
 * @param {boolean} enable True if the block is movable, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) {
  this.setClass_('blocklyDraggable', enable);
};

/**
 * Add or remove styling that shows that if the dragging block is dropped, this
 * block will be replaced.  If a shadow block, it will disappear.  Otherwise it
 * will bump.
 * @param {boolean} enable True if styling should be added.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateReplacementHighlight =
    function(enable) {
    /* eslint-disable indent */
  this.setClass_('blocklyReplaceable', enable);
}; /* eslint-enable indent */
<commit_msg><commit_after>/**
 * @license
 * Copyright 2019 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
 *
 *   http://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.
 */

/**
 * @fileoverview An object that owns a block's rendering SVG elements.
 * @author fenichel@google.com (Rachel Fenichel)
 */

'use strict';

goog.provide('Blockly.blockRendering.PathObject');

goog.require('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.Theme');
goog.require('Blockly.utils.dom');

/**
 * An object that handles creating and setting each of the SVG elements
 * used by the renderer.
 * @param {!SVGElement} root The root SVG element.
 * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's
 *     constants.
 * @constructor
 * @implements {Blockly.blockRendering.IPathObject}
 * @package
 */
Blockly.blockRendering.PathObject = function(root, constants) {
  /**
   * The renderer's constant provider.
   * @type {!Blockly.blockRendering.ConstantProvider}
   * @protected
   */
  this.constants_ = constants;

  this.svgRoot = root;

  /**
   * The primary path of the block.
   * @type {SVGElement}
   * @package
   */
  this.svgPath = Blockly.utils.dom.createSvgElement('path',
      {'class': 'blocklyPath'}, this.svgRoot);

  /**
   * The style object to use when colouring block paths.
   * @type {!Blockly.Theme.BlockStyle}
   * @package
   */
  this.style = Blockly.Theme.createBlockStyle('#000000');
};

/**
 * Set the path generated by the renderer onto the respective SVG element.
 * @param {string} pathString The path.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) {
  this.svgPath.setAttribute('d', pathString);
};

/**
 * Flip the SVG paths in RTL.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.flipRTL = function() {
  // Mirror the block's path.
  this.svgPath.setAttribute('transform', 'scale(-1 1)');
};

/**
 * Apply the stored colours to the block's path, taking into account whether
 * the paths belong to a shadow block.
 * @param {boolean} isShadow True if the block is a shadow block.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) {
  if (isShadow) {
    this.svgPath.setAttribute('stroke', 'none');
    this.svgPath.setAttribute('fill', this.style.colourSecondary);
  } else {
    this.svgPath.setAttribute('stroke', this.style.colourTertiary);
    this.svgPath.setAttribute('fill', this.style.colourPrimary);
  }
};

/**
 * Set the style.
 * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) {
  this.style = blockStyle;
};

/**
 * Add or remove the given CSS class on the path object's root SVG element.
 * @param {string} className The name of the class to add or remove
 * @param {boolean} add True if the class should be added.  False if it should
 *     be removed.
 * @protected
 */
Blockly.blockRendering.PathObject.prototype.setClass_ = function(
    className, add) {
  if (add) {
    Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgRoot),
        className);
  } else {
    Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgRoot),
        className);
  }
};

/**
 * Set whether the block shows a highlight or not.  Block highlighting is
 * often used to visually mark blocks currently being executed.
 * @param {boolean} enable True if highlighted.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateHighlighted = function(
    enable) {
  if (enable) {
    this.svgPath.setAttribute('filter',
        'url(#' + this.constants_.embossFilterId + ')');
  } else {
    this.svgPath.setAttribute('filter', 'none');
  }
};

/**
 * Set whether the block shows a disable pattern or not.
 * @param {boolean} disabled True if disabled.
 * @param {boolean} isShadow True if the block is a shadow block.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled,
    isShadow) {

  this.setClass_('blocklyDisabled', disabled);
  if (disabled) {
    this.svgPath.setAttribute('fill',
        'url(#' + this.constants_.disabledPatternId + ')');
  } else {
    this.applyColour(isShadow);
  }
};

/**
 * Add or remove styling showing that a block is selected.
 * @param {boolean} enable True if selection is enabled, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) {
  this.setClass_('blocklySelected', enable);
  if (enable) {
    this.svgPath.setAttribute('stroke', '#fc3');
    this.svgPath.setAttribute('stroke-width', '3px');
  } else {
    this.svgPath.setAttribute('stroke', '');
    this.svgPath.setAttribute('stroke-width', '');
  }
};

/**
 * Add or remove styling showing that a block is dragged over a delete area.
 * @param {boolean} enable True if the block is being dragged over a delete
 *     area, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function(
    enable) {
  this.setClass_('blocklyDraggingDelete', enable);
};

/**
 * Add or remove styling showing that a block is an insertion marker.
 * @param {boolean} enable True if the block is an insertion marker, false
 *     otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function(
    enable) {
  this.setClass_('blocklyInsertionMarker', enable);
};

/**
 * Add or remove styling showing that a block is movable.
 * @param {boolean} enable True if the block is movable, false otherwise.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) {
  this.setClass_('blocklyDraggable', enable);
};

/**
 * Add or remove styling that shows that if the dragging block is dropped, this
 * block will be replaced.  If a shadow block, it will disappear.  Otherwise it
 * will bump.
 * @param {boolean} enable True if styling should be added.
 * @package
 */
Blockly.blockRendering.PathObject.prototype.updateReplacementHighlight =
    function(enable) {
    /* eslint-disable indent */
  this.setClass_('blocklyReplaceable', enable);
}; /* eslint-enable indent */
<|endoftext|>


<commit_before>//Template.course.events({
//    'click  #edit-course': function () {
//        // set edit mode variable to true
//    },
//    'click #cancel-course-edit': function () {
//        // set edit mode variable to false
//    }
//});

Template.course.rendered = function () {
    // set default mode for x-editable
    //$.fn.editable.defaults.mode = 'inline';
    //modify buttons style
    $.fn.editableform.buttons =
        '<button type="submit" class="btn btn-success editable-submit btn-mini"></button>' +
        '<button type="button" class="btn btn-danger editable-cancel"></button>';
}

/*
* Enable sidebar inline editors
* used in various child-template events
* such as template rendered, cancel edit, etc
*/
enableSidebarInlineEditors = function () {
    //enables inline-editing
    //TODO: think about better place
    $('.lesson-link').editable({
        // Make sure text doesn't display twice after saving
        display: false
    });
    $('.section-title').editable();
    $('#course-title').editable();
};

/*
* Disable sidebar inline editors
* used in various child-template events
* such as template rendered, cancel edit, etc
*/
disableSidebarInlineEditors = function () {
    //disables inline-editing
    $('.lesson-link').editable('destroy');
    $('.section-title').editable('destroy');
    $('#course-title').editable('destroy');
};
<commit_msg>Conditional sidebar editable.<commit_after>//Template.course.events({
//    'click  #edit-course': function () {
//        // set edit mode variable to true
//    },
//    'click #cancel-course-edit': function () {
//        // set edit mode variable to false
//    }
//});

Template.course.rendered = function () {
    // set default mode for x-editable
    //$.fn.editable.defaults.mode = 'inline';
    //modify buttons style
    $.fn.editableform.buttons =
        '<button type="submit" class="btn btn-success editable-submit btn-mini"></button>' +
        '<button type="button" class="btn btn-danger editable-cancel"></button>';
}

/*
* Enable sidebar inline editors
* used in various child-template events
* such as template rendered, cancel edit, etc
*/
enableSidebarInlineEditors = function () {
    if (Session.get('editMode')) {
        //enables inline-editing
        $('.lesson-link').editable({
            // Make sure text doesn't display twice after saving
            // since title will update reactively from database
            display: false
        });
        $('.section-title').editable();
        $('#course-title').editable();
    }
};

/*
* Disable sidebar inline editors
* used in various child-template events
* such as template rendered, cancel edit, etc
*/
disableSidebarInlineEditors = function () {
    //disables inline-editing
    $('.lesson-link').editable('destroy');
    $('.section-title').editable('destroy');
    $('#course-title').editable('destroy');
};
<|endoftext|>


<commit_before>import {UPDATE_SETUP_SUCCESS} from '../actions/actionTypes';

function reducer(state = window.__SESSION_INFO__, action) {
  console.log('session info reducer ', state)
  switch (action.type) {
    case UPDATE_SETUP_SUCCESS:
      return state.setIn('isActive', true);
  }
  return state;
}

export default reducer;
<commit_msg>Revert "fix createSession"<commit_after>
function reducer(state = window.__SESSION_INFO__) {
  console.log('session info reducer ', state)
  return state;
}

export default reducer;
<|endoftext|>


<commit_before>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-main-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const bigRedBtn = document.querySelector('#big-red-btn');
  const controlsTitleWrapper = document.querySelector('.controls-title-wrapper');
  const inputWidth = document.querySelector('#aspect-ratio-width');
  const inputHeight = document.querySelector('#aspect-ratio-height');
  const options = document.querySelector('.options');
  const size = document.querySelector('#size');
  const swapBtn = document.querySelector('.swap-btn');
  const time = document.querySelector('#time');
  const triangle = document.querySelector('#triangle');
  const windowTitle = document.querySelector('#window-title');

  let recording = false;

  let monitoringIntervalId;

  let lastValidInputWidth = 512;
  let lastValidInputHeight = 512;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        if (!err) {
          size.innerText = fileSize(stats.size).human('si');
        } // TODO: track this error
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startRecording() { // eslint-disable-line no-unused-vars
    ipcRenderer.send('will-start-recording');
    const past = Date.now();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed

    let cropperBounds;
    if (ipcRenderer.sendSync('is-cropper-active')) {
      cropperBounds = ipcRenderer.sendSync('get-cropper-bounds');
      // convert the coordinates to cartesian coordinates, which are used by CoreMedia
      cropperBounds.y = screen.height - (cropperBounds.y + cropperBounds.height);

       // the dashed border is 2px wide
      cropperBounds.x += 2;
      cropperBounds.y += 2;
      cropperBounds.width -= 4;
      cropperBounds.height -= 4;
    }

    aperture.startRecording({
      cropArea: cropperBounds
    })
      .then(filePath => {
        windowTitle.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        ipcRenderer.send('will-stop-recording');
        recording = false;
        console.error(err);
        windowTitle.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    ipcRenderer.send('will-stop-recording');
    stopMonitoring();
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        windowTitle.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  bigRedBtn.onclick = function () {
    if (recording) {
      stopRecording();
    } else {
      const state = this.attributes['data-state'].value;
      if (state === 'initial') {
        ipcRenderer.send('open-cropper-window', {
          width: parseInt(inputWidth.value, 10),
          height: parseInt(inputHeight.value, 10)
        });
      }
      // startRecording();
    }
  };

  controlsTitleWrapper.onclick = function () {
    const controls = document.querySelector('.controls');

    triangle.classList.toggle('up');

    controls.classList.toggle('hidden');
    setWindowSize();
  };

  options.onclick = event => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
    event.stopPropagation();
  };

  function shake(input) {
    input.classList.add('invalid');

    input.addEventListener('webkitAnimationEnd', () => {
      input.classList.remove('invalid');
    })
  }

  function validateNumericInput(input, opts) {
    let value = input.value;
    if (value === '' && opts.empty) {
      return value;
    }

    if (!value || !opts || !opts.lastValidValue) {
      return undefined;
    }

    value = parseInt(value, 10);

    if (!/^\d{1,5}$/.test(value)) {
      opts.onInvalid(input);
      return opts.lastValidValue;
    }

    if (opts.max && value > opts.max) {
      opts.onInvalid(input);
      return opts.max;
    }

    if (opts.min && value < opts.min) {
      opts.onInvalid(input);
      return opts.min;
    }

    return value;
  }

  inputWidth.oninput = function () {
    this.value = validateNumericInput(this, {
      lastValidValue: lastValidInputWidth,
      empty: true,
      max: screen.width,
      min: 1,
      onInvalid: shake
    });
    lastValidInputWidth = this.value || lastValidInputWidth;
  };

  inputWidth.onblur = function () {
    this.value = this.value || 512; // prevent the input from staying empty
  };

  inputHeight.oninput = function () {
    this.value = validateNumericInput(this, {
      lastValidValue: lastValidInputHeight,
      empty: true,
      max: screen.height - screen.availTop, // currently we can't draw over the menubar,
      min: 1,
      onInvalid: shake
    });
    lastValidInputHeight = this.value || lastValidInputHeight;
  };

  inputHeight.onblur = function () {
    this.value = this.value || 512; // prevent the input from staying empty
  };

  swapBtn.onclick = () => {
    [inputWidth.value, inputHeight.value] = [inputHeight.value, inputWidth.value];
    inputWidth.oninput();
    inputHeight.oninput();
  }
});

window.addEventListener('load', setWindowSize);
<commit_msg>Shake the input if the values are invalid after a swap<commit_after>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-main-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const bigRedBtn = document.querySelector('#big-red-btn');
  const controlsTitleWrapper = document.querySelector('.controls-title-wrapper');
  const inputWidth = document.querySelector('#aspect-ratio-width');
  const inputHeight = document.querySelector('#aspect-ratio-height');
  const options = document.querySelector('.options');
  const size = document.querySelector('#size');
  const swapBtn = document.querySelector('.swap-btn');
  const time = document.querySelector('#time');
  const triangle = document.querySelector('#triangle');
  const windowTitle = document.querySelector('#window-title');

  let recording = false;

  let monitoringIntervalId;

  let lastValidInputWidth = 512;
  let lastValidInputHeight = 512;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        if (!err) {
          size.innerText = fileSize(stats.size).human('si');
        } // TODO: track this error
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startRecording() { // eslint-disable-line no-unused-vars
    ipcRenderer.send('will-start-recording');
    const past = Date.now();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed

    let cropperBounds;
    if (ipcRenderer.sendSync('is-cropper-active')) {
      cropperBounds = ipcRenderer.sendSync('get-cropper-bounds');
      // convert the coordinates to cartesian coordinates, which are used by CoreMedia
      cropperBounds.y = screen.height - (cropperBounds.y + cropperBounds.height);

       // the dashed border is 2px wide
      cropperBounds.x += 2;
      cropperBounds.y += 2;
      cropperBounds.width -= 4;
      cropperBounds.height -= 4;
    }

    aperture.startRecording({
      cropArea: cropperBounds
    })
      .then(filePath => {
        windowTitle.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        ipcRenderer.send('will-stop-recording');
        recording = false;
        console.error(err);
        windowTitle.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    ipcRenderer.send('will-stop-recording');
    stopMonitoring();
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        windowTitle.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  bigRedBtn.onclick = function () {
    if (recording) {
      stopRecording();
    } else {
      const state = this.attributes['data-state'].value;
      if (state === 'initial') {
        ipcRenderer.send('open-cropper-window', {
          width: parseInt(inputWidth.value, 10),
          height: parseInt(inputHeight.value, 10)
        });
      }
      // startRecording();
    }
  };

  controlsTitleWrapper.onclick = function () {
    const controls = document.querySelector('.controls');

    triangle.classList.toggle('up');

    controls.classList.toggle('hidden');
    setWindowSize();
  };

  options.onclick = event => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
    event.stopPropagation();
  };

  function shake(input) {
    input.classList.add('invalid');

    input.addEventListener('webkitAnimationEnd', () => {
      input.classList.remove('invalid');
    })

    return true;
  }

  function validateNumericInput(input, opts) {
    let value = input.value;
    if (value === '' && opts.empty) {
      return value;
    }

    if (!value || !opts || !opts.lastValidValue) {
      return undefined;
    }

    value = parseInt(value, 10);

    if (!/^\d{1,5}$/.test(value)) {
      opts.onInvalid(input);
      return opts.lastValidValue;
    }

    if (opts.max && value > opts.max) {
      opts.onInvalid(input);
      return opts.max;
    }

    if (opts.min && value < opts.min) {
      opts.onInvalid(input);
      return opts.min;
    }

    return value;
  }

  inputWidth.oninput = function () {
    this.value = validateNumericInput(this, {
      lastValidValue: lastValidInputWidth,
      empty: true,
      max: screen.width,
      min: 1,
      onInvalid: shake
    });
    lastValidInputWidth = this.value || lastValidInputWidth;
  };

  inputWidth.onblur = function () {
    this.value = this.value || (shake(this) && 512); // prevent the input from staying empty
  };

  inputHeight.oninput = function () {
    this.value = validateNumericInput(this, {
      lastValidValue: lastValidInputHeight,
      empty: true,
      max: screen.height - screen.availTop, // currently we can't draw over the menubar,
      min: 1,
      onInvalid: shake
    });
    lastValidInputHeight = this.value || lastValidInputHeight;
  };

  inputHeight.onblur = function () {
    this.value = this.value || (shake(this) && 512); // prevent the input from staying empty
  };

  swapBtn.onclick = () => {
    [inputWidth.value, inputHeight.value] = [inputHeight.value, inputWidth.value];
    inputWidth.oninput();
    inputHeight.oninput();
  }
});

window.addEventListener('load', setWindowSize);
<|endoftext|>


<commit_before>(function() {
    SVG.extend(SVG.Element, {
        /**
         * draggy
         * Makes an element draggable.
         *
         * @name draggy
         * @function
         * @param {Object|Function} constraint An object containing the
         * constraint values or a function which gets the `x` and `y` values
         * and returns a boolean or an object containing the `x` and `y`
         * boolean values.`false` skips moving while `true` allows it.
         * @return {SVG} The SVG element.
         */
        draggy: function (constraint) {

            var start
              , drag
              , end
              , element = this
              ;

            // Remove draggable if already present
            if (typeof this.fixed === "function") {
                this.fixed();
            }

            // Ensure constraint object
            constraint = constraint || {};

            // Start dragging
            start = function(event) {
                var parent = this.parent(SVG.Nested) || this.parent(SVG.Doc);
                event = event || window.event;

                // Invoke any callbacks
                if (element.beforedrag) {
                    element.beforedrag(event);
                }

                // Get element bounding box
                var box = element.bbox();

                if (element instanceof SVG.G) {
                    box.x = element.x();
                    box.y = element.y();
                } else if (element instanceof SVG.Nested) {
                    box = {
                        x: element.x()
                      , y: element.y()
                      , width: element.width()
                      , height: element.height()
                    };
                }

                // Store event
                element.startEvent = event;

                // Store start position
                element.startPosition = {
                    x: box.x
                  , y: box.y
                  , width: box.width
                  , height: box.height
                  , zoom: parent.viewbox().zoom
                  , rotation: element.transform("rotation") * Math.PI / 180
                };

                // Add while and end events to window
                SVG.on(window, "mousemove", drag);
                SVG.on(window, "touchmove", drag);

                SVG.on(window, "mouseup", end);
                SVG.on(window, "touchend", end);

                // Invoke any callbacks
                element.node.dispatchEvent(new CustomEvent("dragstart", {
                    detail: {
                        event: event
                      , delta: {
                            x: 0
                          , y: 0
                        }
                    }
                }));

                // Prevent selection dragging
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            };

            function elmZoom(elm) {
                if (!elm || typeof elm.transform !== "function") { return { x: 1, y: 1 }; }
                var p = elm.parent();
                var t = elm.transform();
                pz = {};
                var pz = elmZoom(p);
                return {
                    x: t.scaleX * pz.x
                  , y: t.scaleY * pz.y
                };
            }

            // While dragging
            drag = function(event) {
                event = event || window.event;

                if (element.startEvent) {
                    // Calculate move position
                    var x
                      , y
                      , rotation = element.startPosition.rotation
                      , width = element.startPosition.width
                      , height = element.startPosition.height
                      , delta = {
                            x: event.pageX - element.startEvent.pageX
                          , y: event.pageY - element.startEvent.pageY
                        }
                      ;

                    if (/^touchstart|touchmove$/.test(event.type)) {
                        delta.x = event.touches[0].pageX - element.startEvent.touches[0].pageX;
                        delta.y = event.touches[0].pageY - element.startEvent.touches[0].pageY;
                    } else if(/^click|mousedown|mousemove$/.test(event.type)) {
                        delta.x = event.pageX - element.startEvent.pageX;
                        delta.y = event.pageY - element.startEvent.pageY;
                    }

                    delta.scale = elmZoom(element);

                    x = element.startPosition.x + (delta.x * Math.cos(rotation) + delta.y * Math.sin(rotation)) / Math.pow(delta.scale.x, 1);
                    y = element.startPosition.y + (delta.y * Math.cos(rotation) + delta.x * Math.sin(-rotation)) / Math.pow(delta.scale.y, 1);

                    // Move the element to its new position, if possible by constraint
                    if (typeof constraint === "function") {
                        var coord = constraint(x, y);
                        if (typeof coord === "object") {
                            if (typeof coord.x !== "boolean" || coord.x) {
                                x = typeof coord.x === "number" ? coord.x : x;
                                element.x(x);
                            } else {
                                x = element.x();
                            }

                            if (typeof coord.y !== "boolean" || coord.y) {
                                y = typeof coord.y === "number" ? coord.y : y;
                                element.y(y);
                            } else {
                                y = element.y();
                            }
                        } else if (typeof coord === "boolean" && coord) {
                            element.move(x, y);
                        } else {
                            x = element.x();
                            y = element.y();
                        }
                    } else if (typeof constraint === "object") {
                        // Keep element within constrained box
                        if (constraint.minX !== null && x < constraint.minX) {
                            x = constraint.minX;
                        } else if (constraint.maxX !== null && x > constraint.maxX - width) {
                            x = constraint.maxX - width;
                        }

                        if (constraint.minY !== null && y < constraint.minY) {
                            y = constraint.minY;
                        } else if (constraint.maxY !== null && y > constraint.maxY - height) {
                            y = constraint.maxY - height;
                        }

                        element.move(x, y);
                    }

                    // Calculate the total movement
                    delta.movedX = x - element.startPosition.x;
                    delta.movedY = y - element.startPosition.y;

                    // Invoke any callbacks
                    element.node.dispatchEvent(new CustomEvent("dragmove", {
                        detail: {
                            delta: delta
                          , event: event
                        }
                    }));
                }
            };

            // When dragging ends
            end = function(event) {
                event = event || window.event;

                // Calculate move position
                var delta = {
                    x: event.pageX - element.startEvent.pageX
                  , y: event.pageY - element.startEvent.pageY
                  , zoom: element.startPosition.zoom
                };

                // Reset store
                element.startEvent = null;
                element.startPosition = null;

                // Remove while and end events to window
                SVG.off(window, "mousemove", drag);
                SVG.off(window, "touchmove", drag);
                SVG.off(window, "mouseup", end);
                SVG.off(window, "touchend", end);

                // Invoke any callbacks
                element.node.dispatchEvent(new CustomEvent("dragend", {
                    detail: {
                        delta: {
                            x: 0
                          , y: 0
                        }
                      , event: event
                    }
                }));
            };

            // Bind mousedown event
            element.on("mousedown", start);
            element.on("touchstart", start);

            // Disable draggable
            element.fixed = function() {
                element.off("mousedown", start);
                element.off("touchstart", start);

                SVG.off(window, "mousemove", drag);
                SVG.off(window, "touchmove", drag);
                SVG.off(window, "mouseup", end);
                SVG.off(window, "touchend", end);

                start = drag = end = null;

                return element;
            };

            return this;
        }
    });
}).call(this);
<commit_msg>Fix dragging on zoomed viewbox<commit_after>(function() {
    SVG.extend(SVG.Element, {
        /**
         * draggy
         * Makes an element draggable.
         *
         * @name draggy
         * @function
         * @param {Object|Function} constraint An object containing the
         * constraint values or a function which gets the `x` and `y` values
         * and returns a boolean or an object containing the `x` and `y`
         * boolean values.`false` skips moving while `true` allows it.
         * @return {SVG} The SVG element.
         */
        draggy: function (constraint) {

            var start
              , drag
              , end
              , element = this
              ;

            // Remove draggable if already present
            if (typeof this.fixed === "function") {
                this.fixed();
            }

            // Ensure constraint object
            constraint = constraint || {};

            // Start dragging
            start = function(event) {
                var parent = this.parent(SVG.Nested) || this.parent(SVG.Doc);
                event = event || window.event;

                // Invoke any callbacks
                if (element.beforedrag) {
                    element.beforedrag(event);
                }

                // Get element bounding box
                var box = element.bbox();

                if (element instanceof SVG.G) {
                    box.x = element.x();
                    box.y = element.y();
                } else if (element instanceof SVG.Nested) {
                    box = {
                        x: element.x()
                      , y: element.y()
                      , width: element.width()
                      , height: element.height()
                    };
                }

                // Store event
                element.startEvent = event;

                // Store start position
                element.startPosition = {
                    x: box.x
                  , y: box.y
                  , width: box.width
                  , height: box.height
                  , zoom: parent.viewbox().zoom
                  , rotation: element.transform("rotation") * Math.PI / 180
                };

                // Add while and end events to window
                SVG.on(window, "mousemove", drag);
                SVG.on(window, "touchmove", drag);

                SVG.on(window, "mouseup", end);
                SVG.on(window, "touchend", end);

                // Invoke any callbacks
                element.node.dispatchEvent(new CustomEvent("dragstart", {
                    detail: {
                        event: event
                      , delta: {
                            x: 0
                          , y: 0
                        }
                    }
                }));

                // Prevent selection dragging
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            };

            function elmZoom(elm) {
                if (!elm || typeof elm.transform !== "function") { return { x: 1, y: 1 }; }
                var p = elm.parent();
                var t = elm.transform();
                pz = {};
                var pz = elmZoom(p);
                return {
                    x: t.scaleX * pz.x
                  , y: t.scaleY * pz.y
                };
            }

            // While dragging
            drag = function(event) {
                event = event || window.event;

                if (element.startEvent) {
                    // Calculate move position
                    var x
                      , y
                      , rotation = element.startPosition.rotation
                      , width = element.startPosition.width
                      , height = element.startPosition.height
                      , zoom = element.startPosition.zoom
                      , delta = {
                            x: event.pageX - element.startEvent.pageX
                          , y: event.pageY - element.startEvent.pageY
                        }
                      ;

                    if (/^touchstart|touchmove$/.test(event.type)) {
                        delta.x = event.touches[0].pageX - element.startEvent.touches[0].pageX;
                        delta.y = event.touches[0].pageY - element.startEvent.touches[0].pageY;
                    } else if(/^click|mousedown|mousemove$/.test(event.type)) {
                        delta.x = event.pageX - element.startEvent.pageX;
                        delta.y = event.pageY - element.startEvent.pageY;
                    }

                    delta.scale = elmZoom(element);

                    x = element.startPosition.x + (delta.x * Math.cos(rotation) + delta.y * Math.sin(rotation)) / Math.pow(delta.scale.x * zoom, 1);
                    y = element.startPosition.y + (delta.y * Math.cos(rotation) + delta.x * Math.sin(-rotation)) / Math.pow(delta.scale.y * zoom, 1);

                    // Move the element to its new position, if possible by constraint
                    if (typeof constraint === "function") {
                        var coord = constraint(x, y);
                        if (typeof coord === "object") {
                            if (typeof coord.x !== "boolean" || coord.x) {
                                x = typeof coord.x === "number" ? coord.x : x;
                                element.x(x);
                            } else {
                                x = element.x();
                            }

                            if (typeof coord.y !== "boolean" || coord.y) {
                                y = typeof coord.y === "number" ? coord.y : y;
                                element.y(y);
                            } else {
                                y = element.y();
                            }
                        } else if (typeof coord === "boolean" && coord) {
                            element.move(x, y);
                        } else {
                            x = element.x();
                            y = element.y();
                        }
                    } else if (typeof constraint === "object") {
                        // Keep element within constrained box
                        if (constraint.minX !== null && x < constraint.minX) {
                            x = constraint.minX;
                        } else if (constraint.maxX !== null && x > constraint.maxX - width) {
                            x = constraint.maxX - width;
                        }

                        if (constraint.minY !== null && y < constraint.minY) {
                            y = constraint.minY;
                        } else if (constraint.maxY !== null && y > constraint.maxY - height) {
                            y = constraint.maxY - height;
                        }

                        element.move(x, y);
                    }

                    // Calculate the total movement
                    delta.movedX = x - element.startPosition.x;
                    delta.movedY = y - element.startPosition.y;

                    // Invoke any callbacks
                    element.node.dispatchEvent(new CustomEvent("dragmove", {
                        detail: {
                            delta: delta
                          , event: event
                        }
                    }));
                }
            };

            // When dragging ends
            end = function(event) {
                event = event || window.event;

                // Calculate move position
                var delta = {
                    x: event.pageX - element.startEvent.pageX
                  , y: event.pageY - element.startEvent.pageY
                  , zoom: element.startPosition.zoom
                };

                // Reset store
                element.startEvent = null;
                element.startPosition = null;

                // Remove while and end events to window
                SVG.off(window, "mousemove", drag);
                SVG.off(window, "touchmove", drag);
                SVG.off(window, "mouseup", end);
                SVG.off(window, "touchend", end);

                // Invoke any callbacks
                element.node.dispatchEvent(new CustomEvent("dragend", {
                    detail: {
                        delta: {
                            x: 0
                          , y: 0
                        }
                      , event: event
                    }
                }));
            };

            // Bind mousedown event
            element.on("mousedown", start);
            element.on("touchstart", start);

            // Disable draggable
            element.fixed = function() {
                element.off("mousedown", start);
                element.off("touchstart", start);

                SVG.off(window, "mousemove", drag);
                SVG.off(window, "touchmove", drag);
                SVG.off(window, "mouseup", end);
                SVG.off(window, "touchend", end);

                start = drag = end = null;

                return element;
            };

            return this;
        }
    });
}).call(this);
<|endoftext|>