<commit_before>L.AwesomeMarkers.DivIcon = L.AwesomeMarkers.Icon.extend({
  initialize: function (options) {
    L.AwesomeMarkers.Icon.prototype.initialize.call(this, options);
  },
  createIcon: function() {
    var div = L.AwesomeMarkers.Icon.prototype.createIcon.call(this);
    var s = document.createElement('div');
    s.cl***REMOVED***Name = "marker-tooltip";
    s.innerHTML = 'New Observation
Drag this marker to re-position
';
    div.insertBefore(s, div.firstChild);
    return div;
  }
});

L.AwesomeMarkers.divIcon = function (options) {
        return new L.AwesomeMarkers.DivIcon(options);
    };

(function () {
  var leafletDirective = angular.module("leaflet-directive", ["mage.***REMOVED***s"]);

  leafletDirective.directive("leaflet", function ($http, $log, $compile, $timeout, IconService, appConstants, MapService, DataService, TimeBucketService) {
    return {
      restrict: "A",
      replace: true,
      transclude: true,
      template: '

',
      link: function (scope, element, attrs, ctrl) {
        // Create the map
        var map = L.map("map", {trackResize: true});
        map.setView([0, 0], 3);
        var layerControl = L.control.layers();
        layerControl.addTo(map);
        scope.ds = DataService;

        map.on('baselayerchange', function(e) {
          MapService.updateLeafletLayer(e.layer._url, e.layer.options);
        });

        /*
        toolbar config
        */
        map.addControl(new L.Control.MageFeature());
        map.addControl(new L.Control.MageUserLocation());
        map.addControl(new L.Control.MageListTools());
        var sidebar = L.control.sidebar('side-bar', {closeButton: false});
        map.addControl(sidebar);
        scope.$watch('newsFeedEnabled', function() {
          if (scope.newsFeedEnabled) {
            sidebar.show();
          } else {
            sidebar.hide();
          }
        });
        //map.addControl(new L.Control.SideBar());
        //map.addControl(new L.Control.TimeScale());

        var addMarker = L.marker([0,0], {
          draggable: true,
          icon: new L.AwesomeMarkers.DivIcon({
            icon: 'plus',
            color: 'cadetblue'
          })
        });

        map.on("click", function(e) {
          if (scope.newObservationEnabled) {
            _.delay(function() { addMarker.setLatLng(e.latlng); }, 250);
            if (!map.hasLayer(addMarker)) {
              _.delay(function() { map.addLayer(addMarker); }, 250);
            }

            scope.$apply(function(s) {
              scope.markerLocation = e.latlng;
            });
          }
        });

        scope.$watch('newObservationEnabled', function() {
          if (!scope.newObservationEnabled && map.hasLayer(addMarker)) {
            map.removeLayer(addMarker);
          } else if (scope.newObservationEnabled) {
            addMarker.setLatLng(map.getCenter());
            scope.markerLocation = map.getCenter();
            if (!map.hasLayer(addMarker)) {
              _.delay(function() { map.addLayer(addMarker); }, 250);
            }
          }
        });

        addMarker.on('dragend', function(e) {
          scope.$apply(function(s) {
            scope.markerLocation = addMarker.getLatLng();
          });
        });

        var baseLayer = {};
        var layers = {};
        var markers = {};

        var locationLayer = L.locationMarker([0,0], {color: '#136AEC'});

        // event hooks
        map.on('locationfound', function(e) {
          if (!map.hasLayer(locationLayer)) {
            map.addLayer(locationLayer);
          }

          // no need to do anything if the location has not changed
          if (scope.location &&
              (scope.location.lat === e.latlng.lat &&
               scope.location.lng === e.latlng.lng &&
               scope.location.accuracy === e.accuracy)) {
            return;
          }

          scope.location = e;

          map.fitBounds(e.bounds);
          locationLayer.setLatLng(e.latlng).setAccuracy(e.accuracy);
          map.addLayer(locationLayer);
        });

        scope.$watch("locate", function(locate) {
          if (!locate) {
            map.removeLayer(locationLayer);
            map.stopLocate();
          } else {
            map.locate({
              watch: true
            });
          }
        });

        scope.$watch("baseLayers", function(layers) {
          if (!layers) return;
          var baseLayer;
          var firstLayer = undefined;
          _.each(layers, function(layer) {
            var options = {};
            if (layer.format == 'XYZ' || layer.format == 'TMS') {
              options = { tms: layer.format == 'TMS', maxZoom: 18}
              baseLayer = new L.TileLayer(layer.url, options);
            } else if (layer.format == 'WMS') {
              options = {
                layers: layer.wms.layers,
                version: layer.wms.version,
                format: layer.wms.format,
                transparent: layer.wms.transparent            };
              if (layer.wms.styles) options.styles = layer.wms.styles;
              baseLayer = new L.TileLayer.WMS(layer.url, options);
            }
            if (!firstLayer) {
              firstLayer = baseLayer;
              MapService.updateLeafletLayer(layer.url, options);
            }
            layerControl.addBaseLayer(baseLayer, layer.name);
           });
          if (firstLayer) {
            firstLayer.addTo(map);
            //MapService.currentBaseLayer = firstLayer;
          }
        });

        var currentLocationMarkers = {};
        var locationLayerGroup = new L.LayerGroup().addTo(map);
        scope.activeUserPopup = undefined;
        scope.$watch("ds.locations", function(derp) {
          if (!scope.ds.locations || !scope.ds.locations.$resolved) {
            if (scope.ds.locations && !scope.ds.locations.$promise) {
              locationLayerGroup.clearLayers();
              currentLocationMarkers = {};
            }
            return;
          }

          var users = scope.ds.locations;

          if (users.length == 0) {
            locationLayerGroup.clearLayers();
            currentLocationMarkers = {};
            return;
          }

          var locationMarkers = {};
          _.each(users, function(user) {
            var u = user;
            if (user.locations.length > 0) {
              var l = u.locations[0];
              var marker = currentLocationMarkers[u.user];
              if (marker) {
                delete currentLocationMarkers[u.user];
                locationMarkers[u.user] = marker;
                // Just update the location
                marker.setLatLng([l.geometry.coordinates[1], l.geometry.coordinates[0]]).setAccuracy(l.properties.accuracy).setColor(appConstants.userLocationToColor(l));
                return;
              }

              var layer = new L.GeoJSON(u.locations[0], {
                pointToLayer: function (feature, latlng) {
                  return L.locationMarker(latlng, {color: appConstants.userLocationToColor(feature)}).setAccuracy(feature.properties.accuracy);
                },
                onEachFeature: function(feature, layer) {
                  var e = $compile("

")(scope);
                  // TODO this sucks but for now set a min width
                  layer.bindPopup(e[0], {minWidth: 200});

                  layer.on('click', function() {

                    scope.activeFeature = undefined;

                    // location table click handling here
                    if(!scope.$$phase) {
                      scope.$apply(function(s) {
                        scope.activeLocation = {locations: [feature], user: feature.properties.user};
                      });
                    } else {
                      scope.activeLocation = {locations: [feature], user: feature.properties.user};
                    }
                    var gu = angular.element(e).scope().getUser;
                    if (gu) {
                      gu(u.user);
                    }
                    scope.activeUserPopup = layer;
                  });

                  locationMarkers[u.user] = layer;
                }
              });

              locationLayerGroup.addLayer(layer);
            }
          });

          _.each(currentLocationMarkers, function(marker, user) {
            locationLayerGroup.removeLayer(marker);
          });

          currentLocationMarkers = locationMarkers;
        }, true);

        var activeMarker;
        var featureConfig = function(layer) {
          return {
            pointToLayer: function (feature, latlng) {
              var icon;
              if (feature.properties.style) {
                var style = feature.properties.style;
                if (style.iconStyle) {
                  var icon = L.icon({
                    iconUrl: style.iconStyle.icon.href,
                    iconSize: [28, 28],
                    iconAnchor: [14, 14],
                  });
                  return L.marker(latlng, { icon: icon });
                }
              } else {
                var icon = IconService.leafletIcon(feature, {types: scope.types});
                var marker =  L.marker(latlng, { icon: icon });

                markers[layer.id][feature.id] = marker;
                return marker;
              }
            },
            style: function(feature) {
              if (feature.properties.style) {
                var style = {};
                if (feature.properties.style.lineStyle) {
                  style.color = feature.properties.style.lineStyle.color.rgb
                }
                if (feature.properties.style.polyStyle) {
                  style.fillColor = feature.properties.style.polyStyle.color.rgb;
                  style.fillOpacity = feature.properties.style.polyStyle.color.opacity;
                }

                return style;
              }
            },
            onEachFeature: function(feature, marker) {
              marker.on("click", function(e) {

                if (scope.activeUserPopup) {
                  scope.activeUserPopup.closePopup();
                }
                scope.activeLocation = undefined;
                scope.locationTableClick = undefined;

                // TODO, tmp for PDC, only have layerId so I cannot check if external layer
                // using style property to indicate an external layer
                activeMarker = marker;
                if (feature.properties.style) {
                  scope.$apply(function(s) {
                    scope.externalFeature = {layerId: layer.id, featureId: feature.id, feature: feature};
                  });
                  marker.bindPopup(L.popup().setContent(feature.properties.description));
                  // marker.bindPopup(L.popup());
                } else {
                  scope.$apply(function(s) {
                    var oldBucket = scope.selectedBucket;
                    scope.selectedBucket = TimeBucketService.findItemBucketIdx(feature, 'newsfeed', function(item) {
                      return item.properties ? item.properties.EVENTDATE : moment(item.locations[0].properties.timestamp).valueOf();
                    });
                    if (oldBucket == scope.selectedBucket) {
                      $('.news-items').animate({scrollTop: $('#'+feature.id).position().top},500);
                    } else {
                      // now we have to wait for the news feed to switch buckets then we can scroll
                      var tries = 0;
                      var runAnimate = function() {
                        var feedElement = $('#'+feature.id);
                        if (feedElement.length != 0) {
                          $('.news-items').animate({scrollTop: feedElement.position().top},500);
                          return;
                        }
                        tries++;
                        if (tries < 10) {
                          $timeout(runAnimate, 500);
                        }
                      };
                      $timeout(runAnimate, 500);
                    }
                    scope.activeFeature = {layerId: feature.layerId, featureId: feature.id, feature: feature};

                    //console.info('scroll top is ' + $('#'+feature.id).position().top);
                    //$('.news-items').scrollTop($('#'+feature.id).position().top);
                  });
                }
              });
            }
          }
        };

        scope.$watch('activeFeature', function(newFeature, oldFeature) {
          if (!newFeature && oldFeature) {
            var marker = markers[oldFeature.layerId][oldFeature.featureId];
            marker.unselect();
          } else if (newFeature) {
            var marker = markers[newFeature.layerId][newFeature.featureId];
            marker.select();
          }
        });

        scope.$watch('featureTableClick', function(o) {
          if (!o) return;
          var marker = markers[o.layerId][o.featureId];
          map.setView(marker.getLatLng(), map.getZoom() > 17 ? map.getZoom() : 17);
          layers[o.layerId].leafletLayer.zoomToShowLayer(marker, function(){});
        });

        scope.$watch('locationTableClick', function(location, oldLocation) {
          if (oldLocation) {
            currentLocationMarkers[oldLocation.user].closePopup();
          }
          if (!location) return;
          var marker = currentLocationMarkers[location.user];
          marker.openPopup();
          marker.fireEvent('click');
          map.setView(marker.getLatLng(), map.getZoom() > 17 ? map.getZoom() : 17);
        });

        scope.$watch("layer", function(layer) {
            if (!layer) return;

            if (layer.checked) {

              // add to map
              var newLayer = null;
              var gj = null;
              if (layer.type === 'Imagery') {
                if (layer.format == 'XYZ' || layer.format == 'TMS') {
                  newLayer = new L.TileLayer(layer.url, { tms: layer.format == 'TMS', maxZoom: 18});
                } else if (layer.format == 'WMS') {
                  var options = {
                    layers: layer.wms.layers,
                    version: layer.wms.version,
                    format: layer.wms.format,
                    transparent: layer.wms.transparent
                  };
                  if (layer.wms.styles) options.styles = layer.wms.styles;
                  newLayer = new L.TileLayer.WMS(layer.url, options);
                }
                newLayer.addTo(map).bringToFront();
              } else {
                if (!layer.features) {
                  return;
                }

              }

              layers[layer.id] = {
                leafletLayer: newLayer,
                layer: layer,
                gjLayer: gj
              };
            } else if (layers[layer.id]) {
              // remove from map
              map.removeLayer(layers[layer.id].leafletLayer);
              delete layers[layer.id];
            }
        }); // watch layer

        scope.$watch('layer.features', function(features) {
          if (!features) return;
          if (layers[scope.layer.id]) {
            var addThese = {
              features: []
            };
            for (var i = 0; i < features.features.length; i++) {
              var marker = markers[scope.layer.id][features.features[i].id];
              if (!marker) {
                addThese.features.push(features.features[i]);
              } else {
                marker.setIcon(IconService.leafletIcon(features.features[i], {types: scope.types}));
              }
            }
            newLayer = layers[scope.layer.id].leafletLayer;
            newLayer.addLayer(L.geoJson(addThese, featureConfig(layers[scope.layer.id].layer)));
          } else {
            markers[scope.layer.id] = {};
            var gj = L.geoJson(features, featureConfig(scope.layer));
            newLayer = L.markerClusterGroup()
            .addLayer(gj)
            .addTo(map)
            .bringToFront();
            layers[scope.layer.id] = {
                leafletLayer: newLayer,
                layer: scope.layer,
                gjLayer: gj
              };
          }
        });

        scope.$watch("newFeature", function(feature) {
          if (!feature) return;

          map.removeLayer(addMarker);
          var layer = layers[scope.currentLayerId];
          if (layer) {
            layer.leafletLayer.addLayer(L.geoJson(feature, featureConfig(layer.layer)));
          }
        }); // watch newFeature

        scope.$watch("updatedFeature", function(feature) {
          if (!feature) return;

          activeMarker.setIcon(IconService.leafletIcon(feature, {types: scope.types, levels: scope.levels}));
        });

        scope.$watch("externalFeature", function(value) {
          if (!value) return;

          //activeMarker.bindPopup(L.popup().setContent(value.feature.properties.description)).openPopup();
        });

        scope.$watch("deletedFeature", function(feature) {
          if (!feature) return;

          var layer = layers[feature.layerId].leafletLayer;
          if (layer) {
            layer.removeLayer(activeMarker);
          }
        })

      } // end of link function
    };
  });
}());<commit_msg>indentation<commit_after>L.AwesomeMarkers.DivIcon = L.AwesomeMarkers.Icon.extend({
  initialize: function (options) {
    L.AwesomeMarkers.Icon.prototype.initialize.call(this, options);
  },
  createIcon: function() {
    var div = L.AwesomeMarkers.Icon.prototype.createIcon.call(this);
    var s = document.createElement('div');
    s.cl***REMOVED***Name = "marker-tooltip";
    s.innerHTML = 'New Observation
Drag this marker to re-position
';
    div.insertBefore(s, div.firstChild);
    return div;
  }
});

L.AwesomeMarkers.divIcon = function (options) {
  return new L.AwesomeMarkers.DivIcon(options);
};

(function () {
  var leafletDirective = angular.module("leaflet-directive", ["mage.***REMOVED***s"]);

  leafletDirective.directive("leaflet", function ($http, $log, $compile, $timeout, IconService, appConstants, MapService, DataService, TimeBucketService) {
    return {
      restrict: "A",
      replace: true,
      transclude: true,
      template: '

',
      link: function (scope, element, attrs, ctrl) {
        // Create the map
        var map = L.map("map", {trackResize: true});
        map.setView([0, 0], 3);
        var layerControl = L.control.layers();
        layerControl.addTo(map);
        scope.ds = DataService;

        map.on('baselayerchange', function(e) {
          MapService.updateLeafletLayer(e.layer._url, e.layer.options);
        });

        /*
        toolbar config
        */
        map.addControl(new L.Control.MageFeature());
        map.addControl(new L.Control.MageUserLocation());
        map.addControl(new L.Control.MageListTools());
        var sidebar = L.control.sidebar('side-bar', {closeButton: false});
        map.addControl(sidebar);
        scope.$watch('newsFeedEnabled', function() {
          if (scope.newsFeedEnabled) {
            sidebar.show();
          } else {
            sidebar.hide();
          }
        });
        //map.addControl(new L.Control.SideBar());
        //map.addControl(new L.Control.TimeScale());

        var addMarker = L.marker([0,0], {
          draggable: true,
          icon: new L.AwesomeMarkers.DivIcon({
            icon: 'plus',
            color: 'cadetblue'
          })
        });

        map.on("click", function(e) {
          if (scope.newObservationEnabled) {
            _.delay(function() { addMarker.setLatLng(e.latlng); }, 250);
            if (!map.hasLayer(addMarker)) {
              _.delay(function() { map.addLayer(addMarker); }, 250);
            }

            scope.$apply(function(s) {
              scope.markerLocation = e.latlng;
            });
          }
        });

        scope.$watch('newObservationEnabled', function() {
          if (!scope.newObservationEnabled && map.hasLayer(addMarker)) {
            map.removeLayer(addMarker);
          } else if (scope.newObservationEnabled) {
            addMarker.setLatLng(map.getCenter());
            scope.markerLocation = map.getCenter();
            if (!map.hasLayer(addMarker)) {
              _.delay(function() { map.addLayer(addMarker); }, 250);
            }
          }
        });

        addMarker.on('dragend', function(e) {
          scope.$apply(function(s) {
            scope.markerLocation = addMarker.getLatLng();
          });
        });

        var baseLayer = {};
        var layers = {};
        var markers = {};

        var locationLayer = L.locationMarker([0,0], {color: '#136AEC'});

        // event hooks
        map.on('locationfound', function(e) {
          if (!map.hasLayer(locationLayer)) {
            map.addLayer(locationLayer);
          }

          // no need to do anything if the location has not changed
          if (scope.location &&
              (scope.location.lat === e.latlng.lat &&
               scope.location.lng === e.latlng.lng &&
               scope.location.accuracy === e.accuracy)) {
            return;
          }

          scope.location = e;

          map.fitBounds(e.bounds);
          locationLayer.setLatLng(e.latlng).setAccuracy(e.accuracy);
          map.addLayer(locationLayer);
        });

        scope.$watch("locate", function(locate) {
          if (!locate) {
            map.removeLayer(locationLayer);
            map.stopLocate();
          } else {
            map.locate({
              watch: true
            });
          }
        });

        scope.$watch("baseLayers", function(layers) {
          if (!layers) return;
          var baseLayer;
          var firstLayer = undefined;
          _.each(layers, function(layer) {
            var options = {};
            if (layer.format == 'XYZ' || layer.format == 'TMS') {
              options = { tms: layer.format == 'TMS', maxZoom: 18}
              baseLayer = new L.TileLayer(layer.url, options);
            } else if (layer.format == 'WMS') {
              options = {
                layers: layer.wms.layers,
                version: layer.wms.version,
                format: layer.wms.format,
                transparent: layer.wms.transparent            };
              if (layer.wms.styles) options.styles = layer.wms.styles;
              baseLayer = new L.TileLayer.WMS(layer.url, options);
            }
            if (!firstLayer) {
              firstLayer = baseLayer;
              MapService.updateLeafletLayer(layer.url, options);
            }
            layerControl.addBaseLayer(baseLayer, layer.name);
           });
          if (firstLayer) {
            firstLayer.addTo(map);
            //MapService.currentBaseLayer = firstLayer;
          }
        });

        var currentLocationMarkers = {};
        var locationLayerGroup = new L.LayerGroup().addTo(map);
        scope.activeUserPopup = undefined;
        scope.$watch("ds.locations", function(derp) {
          if (!scope.ds.locations || !scope.ds.locations.$resolved) {
            if (scope.ds.locations && !scope.ds.locations.$promise) {
              locationLayerGroup.clearLayers();
              currentLocationMarkers = {};
            }
            return;
          }

          var users = scope.ds.locations;

          if (users.length == 0) {
            locationLayerGroup.clearLayers();
            currentLocationMarkers = {};
            return;
          }

          var locationMarkers = {};
          _.each(users, function(user) {
            var u = user;
            if (user.locations.length > 0) {
              var l = u.locations[0];
              var marker = currentLocationMarkers[u.user];
              if (marker) {
                delete currentLocationMarkers[u.user];
                locationMarkers[u.user] = marker;
                // Just update the location
                marker.setLatLng([l.geometry.coordinates[1], l.geometry.coordinates[0]]).setAccuracy(l.properties.accuracy).setColor(appConstants.userLocationToColor(l));
                return;
              }

              var layer = new L.GeoJSON(u.locations[0], {
                pointToLayer: function (feature, latlng) {
                  return L.locationMarker(latlng, {color: appConstants.userLocationToColor(feature)}).setAccuracy(feature.properties.accuracy);
                },
                onEachFeature: function(feature, layer) {
                  var e = $compile("

")(scope);
                  // TODO this sucks but for now set a min width
                  layer.bindPopup(e[0], {minWidth: 200});

                  layer.on('click', function() {

                    scope.activeFeature = undefined;

                    // location table click handling here
                    if(!scope.$$phase) {
                      scope.$apply(function(s) {
                        scope.activeLocation = {locations: [feature], user: feature.properties.user};
                      });
                    } else {
                      scope.activeLocation = {locations: [feature], user: feature.properties.user};
                    }
                    var gu = angular.element(e).scope().getUser;
                    if (gu) {
                      gu(u.user);
                    }
                    scope.activeUserPopup = layer;
                  });

                  locationMarkers[u.user] = layer;
                }
              });

              locationLayerGroup.addLayer(layer);
            }
          });

          _.each(currentLocationMarkers, function(marker, user) {
            locationLayerGroup.removeLayer(marker);
          });

          currentLocationMarkers = locationMarkers;
        }, true);

        var activeMarker;
        var featureConfig = function(layer) {
          return {
            pointToLayer: function (feature, latlng) {
              var icon;
              if (feature.properties.style) {
                var style = feature.properties.style;
                if (style.iconStyle) {
                  var icon = L.icon({
                    iconUrl: style.iconStyle.icon.href,
                    iconSize: [28, 28],
                    iconAnchor: [14, 14],
                  });
                  return L.marker(latlng, { icon: icon });
                }
              } else {
                var icon = IconService.leafletIcon(feature, {types: scope.types});
                var marker =  L.marker(latlng, { icon: icon });

                markers[layer.id][feature.id] = marker;
                return marker;
              }
            },
            style: function(feature) {
              if (feature.properties.style) {
                var style = {};
                if (feature.properties.style.lineStyle) {
                  style.color = feature.properties.style.lineStyle.color.rgb
                }
                if (feature.properties.style.polyStyle) {
                  style.fillColor = feature.properties.style.polyStyle.color.rgb;
                  style.fillOpacity = feature.properties.style.polyStyle.color.opacity;
                }

                return style;
              }
            },
            onEachFeature: function(feature, marker) {
              marker.on("click", function(e) {

                if (scope.activeUserPopup) {
                  scope.activeUserPopup.closePopup();
                }
                scope.activeLocation = undefined;
                scope.locationTableClick = undefined;

                // TODO, tmp for PDC, only have layerId so I cannot check if external layer
                // using style property to indicate an external layer
                activeMarker = marker;
                if (feature.properties.style) {
                  scope.$apply(function(s) {
                    scope.externalFeature = {layerId: layer.id, featureId: feature.id, feature: feature};
                  });
                  marker.bindPopup(L.popup().setContent(feature.properties.description));
                  // marker.bindPopup(L.popup());
                } else {
                  scope.$apply(function(s) {
                    var oldBucket = scope.selectedBucket;
                    scope.selectedBucket = TimeBucketService.findItemBucketIdx(feature, 'newsfeed', function(item) {
                      return item.properties ? item.properties.EVENTDATE : moment(item.locations[0].properties.timestamp).valueOf();
                    });
                    if (oldBucket == scope.selectedBucket) {
                      $('.news-items').animate({scrollTop: $('#'+feature.id).position().top},500);
                    } else {
                      // now we have to wait for the news feed to switch buckets then we can scroll
                      var tries = 0;
                      var runAnimate = function() {
                        var feedElement = $('#'+feature.id);
                        if (feedElement.length != 0) {
                          $('.news-items').animate({scrollTop: feedElement.position().top},500);
                          return;
                        }
                        tries++;
                        if (tries < 10) {
                          $timeout(runAnimate, 500);
                        }
                      };
                      $timeout(runAnimate, 500);
                    }
                    scope.activeFeature = {layerId: feature.layerId, featureId: feature.id, feature: feature};

                    //console.info('scroll top is ' + $('#'+feature.id).position().top);
                    //$('.news-items').scrollTop($('#'+feature.id).position().top);
                  });
                }
              });
            }
          }
        };

        scope.$watch('activeFeature', function(newFeature, oldFeature) {
          if (!newFeature && oldFeature) {
            var marker = markers[oldFeature.layerId][oldFeature.featureId];
            marker.unselect();
          } else if (newFeature) {
            var marker = markers[newFeature.layerId][newFeature.featureId];
            marker.select();
          }
        });

        scope.$watch('featureTableClick', function(o) {
          if (!o) return;
          var marker = markers[o.layerId][o.featureId];
          map.setView(marker.getLatLng(), map.getZoom() > 17 ? map.getZoom() : 17);
          layers[o.layerId].leafletLayer.zoomToShowLayer(marker, function(){});
        });

        scope.$watch('locationTableClick', function(location, oldLocation) {
          if (oldLocation) {
            currentLocationMarkers[oldLocation.user].closePopup();
          }
          if (!location) return;
          var marker = currentLocationMarkers[location.user];
          marker.openPopup();
          marker.fireEvent('click');
          map.setView(marker.getLatLng(), map.getZoom() > 17 ? map.getZoom() : 17);
        });

        scope.$watch("layer", function(layer) {
            if (!layer) return;

            if (layer.checked) {

              // add to map
              var newLayer = null;
              var gj = null;
              if (layer.type === 'Imagery') {
                if (layer.format == 'XYZ' || layer.format == 'TMS') {
                  newLayer = new L.TileLayer(layer.url, { tms: layer.format == 'TMS', maxZoom: 18});
                } else if (layer.format == 'WMS') {
                  var options = {
                    layers: layer.wms.layers,
                    version: layer.wms.version,
                    format: layer.wms.format,
                    transparent: layer.wms.transparent
                  };
                  if (layer.wms.styles) options.styles = layer.wms.styles;
                  newLayer = new L.TileLayer.WMS(layer.url, options);
                }
                newLayer.addTo(map).bringToFront();
              } else {
                if (!layer.features) {
                  return;
                }

              }

              layers[layer.id] = {
                leafletLayer: newLayer,
                layer: layer,
                gjLayer: gj
              };
            } else if (layers[layer.id]) {
              // remove from map
              map.removeLayer(layers[layer.id].leafletLayer);
              delete layers[layer.id];
            }
        }); // watch layer

        scope.$watch('layer.features', function(features) {
          if (!features) return;
          if (layers[scope.layer.id]) {
            var addThese = {
              features: []
            };
            for (var i = 0; i < features.features.length; i++) {
              var marker = markers[scope.layer.id][features.features[i].id];
              if (!marker) {
                addThese.features.push(features.features[i]);
              } else {
                marker.setIcon(IconService.leafletIcon(features.features[i], {types: scope.types}));
              }
            }
            newLayer = layers[scope.layer.id].leafletLayer;
            newLayer.addLayer(L.geoJson(addThese, featureConfig(layers[scope.layer.id].layer)));
          } else {
            markers[scope.layer.id] = {};
            var gj = L.geoJson(features, featureConfig(scope.layer));
            newLayer = L.markerClusterGroup()
            .addLayer(gj)
            .addTo(map)
            .bringToFront();
            layers[scope.layer.id] = {
                leafletLayer: newLayer,
                layer: scope.layer,
                gjLayer: gj
              };
          }
        });

        scope.$watch("newFeature", function(feature) {
          if (!feature) return;

          map.removeLayer(addMarker);
          var layer = layers[scope.currentLayerId];
          if (layer) {
            layer.leafletLayer.addLayer(L.geoJson(feature, featureConfig(layer.layer)));
          }
        }); // watch newFeature

        scope.$watch("updatedFeature", function(feature) {
          if (!feature) return;

          activeMarker.setIcon(IconService.leafletIcon(feature, {types: scope.types, levels: scope.levels}));
        });

        scope.$watch("externalFeature", function(value) {
          if (!value) return;

          //activeMarker.bindPopup(L.popup().setContent(value.feature.properties.description)).openPopup();
        });

        scope.$watch("deletedFeature", function(feature) {
          if (!feature) return;

          var layer = layers[feature.layerId].leafletLayer;
          if (layer) {
            layer.removeLayer(activeMarker);
          }
        })

      } // end of link function
    };
  });
}());<|endoftext|>


<commit_before>var config    = require('../../config');
var tools     = require('../../tools');
var Pipedrive = require('pipedrive');

var pipedrive = config.PIPEDRIVE_TOKEN ?
  new Pipedrive.Client(config.PIPEDRIVE_TOKEN, {strictMode: true}) : null;

module.exports = function(req, res) {

  var promises = [];

  var m = {
    to: [
      'brody@ionic.io', 'matt@ionic.io', 'swami@ionic.io', 'andrew@ionic.io'
      // 'perry@ionic.io'
    ],
    from: 'sales@ionic.io',
    name: 'Ionic Enterprise',
    subject: 'Ionic Enterprise Sub. Entry',
    body: objToString(req.body)
  };

  // send email
  promises.push(new Promise((resolve, reject) => {
    tools.email(m.to, m.from, m.name, m.subject, m.body).then(function() {
      res.locals.notification = 'Message Sent';
      res.locals.notificationClass = 'success';
      resolve();
    }, function(err) {
      res.locals.notification = 'Unable to send message at this time';
      res.locals.notificationClass = 'error';
      reject();
    });
  }));

  if (pipedrive) {
    var asigneeId = 2392390; // brody

    // create a PD object w/ promised methods so we can chain these cleanly
    pd = {
      addOrg: (org) => {
        console.log('adding org')
        return new Promise((resolve, reject) => {
          pipedrive.Organizations.add({
            name: org.name,
            owner_id: org.owner_id,
            visible_to: 3
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response);
          });
        });
      },
      addPerson: (person) => {
        console.log('adding org')
        return new Promise((resolve, reject) => {
          pipedrive.Persons.add({
            name: person.name,
            owner_id: person.owner_id, // brody
            email: [person.email],
            phone: [person.phone],
            org_id: person.org_id,
            visible_to: 3 // everyone
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      },
      addDeal: (deal) => {
        console.log('adding deal')
        return new Promise((resolve, reject) => {
          pipedrive.Deals.add({
            title: deal.title,
            user_id: deal.user_id, // brody
            person_id: deal.person_id,
            org_id: deal.org_id,
            '6205dc9bf717d81a22659121b0f4c5407dcb86eb': 'Website Enterprise Form',
            visible_to: 3
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      },
      addNote: (note) => {
        console.log('adding note')
        return new Promise((resolve, reject) => {
          pipedrive.Notes.add({
            content: note.content,
            deal_id: note.deal_id,
            person_id: note.person_id,
            org_id: note.org_id
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      }
    }

    // Make API Calls to Pipedrive
    promises.push(new Promise((resolve, reject) => {
      pd.addOrg({
        name: req.body.company,
        owner_id: asigneeId
      }).then((org) => pd.addPerson({
        name: req.body.first_name + ' ' + req.body.last_name,
        owner_id: asigneeId, // brody
        email: req.body.email,
        phone: req.body.phone,
        org_id: org.id
      })).then((person) => pd.addDeal({
        title: 'Enterprise Website Lead: ' + req.body.company,
        user_id: asigneeId, // brody
        person_id: person.id,
        org_id: person.org_id,
      })).then((deal) => pd.addNote({
        content: objToString(req.body).replace(/\n/g, ' | '),
        deal_id: deal.id,
        person_id: deal.person_id,
        org_id: deal.org_id
      })).then(resolve);
    }));

    promises.push(tools.saveEmail({
      email: req.body.email,
      first_name: req.body.first_name,
      last_name: req.body.last_name
    }).then((response)=>{
      return tools.addEmailToList({
        list_id: 1372369,
        user: response.body.persisted_recipients[0]
      })
    }));

    // relfect because we want to show the page even if one of the tasks error
    Promise.all(promises.map(reflect)).then(values => {
      res.render('enterprise/index');
    });
  }
}

function reflect(promise) {
  return promise.then(function(v) { return {v: v, status: 'resolved'};},
                      function(e) { return {e: e, status: 'rejected'};});
}

function objToString(obj) {
  var str = '';
  for (var p in obj) {
    if (obj.hasOwnProperty(p)) {
      str += cap(p) + ' :: ' + obj[p] + '\n\r';
    }
  }
  return str;
};

function cap(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
};
<commit_msg>welcome joe!<commit_after>var config    = require('../../config');
var tools     = require('../../tools');
var Pipedrive = require('pipedrive');

var pipedrive = config.PIPEDRIVE_TOKEN ?
  new Pipedrive.Client(config.PIPEDRIVE_TOKEN, {strictMode: true}) : null;

module.exports = function(req, res) {

  var promises = [];

  var m = {
    to: [
      'brody@ionic.io', 'joe@ionic.io', 'matt@ionic.io', 'swami@ionic.io', 'andrew@ionic.io'
      // 'perry@ionic.io'
    ],
    from: 'sales@ionic.io',
    name: 'Ionic Enterprise',
    subject: 'Ionic Enterprise Sub. Entry',
    body: objToString(req.body)
  };

  // send email
  promises.push(new Promise((resolve, reject) => {
    tools.email(m.to, m.from, m.name, m.subject, m.body).then(function() {
      res.locals.notification = 'Message Sent';
      res.locals.notificationClass = 'success';
      resolve();
    }, function(err) {
      res.locals.notification = 'Unable to send message at this time';
      res.locals.notificationClass = 'error';
      reject();
    });
  }));

  if (pipedrive) {
    var asigneeId = 2392390; // brody

    // create a PD object w/ promised methods so we can chain these cleanly
    pd = {
      addOrg: (org) => {
        console.log('adding org')
        return new Promise((resolve, reject) => {
          pipedrive.Organizations.add({
            name: org.name,
            owner_id: org.owner_id,
            visible_to: 3
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response);
          });
        });
      },
      addPerson: (person) => {
        console.log('adding org')
        return new Promise((resolve, reject) => {
          pipedrive.Persons.add({
            name: person.name,
            owner_id: person.owner_id, // brody
            email: [person.email],
            phone: [person.phone],
            org_id: person.org_id,
            visible_to: 3 // everyone
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      },
      addDeal: (deal) => {
        console.log('adding deal')
        return new Promise((resolve, reject) => {
          pipedrive.Deals.add({
            title: deal.title,
            user_id: deal.user_id, // brody
            person_id: deal.person_id,
            org_id: deal.org_id,
            '6205dc9bf717d81a22659121b0f4c5407dcb86eb': 'Website Enterprise Form',
            visible_to: 3
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      },
      addNote: (note) => {
        console.log('adding note')
        return new Promise((resolve, reject) => {
          pipedrive.Notes.add({
            content: note.content,
            deal_id: note.deal_id,
            person_id: note.person_id,
            org_id: note.org_id
          }, (err, response) => {
	          if (err) {
              reject(err);
              return console.error(err);
            }
            // console.log(response);
	          resolve(response)
          })
        })
      }
    }

    // Make API Calls to Pipedrive
    promises.push(new Promise((resolve, reject) => {
      pd.addOrg({
        name: req.body.company,
        owner_id: asigneeId
      }).then((org) => pd.addPerson({
        name: req.body.first_name + ' ' + req.body.last_name,
        owner_id: asigneeId, // brody
        email: req.body.email,
        phone: req.body.phone,
        org_id: org.id
      })).then((person) => pd.addDeal({
        title: 'Enterprise Website Lead: ' + req.body.company,
        user_id: asigneeId, // brody
        person_id: person.id,
        org_id: person.org_id,
      })).then((deal) => pd.addNote({
        content: objToString(req.body).replace(/\n/g, ' | '),
        deal_id: deal.id,
        person_id: deal.person_id,
        org_id: deal.org_id
      })).then(resolve);
    }));

    promises.push(tools.saveEmail({
      email: req.body.email,
      first_name: req.body.first_name,
      last_name: req.body.last_name
    }).then((response)=>{
      return tools.addEmailToList({
        list_id: 1372369,
        user: response.body.persisted_recipients[0]
      })
    }));

    // relfect because we want to show the page even if one of the tasks error
    Promise.all(promises.map(reflect)).then(values => {
      res.render('enterprise/index');
    });
  }
}

function reflect(promise) {
  return promise.then(function(v) { return {v: v, status: 'resolved'};},
                      function(e) { return {e: e, status: 'rejected'};});
}

function objToString(obj) {
  var str = '';
  for (var p in obj) {
    if (obj.hasOwnProperty(p)) {
      str += cap(p) + ' :: ' + obj[p] + '\n\r';
    }
  }
  return str;
};

function cap(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
};
<|endoftext|>


<commit_before>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Pretokenise code before it uploads
 ------------------------------------------------------------------
**/
"use strict";
(function(){
  function init() {
    Espruino.Core.Config.add("PRETOKENISE", {
      section : "Minification",
      name : "Pretokenise code before upload (BETA)",
      description : "All whitespace and comments are removed and all reserved words are converted to tokens before upload. This means a faster upload, less memory used, and increased performance (+10%) at the expense of code readability.",
      type : "boolean",
      defaultValue : false
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      if (!Espruino.Config.PRETOKENISE) return callback(code);
      pretokenise(code, callback);
    });
   // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformModuleForEspruino", function(module, callback) {
      if (!Espruino.Config.PRETOKENISE) return callback(module);
      pretokenise(module.code, function(code) {
        module.code = code;
        callback(module);
      });
    });
  }

  var LEX_OPERATOR_START = 138;
  var TOKENS =  [// plundered from jslex.c
/* LEX_EQUAL      :   */ "==",
/* LEX_TYPEEQUAL  :   */ "===",
/* LEX_NEQUAL     :   */ "!=",
/* LEX_NTYPEEQUAL :   */ "!==",
/* LEX_LEQUAL    :    */ "<=",
/* LEX_LSHIFT     :   */ "<<",
/* LEX_LSHIFTEQUAL :  */ "<<=",
/* LEX_GEQUAL      :  */ ">=",
/* LEX_RSHIFT      :  */ ">>",
/* LEX_RSHIFTUNSIGNED */ ">>>",
/* LEX_RSHIFTEQUAL :  */ ">>=",
/* LEX_RSHIFTUNSIGNEDEQUAL */ ">>>=",
/* LEX_PLUSEQUAL   :  */ "+=",
/* LEX_MINUSEQUAL  :  */ "-=",
/* LEX_PLUSPLUS :     */ "++",
/* LEX_MINUSMINUS     */ "--",
/* LEX_MULEQUAL :     */ "*=",
/* LEX_DIVEQUAL :     */ "/=",
/* LEX_MODEQUAL :     */ "%=",
/* LEX_ANDEQUAL :     */ "&=",
/* LEX_ANDAND :       */ "&&",
/* LEX_OREQUAL :      */ "|=",
/* LEX_OROR :         */ "||",
/* LEX_XOREQUAL :     */ "^=",
/* LEX_ARROW_FUNCTION */ "=>",
// reserved words
/*LEX_R_IF :       */ "if",
/*LEX_R_ELSE :     */ "else",
/*LEX_R_DO :       */ "do",
/*LEX_R_WHILE :    */ "while",
/*LEX_R_FOR :      */ "for",
/*LEX_R_BREAK :    */ "break",
/*LEX_R_CONTINUE   */ "continue",
/*LEX_R_FUNCTION   */ "function",
/*LEX_R_RETURN     */ "return",
/*LEX_R_VAR :      */ "var",
/*LEX_R_LET :      */ "let",
/*LEX_R_CONST :    */ "const",
/*LEX_R_THIS :     */ "this",
/*LEX_R_THROW :    */ "throw",
/*LEX_R_TRY :      */ "try",
/*LEX_R_CATCH :    */ "catch",
/*LEX_R_FINALLY :  */ "finally",
/*LEX_R_TRUE :     */ "true",
/*LEX_R_FALSE :    */ "false",
/*LEX_R_NULL :     */ "null",
/*LEX_R_UNDEFINED  */ "undefined",
/*LEX_R_NEW :      */ "new",
/*LEX_R_IN :       */ "in",
/*LEX_R_INSTANCEOF */ "instanceof",
/*LEX_R_SWITCH     */ "switch",
/*LEX_R_CASE       */ "case",
/*LEX_R_DEFAULT    */ "default",
/*LEX_R_DELETE     */ "delete",
/*LEX_R_TYPEOF :   */ "typeof",
/*LEX_R_VOID :     */ "void",
/*LEX_R_DEBUGGER : */ "debugger",
/*LEX_R_CLASS :    */ "class",
/*LEX_R_EXTENDS :  */ "extends",
/*LEX_R_SUPER :  */   "super",
/*LEX_R_STATIC :   */ "static",
/*LEX_R_OF    :   */  "of"
];

  function pretokenise(code, callback) {
    var lex = Espruino.Core.Utils.getLexer(code);
    var brackets = 0;
    var resultCode = "";
    var lastIdx = 0;
    var lastTok = {str:""};
    var tok = lex.next();
    while (tok!==undefined) {
      var previousString = code.substring(lastIdx, tok.startIdx);
      var tokenString = code.substring(tok.startIdx, tok.endIdx);
      var tokenId = LEX_OPERATOR_START + TOKENS.indexOf(tokenString);
      if (tokenId<LEX_OPERATOR_START) tokenId=undefined;
      //console.log("prev "+JSON.stringify(previousString)+"   next "+tokenString);

      if (tok.str=="(" || tok.str=="{" || tok.str=="[") brackets++;
      if (tok.str==")" || tok.str=="}" || tok.str=="]") brackets--;

      // TODO: check for eg. two IDs/similar which can't be merged without a space
      // preserve newlines at root scope to avoid us filling up the command buffer all at once
      if (brackets==0 && previousString.indexOf("\n")>=0)
        resultCode += "\n";
      // if we have a token for something, use that - else use the string
      if (tokenId) {
        //console.log(JSON.stringify(tok.str)+" => "+tokenId);
        resultCode += String.fromCharCode(tokenId);
      } else
        resultCode += tokenString;
      // next
      lastIdx = tok.endIdx;
      lastTok = tok;
      tok = lex.next();
    }
    callback(resultCode);
  }

  Espruino.Plugins.Pretokenise = {
    init : init,
  };
}());
<commit_msg>Fix misc. pretokeniser issues<commit_after>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Pretokenise code before it uploads
 ------------------------------------------------------------------
**/
"use strict";
(function(){
  function init() {
    Espruino.Core.Config.add("PRETOKENISE", {
      section : "Minification",
      name : "Pretokenise code before upload (BETA)",
      description : "All whitespace and comments are removed and all reserved words are converted to tokens before upload. This means a faster upload, less memory used, and increased performance (+10%) at the expense of code readability.",
      type : "boolean",
      defaultValue : false
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      if (!Espruino.Config.PRETOKENISE) return callback(code);
      pretokenise(code, callback);
    });
   // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformModuleForEspruino", function(module, callback) {
      if (!Espruino.Config.PRETOKENISE) return callback(module);
      pretokenise(module.code, function(code) {
        module.code = code;
        callback(module);
      });
    });
  }

  var LEX_OPERATOR_START = 138;
  var TOKENS =  [// plundered from jslex.c
/* LEX_EQUAL      :   */ "==",
/* LEX_TYPEEQUAL  :   */ "===",
/* LEX_NEQUAL     :   */ "!=",
/* LEX_NTYPEEQUAL :   */ "!==",
/* LEX_LEQUAL    :    */ "<=",
/* LEX_LSHIFT     :   */ "<<",
/* LEX_LSHIFTEQUAL :  */ "<<=",
/* LEX_GEQUAL      :  */ ">=",
/* LEX_RSHIFT      :  */ ">>",
/* LEX_RSHIFTUNSIGNED */ ">>>",
/* LEX_RSHIFTEQUAL :  */ ">>=",
/* LEX_RSHIFTUNSIGNEDEQUAL */ ">>>=",
/* LEX_PLUSEQUAL   :  */ "+=",
/* LEX_MINUSEQUAL  :  */ "-=",
/* LEX_PLUSPLUS :     */ "++",
/* LEX_MINUSMINUS     */ "--",
/* LEX_MULEQUAL :     */ "*=",
/* LEX_DIVEQUAL :     */ "/=",
/* LEX_MODEQUAL :     */ "%=",
/* LEX_ANDEQUAL :     */ "&=",
/* LEX_ANDAND :       */ "&&",
/* LEX_OREQUAL :      */ "|=",
/* LEX_OROR :         */ "||",
/* LEX_XOREQUAL :     */ "^=",
/* LEX_ARROW_FUNCTION */ "=>",
// reserved words
/*LEX_R_IF :       */ "if",
/*LEX_R_ELSE :     */ "else",
/*LEX_R_DO :       */ "do",
/*LEX_R_WHILE :    */ "while",
/*LEX_R_FOR :      */ "for",
/*LEX_R_BREAK :    */ "break",
/*LEX_R_CONTINUE   */ "continue",
/*LEX_R_FUNCTION   */ "function",
/*LEX_R_RETURN     */ "return",
/*LEX_R_VAR :      */ "var",
/*LEX_R_LET :      */ "let",
/*LEX_R_CONST :    */ "const",
/*LEX_R_THIS :     */ "this",
/*LEX_R_THROW :    */ "throw",
/*LEX_R_TRY :      */ "try",
/*LEX_R_CATCH :    */ "catch",
/*LEX_R_FINALLY :  */ "finally",
/*LEX_R_TRUE :     */ "true",
/*LEX_R_FALSE :    */ "false",
/*LEX_R_NULL :     */ "null",
/*LEX_R_UNDEFINED  */ "undefined",
/*LEX_R_NEW :      */ "new",
/*LEX_R_IN :       */ "in",
/*LEX_R_INSTANCEOF */ "instanceof",
/*LEX_R_SWITCH     */ "switch",
/*LEX_R_CASE       */ "case",
/*LEX_R_DEFAULT    */ "default",
/*LEX_R_DELETE     */ "delete",
/*LEX_R_TYPEOF :   */ "typeof",
/*LEX_R_VOID :     */ "void",
/*LEX_R_DEBUGGER : */ "debugger",
/*LEX_R_CLASS :    */ "class",
/*LEX_R_EXTENDS :  */ "extends",
/*LEX_R_SUPER :  */   "super",
/*LEX_R_STATIC :   */ "static",
/*LEX_R_OF    :   */  "of"
];

  function pretokenise(code, callback) {
    var lex = Espruino.Core.Utils.getLexer(code);
    var brackets = 0;
    var resultCode = "";
    var lastIdx = 0;
    var lastTok = {str:""};
    var tok = lex.next();
    while (tok!==undefined) {
      var previousString = code.substring(lastIdx, tok.startIdx);
      var tokenString = code.substring(tok.startIdx, tok.endIdx);
      var tokenId = LEX_OPERATOR_START + TOKENS.indexOf(tokenString);
      if (tokenId<LEX_OPERATOR_START) tokenId=undefined;
      //console.log("prev "+JSON.stringify(previousString)+"   next "+tokenString);

      if (tok.str=="(" || tok.str=="{" || tok.str=="[") brackets++;
      // TODO: check for eg. two IDs/similar which can't be merged without a space
      // preserve newlines at root scope to avoid us filling up the command buffer all at once
      if (brackets==0 && previousString.indexOf("\n")>=0)
        resultCode += "\n";
      if (tok.str==")" || tok.str=="}" || tok.str=="]") brackets--;
      // if we have a token for something, use that - else use the string
      if (tokenId) {
        //console.log(JSON.stringify(tok.str)+" => "+tokenId);
        resultCode += String.fromCharCode(tokenId);
        tok.type = "TOKENISED";
      } else {
        if ((tok.type=="ID" || tok.type=="NUMBER") &&
            (lastTok.type=="ID" || lastTok.type=="NUMBER"))
          resultCode += " ";
        resultCode += tokenString;
      }
      // next
      lastIdx = tok.endIdx;
      lastTok = tok;
      tok = lex.next();
    }
    callback(resultCode);
  }

  Espruino.Plugins.Pretokenise = {
    init : init,
  };
}());
<|endoftext|>


<commit_before>String.prototype.repeat = function(i) { // Some browsers don't support repeat, for example, Safari
    return new Array(i + 1).join(this);
}

function prompt_for_a_value(key, action) {
  $(document).on('opened', '#' + key + '-modal', function() {
    $('#' + key + '-code').focus();
  });
  $('#' + key + '-code').keyup(function(e) {
   if(e.which == 13) { // press enter to confirm
      $('#' + key + '-confirm').click();
    }
  });
  $(document).on('confirm', '#' + key + '-modal', function() {
    var value = $('#' + key + '-code').val().trim();
    if(value.length > 0) {
      action(value);
      $('#' + key + '-code').val('');
    }
  });
}
// modals
$(document).on('close', '.remodal', function(e) {
  editor.focus();
});

// function get_editor_scroll() { // 获取编辑器的滚动位置
//   var line_markers = $('.ui-layout-east article > [data-line]');
//   var lines = []; // 逻辑行
//   line_markers.each(function() {
//     lines.push($(this).data('line'));
//   });
//   var pLines = []; // 物理行
//   var pLine = 0;
//   for(var i = 0; i < lines[lines.length - 1]; i++) {
//     if($.inArray(i + 1, lines) !== -1) {
//       pLines.push(pLine);
//     }
//     pLine += editor.session.getRowLength(i) // 因为有wrap，所以行高未必是1
//   }
//   var currentLine = editor.session.getScrollTop() / editor.renderer.lineHeight; // 当前滚动到的物理行
//   var lastMarker = false;
//   var nextMarker = false;
//   for(var i = 0; i < pLines.length; i++) {
//     if(pLines[i] < currentLine) {
//       lastMarker = i;
//     } else {
//       nextMarker = i;
//       break;
//     }
//   } // 当前滚动到了哪两个marker中间
//   var lastLine = 0;
//   var nextLine = editor.session.getScreenLength() - 1; // 最后一个物理行的顶部，所以 -1
//   if(lastMarker !== false) {
//     lastLine = pLines[lastMarker];
//   }
//   if(nextMarker !== false) {
//     nextLine = pLines[nextMarker];
//   } // 前后两个marker的物理行
//   var percentage = 0;
//   if(nextLine !== lastLine) { // 行首的情况下可能相等，0 不能作为除数
//     percentage = (currentLine - lastLine) / (nextLine - lastLine);
//   } // 当前位置在两个marker之间所处的百分比
//   return { lastMarker: lines[lastMarker], nextMarker: lines[nextMarker], percentage: percentage }; // 返回的是前后两个marker对应的逻辑行，以及当前位置在前后两个marker之间所处的百分比
// }
//
// function set_preview_scroll(editor_scroll) { // 设置预览的滚动位置
//   var lastPosition = 0;
//   var nextPosition = $('.ui-layout-east article').outerHeight() - $('.ui-layout-east').height(); // 这是总共可以scroll的最大幅度
//   if(editor_scroll.lastMarker !== undefined) { // 最开始的位置没有marker
//     lastPosition = $('.ui-layout-east article').find('>[data-line="' + editor_scroll.lastMarker + '"]').get(0).offsetTop;
//   }
//   if(editor_scroll.nextMarker !== undefined) { // 最末尾的位置没有marker
//     nextPosition = $('.ui-layout-east article').find('>[data-line="' + editor_scroll.nextMarker + '"]').get(0).offsetTop;
//   } // 查找出前后两个marker在页面上所处的滚动距离
//   scrollPosition = lastPosition + (nextPosition - lastPosition) * editor_scroll.percentage; // 按照左侧的百分比计算出右侧应该滚动到的位置
//   $('.ui-layout-east').animate({scrollTop: scrollPosition}, 16); // 加一点动画效果
// }
//
// var sync_preview = _.debounce(function() { // 右侧预览和左侧的内容同步
//   set_preview_scroll(get_editor_scroll());
// }, 8, false);

var lazy_change = _.debounce(function() { // 用户停止输入128毫秒之后才会触发
  mdc.init(editor.session.getValue(), false); // realtime preview
  // sync_preview();
}, 128, false);

var Vim = ace.require("ace/keyboard/vim").CodeMirror.Vim // vim commands
Vim.defineEx("write", "w", function(cm, input) {
  console.log('write');
});
Vim.defineEx("quit", "q", function(cm, input) {
  if(input.input === 'q') {
    console.log('quit');
  } else if(input.input === 'q!') {
    console.log('quit without warning');
  }
});
Vim.defineEx("wq", "wq", function(cm, input) {
  console.log('write then quit');
});

var editor;
$(function() {
  $('body').layout({ // create 3-panels layout
    resizerDblClickToggle: false,
    resizable: false,
    slidable: false,
    togglerLength_open: '100%',
    togglerLength_closed: '100%',
    north: {
      size: 'auto',
      togglerTip_open: $('#toolbar').data('open-title'),
      togglerTip_closed: $('#toolbar').data('closed-title')
    },
    east: {
      size: '50%',
      togglerTip_open: $('#preview').data('open-title'),
      togglerTip_closed: $('#preview').data('closed-title'),
      onresize: function() {
        $('.markdown-body').css('padding-bottom', ($('.ui-layout-east').height() - parseInt($('.markdown-body').css('line-height')) + 1) + 'px'); // scroll past end
      }
    },
    center: {
      onresize: function() {
        editor.session.setUseWrapMode(false); // fix ACE editor text wrap issue
        editor.session.setUseWrapMode(true);
      }
    }
  });

  $('.markdown-body').css('padding-bottom', ($('.ui-layout-east').height() - parseInt($('.markdown-body').css('line-height')) + 1) + 'px'); // scroll past end

  // editor on the left
  editor = ace.edit("editor");
  editor.session.setUseWorker(false);
  editor.$blockScrolling = Infinity;
  editor.renderer.setShowPrintMargin(false);
  editor.session.setMode('ace/mode/markdown');
  editor.session.setUseWrapMode(true);
  editor.setScrollSpeed(1);
  editor.setOption("scrollPastEnd", true);
  editor.session.setFoldStyle('manual');
  editor.focus();
  editor.session.on('changeScrollTop', function(scroll) {
    // sync_preview();
  });

  // load preferences
  var key_binding = Cookies.get('key-binding');
  if(key_binding == undefined) {
    key_binding = 'default'
  }
  $('select#key-binding').val(key_binding);
  if(key_binding !== 'default') {
    editor.setKeyboardHandler(ace.require("ace/keyboard/" + key_binding).handler);
  }

  var font_size = Cookies.get('editor-font-size');
  if(font_size == undefined) {
    font_size = '14';
  }
  $('select#editor-font-size').val(font_size);
  editor.setFontSize(font_size + 'px');

  var editor_theme = Cookies.get('editor-theme');
  if(editor_theme == undefined) {
    editor_theme = 'tomorrow_night_eighties';
  }
  $('select#editor-theme').val(editor_theme);
  editor.setTheme('ace/theme/' + editor_theme);

  // change preferences
  $('select#key-binding').change(function() {
    var key_binding = $(this).val();
    Cookies.set('key-binding', key_binding, { expires: 10000 });
    if(key_binding == 'default') {
      editor.setKeyboardHandler(null);
    } else {
      editor.setKeyboardHandler(ace.require("ace/keyboard/" + key_binding).handler);
    }
  });

  $('select#editor-font-size').change(function() {
    var font_size = $(this).val();
    Cookies.set('editor-font-size', font_size, { expires: 10000 });
    editor.setFontSize(font_size + 'px');
  });

  $('select#editor-theme').change(function() {
    var editor_theme = $(this).val();
    Cookies.set('editor-theme', editor_theme, { expires: 10000 });
    editor.setTheme('ace/theme/' + editor_theme);
  });

  // extension methods for editor
  editor.selection.smartRange = function() {
    var range = editor.selection.getRange();
    if(!range.isEmpty()) {
      return range; // return what user selected
    }
    // nothing was selected
    var _range = range; // backup original range
    range = editor.selection.getWordRange(range.start.row, range.start.column); // range for current word
    if(editor.session.getTextRange(range).trim().length == 0) { // selected is blank
      range = _range; // restore original range
    }
    return range;
  };

  // overwrite some ACE editor keyboard shortcuts
  editor.commands.addCommands([
    {
      name: "preferences",
      bindKey: { win: "Ctrl-,", mac: "Command-," },
      exec: function (editor) {
        $('i.fa-cog').click(); // show M+ preferences modal
      }
    }
  ]);

  // whenever user changes markdown...
  editor.session.on('change', function() {
    lazy_change();
  });

  // h1 - h6 heading
  $('.heading-icon').click(function() {
    var level = $(this).data('level');
    var p = editor.getCursorPosition();
    p.column += level + 1; // 光标位置会产生偏移
    editor.navigateTo(editor.getSelectionRange().start.row, 0); // navigateLineStart 在 wrap 的时候有问题
    editor.insert('#'.repeat(level) + ' ');
    editor.moveCursorToPosition(p); // restore cursor position
    editor.focus();
  });

  // styling icons
  $('.styling-icon').click(function() {
    var modifier = $(this).data('modifier');
    var range = editor.selection.smartRange();
    var p = editor.getCursorPosition();
    p.column += modifier.length; // 光标位置会产生偏移
    editor.session.replace(range, modifier + editor.session.getTextRange(range) + modifier);
    editor.moveCursorToPosition(p); // restore cursor position
    editor.selection.clearSelection(); // 不知为何上一个语句会选中一部分文字
    editor.focus();
  });

  //

  $('#horizontal-rule').click(function() {
    var p = editor.getCursorPosition();
    if(p.column == 0) { // cursor is at line start
      editor.selection.clearSelection();
      editor.insert('\n---\n');
    } else {
      editor.navigateTo(editor.getSelectionRange().start.row, Number.MAX_VALUE); // navigateLineEnd 在 wrap 的时候有问题
      editor.insert('\n\n---\n');
    }
    editor.focus();
  });

  // list icons
  $('.list-icon').click(function() {
    var prefix = $(this).data('prefix');
    var p = editor.getCursorPosition();
    p.column += prefix.length; // 光标位置会产生偏移
    var range = editor.selection.getRange();
    for(var i = range.start.row + 1; i < range.end.row + 2; i++) {
      editor.gotoLine(i);
      editor.insert(prefix);
    }
    editor.moveCursorToPosition(p); // restore cursor position
    editor.focus();
  });

  $('#link-icon').click(function() {
    var range = editor.selection.smartRange();
    var text = editor.session.getTextRange(range);
    if(text.trim().length == 0) {
      text = $(this).data('sample-text');
    }
    var url = $(this).data('sample-url');
    editor.session.replace(range, '[' + text + '](' + url + ')');
    editor.focus();
  });

  $('#image-icon').click(function() {
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample-text');
    }
    var url = $(this).data('sample-url')
    editor.insert('![' + text + '](' + url + ')');
    editor.focus();
  });

  $('#code-icon').click(function() {
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    editor.insert('\n```\n' + text + '\n```\n');
    editor.focus();
    editor.navigateUp(2);
    editor.navigateLineEnd();
  });

  $('#table-icon').click(function() {
    var sample = $(this).data('sample');
    editor.insert(''); // delete selected
    var p = editor.getCursorPosition();
    if(p.column == 0) { // cursor is at line start
      editor.selection.clearSelection();
      editor.insert('\n' + sample + '\n\n');
    } else {
      editor.navigateTo(editor.getSelectionRange().start.row, Number.MAX_VALUE);
      editor.insert('\n\n' + sample + '\n');
    }
    editor.focus();
  });

  // emoji icon
  prompt_for_a_value('emoji', function(value){
    if(/^:.+:$/.test(value)) {
      value = /^:(.+):$/.exec(value)[1];
    }
    editor.insert('');
  });

  // Font Awesome icon
  prompt_for_a_value('fa', function(value){
    if(value.substring(0, 3) == 'fa-') {
      value = value.substring(3);
    }
    editor.insert('');
  });

  // Ionicons icon
  prompt_for_a_value('ion', function(value){
    if(value.substring(0, 4) == 'ion-') {
      value = value.substring(4);
    }
    editor.insert('');
  });

  $('#math-icon').click(function(){
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample');;
    }
    editor.insert('\n```math\n' + text + '\n```\n');
    editor.focus();
  });

  $('.mermaid-icon').click(function(){
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample');
    }
    editor.insert('\n```\n' + text + '\n```\n');
    editor.focus();
  });
});
<commit_msg>Enable sync_preview<commit_after>String.prototype.repeat = function(i) { // Some browsers don't support repeat, for example, Safari
    return new Array(i + 1).join(this);
}

function prompt_for_a_value(key, action) {
  $(document).on('opened', '#' + key + '-modal', function() {
    $('#' + key + '-code').focus();
  });
  $('#' + key + '-code').keyup(function(e) {
   if(e.which == 13) { // press enter to confirm
      $('#' + key + '-confirm').click();
    }
  });
  $(document).on('confirm', '#' + key + '-modal', function() {
    var value = $('#' + key + '-code').val().trim();
    if(value.length > 0) {
      action(value);
      $('#' + key + '-code').val('');
    }
  });
}
// modals
$(document).on('close', '.remodal', function(e) {
  editor.focus();
});

function get_editor_scroll() { // 获取编辑器的滚动位置
  var line_markers = $('.ui-layout-east article > [data-source-line]');
  var lines = []; // 逻辑行
  line_markers.each(function() {
    lines.push($(this).data('source-line'));
  });
  var pLines = []; // 物理行
  var pLine = 0;
  for(var i = 0; i < lines[lines.length - 1]; i++) {
    if($.inArray(i + 1, lines) !== -1) {
      pLines.push(pLine);
    }
    pLine += editor.session.getRowLength(i) // 因为有wrap，所以行高未必是1
  }
  var currentLine = editor.session.getScrollTop() / editor.renderer.lineHeight; // 当前滚动到的物理行
  var lastMarker = false;
  var nextMarker = false;
  for(var i = 0; i < pLines.length; i++) {
    if(pLines[i] < currentLine) {
      lastMarker = i;
    } else {
      nextMarker = i;
      break;
    }
  } // 当前滚动到了哪两个marker中间
  var lastLine = 0;
  var nextLine = editor.session.getScreenLength() - 1; // 最后一个物理行的顶部，所以 -1
  if(lastMarker !== false) {
    lastLine = pLines[lastMarker];
  }
  if(nextMarker !== false) {
    nextLine = pLines[nextMarker];
  } // 前后两个marker的物理行
  var percentage = 0;
  if(nextLine !== lastLine) { // 行首的情况下可能相等，0 不能作为除数
    percentage = (currentLine - lastLine) / (nextLine - lastLine);
  } // 当前位置在两个marker之间所处的百分比
  // 返回的是前后两个marker对应的逻辑行，以及当前位置在前后两个marker之间所处的百分比
  return { lastMarker: lines[lastMarker], nextMarker: lines[nextMarker], percentage: percentage };
}

function set_preview_scroll(editor_scroll) { // 设置预览的滚动位置
  var lastPosition = 0;
  var nextPosition = $('.ui-layout-east article').outerHeight() - $('.ui-layout-east').height(); // 这是总共可以scroll的最大幅度
  if(editor_scroll.lastMarker !== undefined) { // 最开始的位置没有marker
    lastPosition = $('.ui-layout-east article').find('>[data-source-line="' + editor_scroll.lastMarker + '"]').get(0).offsetTop;
  }
  if(editor_scroll.nextMarker !== undefined) { // 最末尾的位置没有marker
    nextPosition = $('.ui-layout-east article').find('>[data-source-line="' + editor_scroll.nextMarker + '"]').get(0).offsetTop;
  } // 查找出前后两个marker在页面上所处的滚动距离
  scrollPosition = lastPosition + (nextPosition - lastPosition) * editor_scroll.percentage; // 按照左侧的百分比计算出右侧应该滚动到的位置
  $('.ui-layout-east').animate({scrollTop: scrollPosition}, 16); // 加一点动画效果
}

var sync_preview = _.debounce(function() { // 右侧预览和左侧的内容同步
  set_preview_scroll(get_editor_scroll());
}, 64, false);

var lazy_change = _.debounce(function() { // 用户停止输入128毫秒之后才会触发
  mdc.init(editor.session.getValue(), false); // realtime preview
  sync_preview();
}, 256, false);

var Vim = ace.require("ace/keyboard/vim").CodeMirror.Vim // vim commands
Vim.defineEx("write", "w", function(cm, input) {
  console.log('write');
});
Vim.defineEx("quit", "q", function(cm, input) {
  if(input.input === 'q') {
    console.log('quit');
  } else if(input.input === 'q!') {
    console.log('quit without warning');
  }
});
Vim.defineEx("wq", "wq", function(cm, input) {
  console.log('write then quit');
});

var editor;
$(function() {
  $('body').layout({ // create 3-panels layout
    resizerDblClickToggle: false,
    resizable: false,
    slidable: false,
    togglerLength_open: '100%',
    togglerLength_closed: '100%',
    north: {
      size: 'auto',
      togglerTip_open: $('#toolbar').data('open-title'),
      togglerTip_closed: $('#toolbar').data('closed-title')
    },
    east: {
      size: '50%',
      togglerTip_open: $('#preview').data('open-title'),
      togglerTip_closed: $('#preview').data('closed-title'),
      onresize: function() {
        $('.markdown-body').css('padding-bottom', ($('.ui-layout-east').height() - parseInt($('.markdown-body').css('line-height')) + 1) + 'px'); // scroll past end
      }
    },
    center: {
      onresize: function() {
        editor.session.setUseWrapMode(false); // fix ACE editor text wrap issue
        editor.session.setUseWrapMode(true);
      }
    }
  });

  $('.markdown-body').css('padding-bottom', ($('.ui-layout-east').height() - parseInt($('.markdown-body').css('line-height')) + 1) + 'px'); // scroll past end

  // editor on the left
  editor = ace.edit("editor");
  editor.session.setUseWorker(false);
  editor.$blockScrolling = Infinity;
  editor.renderer.setShowPrintMargin(false);
  editor.session.setMode('ace/mode/markdown');
  editor.session.setUseWrapMode(true);
  editor.setScrollSpeed(1);
  editor.setOption("scrollPastEnd", true);
  editor.session.setFoldStyle('manual');
  editor.focus();
  editor.session.on('changeScrollTop', function(scroll) {
    sync_preview();
  });

  // load preferences
  var key_binding = Cookies.get('key-binding');
  if(key_binding == undefined) {
    key_binding = 'default'
  }
  $('select#key-binding').val(key_binding);
  if(key_binding !== 'default') {
    editor.setKeyboardHandler(ace.require("ace/keyboard/" + key_binding).handler);
  }

  var font_size = Cookies.get('editor-font-size');
  if(font_size == undefined) {
    font_size = '14';
  }
  $('select#editor-font-size').val(font_size);
  editor.setFontSize(font_size + 'px');

  var editor_theme = Cookies.get('editor-theme');
  if(editor_theme == undefined) {
    editor_theme = 'tomorrow_night_eighties';
  }
  $('select#editor-theme').val(editor_theme);
  editor.setTheme('ace/theme/' + editor_theme);

  // change preferences
  $('select#key-binding').change(function() {
    var key_binding = $(this).val();
    Cookies.set('key-binding', key_binding, { expires: 10000 });
    if(key_binding == 'default') {
      editor.setKeyboardHandler(null);
    } else {
      editor.setKeyboardHandler(ace.require("ace/keyboard/" + key_binding).handler);
    }
  });

  $('select#editor-font-size').change(function() {
    var font_size = $(this).val();
    Cookies.set('editor-font-size', font_size, { expires: 10000 });
    editor.setFontSize(font_size + 'px');
  });

  $('select#editor-theme').change(function() {
    var editor_theme = $(this).val();
    Cookies.set('editor-theme', editor_theme, { expires: 10000 });
    editor.setTheme('ace/theme/' + editor_theme);
  });

  // extension methods for editor
  editor.selection.smartRange = function() {
    var range = editor.selection.getRange();
    if(!range.isEmpty()) {
      return range; // return what user selected
    }
    // nothing was selected
    var _range = range; // backup original range
    range = editor.selection.getWordRange(range.start.row, range.start.column); // range for current word
    if(editor.session.getTextRange(range).trim().length == 0) { // selected is blank
      range = _range; // restore original range
    }
    return range;
  };

  // overwrite some ACE editor keyboard shortcuts
  editor.commands.addCommands([
    {
      name: "preferences",
      bindKey: { win: "Ctrl-,", mac: "Command-," },
      exec: function (editor) {
        $('i.fa-cog').click(); // show M+ preferences modal
      }
    }
  ]);

  // whenever user changes markdown...
  editor.session.on('change', function() {
    lazy_change();
  });

  // h1 - h6 heading
  $('.heading-icon').click(function() {
    var level = $(this).data('level');
    var p = editor.getCursorPosition();
    p.column += level + 1; // 光标位置会产生偏移
    editor.navigateTo(editor.getSelectionRange().start.row, 0); // navigateLineStart 在 wrap 的时候有问题
    editor.insert('#'.repeat(level) + ' ');
    editor.moveCursorToPosition(p); // restore cursor position
    editor.focus();
  });

  // styling icons
  $('.styling-icon').click(function() {
    var modifier = $(this).data('modifier');
    var range = editor.selection.smartRange();
    var p = editor.getCursorPosition();
    p.column += modifier.length; // 光标位置会产生偏移
    editor.session.replace(range, modifier + editor.session.getTextRange(range) + modifier);
    editor.moveCursorToPosition(p); // restore cursor position
    editor.selection.clearSelection(); // 不知为何上一个语句会选中一部分文字
    editor.focus();
  });

  //

  $('#horizontal-rule').click(function() {
    var p = editor.getCursorPosition();
    if(p.column == 0) { // cursor is at line start
      editor.selection.clearSelection();
      editor.insert('\n---\n');
    } else {
      editor.navigateTo(editor.getSelectionRange().start.row, Number.MAX_VALUE); // navigateLineEnd 在 wrap 的时候有问题
      editor.insert('\n\n---\n');
    }
    editor.focus();
  });

  // list icons
  $('.list-icon').click(function() {
    var prefix = $(this).data('prefix');
    var p = editor.getCursorPosition();
    p.column += prefix.length; // 光标位置会产生偏移
    var range = editor.selection.getRange();
    for(var i = range.start.row + 1; i < range.end.row + 2; i++) {
      editor.gotoLine(i);
      editor.insert(prefix);
    }
    editor.moveCursorToPosition(p); // restore cursor position
    editor.focus();
  });

  $('#link-icon').click(function() {
    var range = editor.selection.smartRange();
    var text = editor.session.getTextRange(range);
    if(text.trim().length == 0) {
      text = $(this).data('sample-text');
    }
    var url = $(this).data('sample-url');
    editor.session.replace(range, '[' + text + '](' + url + ')');
    editor.focus();
  });

  $('#image-icon').click(function() {
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample-text');
    }
    var url = $(this).data('sample-url')
    editor.insert('![' + text + '](' + url + ')');
    editor.focus();
  });

  $('#code-icon').click(function() {
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    editor.insert('\n```\n' + text + '\n```\n');
    editor.focus();
    editor.navigateUp(2);
    editor.navigateLineEnd();
  });

  $('#table-icon').click(function() {
    var sample = $(this).data('sample');
    editor.insert(''); // delete selected
    var p = editor.getCursorPosition();
    if(p.column == 0) { // cursor is at line start
      editor.selection.clearSelection();
      editor.insert('\n' + sample + '\n\n');
    } else {
      editor.navigateTo(editor.getSelectionRange().start.row, Number.MAX_VALUE);
      editor.insert('\n\n' + sample + '\n');
    }
    editor.focus();
  });

  // emoji icon
  prompt_for_a_value('emoji', function(value){
    if(/^:.+:$/.test(value)) {
      value = /^:(.+):$/.exec(value)[1];
    }
    editor.insert('');
  });

  // Font Awesome icon
  prompt_for_a_value('fa', function(value){
    if(value.substring(0, 3) == 'fa-') {
      value = value.substring(3);
    }
    editor.insert('');
  });

  // Ionicons icon
  prompt_for_a_value('ion', function(value){
    if(value.substring(0, 4) == 'ion-') {
      value = value.substring(4);
    }
    editor.insert('');
  });

  $('#math-icon').click(function(){
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample');;
    }
    editor.insert('\n```math\n' + text + '\n```\n');
    editor.focus();
  });

  $('.mermaid-icon').click(function(){
    var text = editor.session.getTextRange(editor.selection.getRange()).trim();
    if(text.length == 0) {
      text = $(this).data('sample');
    }
    editor.insert('\n```\n' + text + '\n```\n');
    editor.focus();
  });
});
<|endoftext|>


<commit_before>'use strict';

const gulp   = require('gulp');
const ms     = require('merge-stream');
const bower  = require('main-bower-files');
const config = require('../config.js');
const $      = require('../load.js');

/**
 * BowerパッケージのmainファイルをJS/CSSそれぞれ結合し出力する
 * CSSのurl(...)はdataURIに変換する
 */

gulp.task('bower', () => {

	const regexp_excludes = new RegExp(`(${config.bower.excludes.join('|')})$`, 'i');
	const js_files        = filterExcludes(bower().filter(value => /\.js$/.test(value)));
	const css_files       = filterExcludes(bower().filter(value => /\.css$/.test(value)));

	const js = gulp.src(js_files)
		.pipe($.concat(`${config.bower.output}.js`))
		.pipe($.if(config.build.bower_minify, $.uglify({ preserveComments : 'some' })))
		.pipe(gulp.dest(config.path.bower.dest));

	const css = gulp.src(css_files)
		.pipe($.cssBase64())
		.pipe($.concat(`${config.bower.output}.css`))
		.pipe($.if(config.build.bower_minify, $.csso()))
		.pipe(gulp.dest(config.path.bower.dest));

	return ms(js, css);

	function filterExcludes(files) {
		if (!config.bower.excludes.length) { return files; }
		return files.filter(value => !regexp_excludes.test(value));
	}
});
<commit_msg>[fix] BowerタスクでDataURI化するファイルの最大サイズを100MBに変更<commit_after>'use strict';

const gulp   = require('gulp');
const ms     = require('merge-stream');
const bower  = require('main-bower-files');
const config = require('../config.js');
const $      = require('../load.js');

/**
 * BowerパッケージのmainファイルをJS/CSSそれぞれ結合し出力する
 * CSSのurl(...)はdataURIに変換する
 */

gulp.task('bower', () => {

	const regexp_excludes = new RegExp(`(${config.bower.excludes.join('|')})$`, 'i');
	const js_files        = filterExcludes(bower().filter(value => /\.js$/.test(value)));
	const css_files       = filterExcludes(bower().filter(value => /\.css$/.test(value)));

	const js = gulp.src(js_files)
		.pipe($.concat(`${config.bower.output}.js`))
		.pipe($.if(config.build.bower_minify, $.uglify({ preserveComments : 'some' })))
		.pipe(gulp.dest(config.path.bower.dest));

	const css = gulp.src(css_files)
		.pipe($.cssBase64({
			maxWeightResource : 104857600
		}))
		.pipe($.concat(`${config.bower.output}.css`))
		.pipe($.if(config.build.bower_minify, $.csso()))
		.pipe(gulp.dest(config.path.bower.dest));

	return ms(js, css);

	function filterExcludes(files) {
		if (!config.bower.excludes.length) { return files; }
		return files.filter(value => !regexp_excludes.test(value));
	}
});
<|endoftext|>


<commit_before>import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import user from './user';
import userWords from './userWords';

const reducer = combineReducers({ user, userWords });
const middleware = [thunkMiddleware, createLogger({collapsed: true})]

// SETUP w/ REDUX DevTools

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(...middleware)));

// SETUP w/o REDUX DevTools
// const store = createStore(reducer, applyMiddleware(...middleware));

export default store;
export * from './user';
export * from './userWords';
<commit_msg>got rid of linting errors<commit_after>import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import user from './user';
import userWords from './userWords';

const reducer = combineReducers({ user, userWords });
const middleware = [thunkMiddleware, createLogger({ collapsed: true })];

// SETUP w/ REDUX DevTools

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(...middleware)));

// SETUP w/o REDUX DevTools
// const store = createStore(reducer, applyMiddleware(...middleware));

export default store;
export * from './user';
export * from './userWords';
<|endoftext|>


<commit_before>function Fft(elem, host, port, udpport, rearrange_halves, mean_window_size) {
    this._host = host;
    this._port = port;
    this._udpport = udpport;
    this._rearrange_halves = rearrange_halves;
    this._mean_window_size = mean_window_size;
    this._mean_window = [];
    this._elem = d3.select(elem);
    this._total_width = $(elem).width();
    this._total_height = $(elem).height();
    this._margin = {top: 20, right: 20, bottom: 30, left: 50};
    this._graph_width = this._total_width
        - this._margin.left - this._margin.right;
    this._graph_height = this._total_height
        - this._margin.top - this._margin.bottom;
    this._chart = this._elem.append("svg")
        .attr("width", this._total_width)
        .attr("height", this._total_height)
        .append("g")
        .attr("transform", "translate(" + this._margin.left + "," + this._margin.top + ")");
    this._current_fft_size = -1;
    this._sx = null;
    this._sy = d3.scale.linear()
        .domain([-128,127])
        .rangeRound([0, this._graph_height]);
    this._yaxis = d3.svg.axis()
        .scale(this._sy)
        .tickValues([])
        .tickFormat(function(d) { return (((d+128.0) / 256.0) * -100.0).toFixed(0); })
        .orient("left");
    this._svgxaxis = this._chart.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + this._graph_height + ")");
    this._svgyaxis = this._chart.append("g")
        .attr("class", "y axis")
        .call(this._yaxis);
    this._fftline = d3.svg.line()
        .x(function(d, i) { return this._sx(i); })
        .y(function(d) { return this._graph_height - this._sy(d); });
    this._fftpath = this._chart.append("svg:path")
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-width", "1.5px");
    return this;
}

Fft.prototype._push_data = function(data) {
    this._mean_window.push(data);
    while (this._mean_window.length > this._mean_window_size) {
        this._mean_window.shift();
    }
}

Fft.prototype._get_window_mean = function() {
    var min_size = -1;
    for (var i = 0; i < this._mean_window.length; i++) {
        if (min_size == -1 || this._mean_window[i].length < min_size) {
            min_size = this._mean_window[i].length;
        }
    }
    mean = new Int8Array(min_size);
    for (var x = 0; x < min_size; x++) {
        var m = 0.0;
        for (var i = 0; i < this._mean_window.length; i++) {
            m = m + this._mean_window[i][x];
        }
        mean[x] = m / this._mean_window.length;
    }
    return mean;
}

Fft.prototype._update_sx = function(size) {
    if (size != this._current_fft_size) {
        this._sx = d3.scale.linear()
            .domain([0, size])
            .rangeRound([0, this._graph_width]);
        this._xaxis = d3.svg.axis()
            .scale(this._sx)
            .tickValues([0, size/2, size])
            .tickFormat(function(d) { return d - size/2; })
            .orient("bottom");
        this._svgxaxis.call(this._xaxis);
        this._current_fft_size = size;
    }
}

function get_rearranged_fft(fft) {
    var rearranged = new Int8Array(fft.length);
    middle = Math.floor(fft.length / 2);
    rearranged.set(fft.subarray(middle, fft.length), 0);
    rearranged.set(fft.subarray(0, middle), middle);
    return rearranged;
}

Fft.prototype.start = function() {
    this._ws = new WebSocket("ws://" + this._host + ":" + this._port + "/fftws/" + this._udpport);
    this._ws.binaryType = "arraybuffer";
    this._ws.onopen = function() { console.log("fft websocket opened"); };
    this._ws.onclose = function() { console.log("fft websocket closed"); };
    var self = this;
    this._ws.onmessage = function(evt) {
        if (evt.data instanceof ArrayBuffer) {
            fft = new Int8Array(evt.data);
            self._push_data(fft);
            mean = self._get_window_mean();
            if (self._rearrange_halves) {
                mean = get_rearranged_fft(mean);
            }
            self._update_sx(mean.length);
            self._fftpath.attr("d", self._fftline(mean));
        }
    };
}

Fft.prototype.stop = function() {
    this._ws.close();
}
<commit_msg>add websocket keepalive<commit_after>function Fft(elem, host, port, udpport, rearrange_halves, mean_window_size) {
    this._host = host;
    this._port = port;
    this._udpport = udpport;
    this._rearrange_halves = rearrange_halves;
    this._mean_window_size = mean_window_size;
    this._mean_window = [];
    this._elem = d3.select(elem);
    this._total_width = $(elem).width();
    this._total_height = $(elem).height();
    this._margin = {top: 20, right: 20, bottom: 30, left: 50};
    this._graph_width = this._total_width
        - this._margin.left - this._margin.right;
    this._graph_height = this._total_height
        - this._margin.top - this._margin.bottom;
    this._chart = this._elem.append("svg")
        .attr("width", this._total_width)
        .attr("height", this._total_height)
        .append("g")
        .attr("transform", "translate(" + this._margin.left + "," + this._margin.top + ")");
    this._current_fft_size = -1;
    this._sx = null;
    this._sy = d3.scale.linear()
        .domain([-128,127])
        .rangeRound([0, this._graph_height]);
    this._yaxis = d3.svg.axis()
        .scale(this._sy)
        .tickValues([])
        .tickFormat(function(d) { return (((d+128.0) / 256.0) * -100.0).toFixed(0); })
        .orient("left");
    this._svgxaxis = this._chart.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + this._graph_height + ")");
    this._svgyaxis = this._chart.append("g")
        .attr("class", "y axis")
        .call(this._yaxis);
    this._fftline = d3.svg.line()
        .x(function(d, i) { return this._sx(i); })
        .y(function(d) { return this._graph_height - this._sy(d); });
    this._fftpath = this._chart.append("svg:path")
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-width", "1.5px");
    return this;
}

Fft.prototype._push_data = function(data) {
    this._mean_window.push(data);
    while (this._mean_window.length > this._mean_window_size) {
        this._mean_window.shift();
    }
}

Fft.prototype._get_window_mean = function() {
    var min_size = -1;
    for (var i = 0; i < this._mean_window.length; i++) {
        if (min_size == -1 || this._mean_window[i].length < min_size) {
            min_size = this._mean_window[i].length;
        }
    }
    mean = new Int8Array(min_size);
    for (var x = 0; x < min_size; x++) {
        var m = 0.0;
        for (var i = 0; i < this._mean_window.length; i++) {
            m = m + this._mean_window[i][x];
        }
        mean[x] = m / this._mean_window.length;
    }
    return mean;
}

Fft.prototype._update_sx = function(size) {
    if (size != this._current_fft_size) {
        this._sx = d3.scale.linear()
            .domain([0, size])
            .rangeRound([0, this._graph_width]);
        this._xaxis = d3.svg.axis()
            .scale(this._sx)
            .tickValues([0, size/2, size])
            .tickFormat(function(d) { return d - size/2; })
            .orient("bottom");
        this._svgxaxis.call(this._xaxis);
        this._current_fft_size = size;
    }
}

function get_rearranged_fft(fft) {
    var rearranged = new Int8Array(fft.length);
    middle = Math.floor(fft.length / 2);
    rearranged.set(fft.subarray(middle, fft.length), 0);
    rearranged.set(fft.subarray(0, middle), middle);
    return rearranged;
}

Fft.prototype.start = function() {
    this._ws = new WebSocket("ws://" + this._host + ":" + this._port + "/fftws/" + this._udpport);
    this._ws.binaryType = "arraybuffer";
    this._ws.onopen = function() { console.log("fft websocket opened"); };
    this._ws.onclose = function() { console.log("fft websocket closed"); };
    var self = this;
    this._ws.onmessage = function(evt) {
        if (evt.data instanceof ArrayBuffer) {
            fft = new Int8Array(evt.data);
            self._push_data(fft);
            mean = self._get_window_mean();
            if (self._rearrange_halves) {
                mean = get_rearranged_fft(mean);
            }
            self._update_sx(mean.length);
            self._fftpath.attr("d", self._fftline(mean));
        }
    };
    this._keepalive = setInterval(function() {
        self._ws.send("ping");
    }, 60000);
}

Fft.prototype.stop = function() {
    clearInterval(this._keepalive);
    this._ws.close();
}
<|endoftext|>