<commit_before>(function (window, document, undefined) {

  L.Control.ZoomIndicator = L.Control.extend({
  	options: {
  		position: 'topleft',
  		enabled: true
  	},

  	onAdd: function (map) {
  		var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-zoom-indicator');
      this._link = L.DomUtil.create('a', '', container);
      this._link.innerHTML = map.getZoom();
      map.on('zoomend', function() {
        this._link.innerHTML = map.getZoom();
      }, this);

      return container;
    }
  });

}(this, document));

  L.Icon.Default.imagePath = 'node_modules/leaflet/dist/images/';
var map = L.map('map', {
  center: [45,0],
  zoom: 3,
  worldCopyJump: false,
  maxBounds: [
    [-85, -180],
    [85, 180]
  ],
  attributionControl: false
});

map.addControl(new L.Control.ZoomIndicator());

var credits = L.control.attribution().addTo(map);
credits.addAttribution("© Mapbox © OpenStreetMap");

var baseLayer = L.tileLayer('http://mapbox.geointservices.io:2999/v4/mapbox.light/{z}/{x}/{y}.png');
baseLayer.addTo(map);

var geoPackage;
var tableLayers;
var imageOverlay;
var currentTile = {};
var tableInfos;
var fileName;

var saveByteArray = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, name) {
        var blob = new Blob(data, {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = name;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

window.saveGeoPackage = function() {
  geoPackage.export(function(err, data) {
    fileName = fileName || 'geopackage.gpkg';
    saveByteArray([data.buffer], fileName.substring(0, fileName.lastIndexOf('.')) + '.gpkg');
  });
}

window.loadGeoPackage = function(files) {
  var f = files[0];
  fileName = f.name;
  $('#choose-label').text(f.name);
  var r = new FileReader();
  r.onload = function() {
    var array = new Uint8Array(r.result);

    // if it is a GeoPackage file
    if (f.name.lastIndexOf('gpkg') === f.name.lastIndexOf('.')+1) {
      loadByteArray(array, function() {
        $('#download').removeClass('gone');
      });
    }
    // if it is a GeoJSON file
    else if (f.name.lastIndexOf('json') > f.name.lastIndexOf('.')) {
      var jsonString = '';
      var len = array.byteLength;
      for (var i = 0; i < len; i++) {
        jsonString += String.fromCharCode( array[ i ] );
      }
      var json = JSON.parse(jsonString);
      GeoJSONToGeoPackage.convert(json, function(err, gp) {
        geoPackage = gp;
        clearInfo();
        readGeoPackage(function() {
          $('#download').removeClass('gone');
        });
      });
    }
  }
  r.readAsArrayBuffer(f);
}

function clearInfo() {
  var tileTableNode = $('#tile-tables');
  tileTableNode.empty();
  var featureTableNode = $('#feature-tables');
  featureTableNode.empty();

  for (layerName in tableLayers) {
    map.removeLayer(tableLayers[layerName]);
  }
  tableLayers = {};
  if (imageOverlay) {
    map.removeLayer(imageOverlay);
  }
  $('#information').removeClass('hidden').addClass('visible');
}

function loadByteArray(array, callback) {
  clearInfo();

  GeoPackageAPI.openGeoPackageByteArray(array, function(err, gp) {
    geoPackage = gp;
    readGeoPackage(callback);
  });
}

function readGeoPackage(callback) {
  tableInfos = {};
  var featureTableTemplate = $('#feature-table-template').html();
  Mustache.parse(featureTableTemplate);

  var tileTableTemplate = $('#tile-table-template').html();
  Mustache.parse(tileTableTemplate);

  var tileTableNode = $('#tile-tables');
  var featureTableNode = $('#feature-tables');

  async.parallel([
    function(callback) {
      geoPackage.getTileTables(function(err, tables) {
        async.eachSeries(tables, function(table, callback) {
          geoPackage.getTileDaoWithTableName(table, function(err, tileDao) {
            geoPackage.getInfoForTable(tileDao, function(err, info) {
              tableInfos[table] = info;
              var rendered = Mustache.render(tileTableTemplate, info);
              tileTableNode.append(rendered);
              callback();
            });
          });
        }, callback);
      });
    }, function(callback) {
      geoPackage.getFeatureTables(function(err, tables) {
        async.eachSeries(tables, function(table, callback) {
          geoPackage.getFeatureDaoWithTableName(table, function(err, featureDao) {
            if (err) {
              return callback();
            }
            geoPackage.getInfoForTable(featureDao, function(err, info) {
              tableInfos[table] = info;
              var rendered = Mustache.render(featureTableTemplate, info);
              featureTableNode.append(rendered);
              callback();
            });
          });
        }, callback);
      });
    }
  ], callback);
}

window.zoomTo = function(minX, minY, maxX, maxY, projection) {
  try {
    var sw = proj4(projection, 'EPSG:4326', [minX, minY]);
    var ne = proj4(projection, 'EPSG:4326', [maxX, maxY]);
    map.fitBounds([[sw[1], sw[0]], [ne[1], ne[0]]]);
  } catch (e) {
    map.fitBounds([[minY, minX], [maxY, maxX]]);
  }
}

window.toggleLayer = function(layerType, table) {
  if (tableLayers[table]) {
    map.removeLayer(tableLayers[table]);
    delete tableLayers[table];
    return;
  }

  if (layerType === 'tile') {
    geoPackage.getTileDaoWithTableName(table, function(err, tileDao) {

      var maxZoom = tileDao.maxZoom;
      var minZoom = tileDao.minZoom;
      var tableLayer = L.tileLayer.canvas({noWrap: true, minZoom: minZoom, maxZoom: maxZoom});
      tableLayer.drawTile = function(canvas, tilePoint, zoom) {
        console.time('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + zoom);
        GeoPackageAPI.drawXYZTileInCanvas(geoPackage, table, tilePoint.x, tilePoint.y, zoom, 256, 256, canvas, function(err) {
          console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + zoom);
          tableLayer.tileDrawn(canvas);
        });
      };
      tableLayer.addTo(map);
      tableLayer.bringToFront();
      tableLayers[table] = tableLayer;
    });
  } else if (layerType === 'feature') {
    var geojsonLayer = L.geoJson([], {
        style: function (feature) {
            return {
              color: "#00F",
              weight: 2,
              opacity: 1
            };
        },
        onEachFeature: function (feature, layer) {
          var string = "";
          for (var key in feature.properties) {
            string += '
' + key + ': ' + feature.properties[key] + '
';
          }
          layer.bindPopup(string);
        }
    });
    var tableInfo = tableInfos[table];

    GeoPackageAPI.iterateGeoJSONFeaturesFromTable(geoPackage, table, function(err, geoJson, done) {
      geojsonLayer.addData(geoJson);
      done();
    }, function(err) {
      geojsonLayer.addTo(map);
      geojsonLayer.bringToFront();
      tableLayers[table] = geojsonLayer;
    });
  }
}

window.loadUrl = function(url, loadingElement, gpName) {
  loadingElement.toggle();
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';

  $('#choose-label').text(gpName);

  xhr.onload = function(e) {
    var uInt8Array = new Uint8Array(this.response);
    loadByteArray(uInt8Array, function() {
      $('#download').removeClass('gone');
      loadingElement.toggle();
    });
  };
  xhr.send();
}

window.loadZooms = function(tableName, tilesElement) {
  var zoomsTemplate = $('#tile-zoom-levels-template').html();
  Mustache.parse(zoomsTemplate);

  geoPackage.getTileDaoWithTableName(tableName, function(err, tileDao) {
    var zooms = [];
    for (var i = tileDao.minZoom; i <= tileDao.maxZoom; i++) {
      zooms.push({zoom: i, tableName: tableName});
    }
    var zoomLevels = {
      zooms: zooms
    };
    var rendered = Mustache.render(zoomsTemplate, zoomLevels);
    tilesElement.empty();
    tilesElement.append(rendered);
  });
}

var visibleTileTables = {};

window.zoomMap = function(zoom) {
  map.setZoom(zoom);
}

window.registerTileTable = function(tableName, tilesElement) {
  visibleTileTables[tableName] = tilesElement;
  loadTiles(tableName, map.getZoom(), tilesElement);
}

window.unregisterTileTable = function(tableName) {
  delete visibleTileTables[tableName];
}

map.on('moveend', function() {
  for (var table in visibleTileTables) {
    window.loadTiles(table, map.getZoom(), visibleTileTables[table]);
  }
});

window.loadTiles = function(tableName, zoom, tilesElement) {
  map.setZoom(zoom);
  var mapBounds = map.getBounds();
  if (imageOverlay) map.removeLayer(imageOverlay);
  currentTile = {};

  var tilesTableTemplate = $('#all-tiles-template').html();
  Mustache.parse(tilesTableTemplate);

  GeoPackageAPI.getTilesInBoundingBox(geoPackage, tableName, zoom, Math.max(-180, mapBounds.getWest()), Math.min(mapBounds.getEast(), 180), mapBounds.getSouth(), mapBounds.getNorth(), function(err, tiles) {
    if (!tiles || !tiles.tiles || !tiles.tiles.length) {
      tilesElement.empty();
      tilesElement.html('
No tiles exist in the GeoPackage for the current bounds and zoom level. Min zoom: ' + tileDao.minZoom + ' Max Zoom: ' + tileDao.maxZoom + '
')
      return;
    }
    var rendered = Mustache.render(tilesTableTemplate, tiles);
    tilesElement.empty();
    tilesElement.append(rendered);
  });
}

window.zoomToTile = function(tileColumn, tileRow, zoom, minLongitude, minLatitude, maxLongitude, maxLatitude, projection, tableName) {
  if (imageOverlay) map.removeLayer(imageOverlay);
  if (tileColumn === currentTile.tileColumn
  && tileRow === currentTile.tileRow
  && zoom === currentTile.zoom
  && tableName === currentTile.tableName) {
    currentTile = {};
    return;
  }
  var sw = proj4(projection, 'EPSG:4326', [minLongitude, minLatitude]);
  var ne = proj4(projection, 'EPSG:4326', [maxLongitude, maxLatitude]);

  GeoPackageAPI.getTileFromTable(geoPackage, tableName, zoom, tileRow, tileColumn, function(err, tile) {
    var tileData = tile.getTileData();
    var type = fileType(tileData);
    var binary = '';
    var bytes = tileData;
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
      binary += String.fromCharCode( bytes[ i ] );
    }
    var base64Data = btoa( binary );
    var url = 'data:'+type.mime+';base64,' + base64Data;
    imageOverlay = L.imageOverlay(url, [[sw[1], sw[0]], [ne[1], ne[0]]]);
    currentTile.tileColumn = tileColumn;
    currentTile.tileRow = tileRow;
    currentTile.zoom = zoom;
    currentTile.tableName = tableName;
    imageOverlay.addTo(map);
  });
}

window.highlightTile = function(minLongitude, minLatitude, maxLongitude, maxLatitude, projection) {

  var sw = proj4(projection, 'EPSG:4326', [minLongitude, minLatitude]);
  var ne = proj4(projection, 'EPSG:4326', [maxLongitude, maxLatitude]);
  var poly =  {
    type: "Feature",
    geometry: {
      type: "Polygon",
      coordinates: [
        [[sw[0], sw[1]],
        [sw[0], ne[1]],
        [ne[0], ne[1]],
        [ne[0], sw[1]],
        [sw[0], sw[1]]]
      ]
    }
  };

  highlightLayer.clearLayers();
  highlightLayer.addData(poly);
  highlightLayer.bringToFront();
}

window.loadFeatures = function(tableName, featuresElement) {
  var featuresTableTemplate = $('#all-features-template').html();
  Mustache.parse(featuresTableTemplate);

  var features = {
    columns: tableInfos[tableName].columns,
    srs: tableInfos[tableName].srs,
    features: []
  };
  console.log('columns', features.columns);
  GeoPackageAPI.iterateGeoJSONFeaturesFromTable(geoPackage, tableName, function(err, feature, featureDone) {
    feature.tableName = tableName;
    feature.values = [];
    console.log('feature.properties', feature.properties);
    for (var i = 0; i < features.columns.length; i++) {
      var value = feature.properties[features.columns[i].name];
      if (value === null || value === 'null') {
        feature.values.push('');
      } else {
        feature.values.push(value.toString());
      }
    }
    features.features.push(feature);
    featureDone();
  }, function() {
    var rendered = Mustache.render(featuresTableTemplate, features);
    featuresElement.empty();
    featuresElement.append(rendered);
  });
}

var highlightLayer = L.geoJson([], {
    style: function (feature) {
        return {
          color: "#F00",
          weight: 3,
          opacity: 1
        };
    },
    onEachFeature: function (feature, layer) {
      var string = "";
      for (var key in feature.properties) {
        string += '
' + key + ': ' + feature.properties[key] + '
';
      }
      layer.bindPopup(string);
    }
});
map.addLayer(highlightLayer);

window.highlightFeature = function(featureId, tableName) {

  GeoPackageAPI.getFeature(geoPackage, tableName, featureId, function(err, geoJson) {
    highlightLayer.clearLayers();
    highlightLayer.addData(geoJson);
    highlightLayer.bringToFront();
  });
}

window.zoomToFeature = function(featureId, tableName) {
  window.toggleFeature(featureId, tableName, true, true);
}

var currentFeature;
var featureLayer = L.geoJson([], {
    style: function (feature) {
        return {
          color: "#8000FF",
          weight: 3,
          opacity: 1
        };
    },
    onEachFeature: function (feature, layer) {
      var string = "";
      for (var key in feature.properties) {
        string += '
' + key + ': ' + feature.properties[key] + '
';
      }
      layer.bindPopup(string);
    }
});
map.addLayer(featureLayer);

window.toggleFeature = function(featureId, tableName, zoom, force) {
  featureLayer.clearLayers();

  if (currentFeature === featureId && !force) {
    currentFeature = undefined;
    return;
  }

  currentFeature = featureId;

  GeoPackageAPI.getFeature(geoPackage, tableName, featureId, function(err, geoJson) {
    featureLayer.addData(geoJson);
    featureLayer.bringToFront();
    if (zoom) {
      map.fitBounds(featureLayer.getBounds());
    }
  });
}

window.clearHighlights = function() {
  highlightLayer.clearLayers();
}
<commit_msg>fixed incorrect filenames when downloading sample geopackages<commit_after>(function (window, document, undefined) {

  L.Control.ZoomIndicator = L.Control.extend({
  	options: {
  		position: 'topleft',
  		enabled: true
  	},

  	onAdd: function (map) {
  		var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-zoom-indicator');
      this._link = L.DomUtil.create('a', '', container);
      this._link.innerHTML = map.getZoom();
      map.on('zoomend', function() {
        this._link.innerHTML = map.getZoom();
      }, this);

      return container;
    }
  });

}(this, document));

  L.Icon.Default.imagePath = 'node_modules/leaflet/dist/images/';
var map = L.map('map', {
  center: [45,0],
  zoom: 3,
  worldCopyJump: false,
  maxBounds: [
    [-85, -180],
    [85, 180]
  ],
  attributionControl: false
});

map.addControl(new L.Control.ZoomIndicator());

var credits = L.control.attribution().addTo(map);
credits.addAttribution("© Mapbox © OpenStreetMap");

var baseLayer = L.tileLayer('http://mapbox.geointservices.io:2999/v4/mapbox.light/{z}/{x}/{y}.png');
baseLayer.addTo(map);

var geoPackage;
var tableLayers;
var imageOverlay;
var currentTile = {};
var tableInfos;
var fileName;

var saveByteArray = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, name) {
        var blob = new Blob(data, {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = name;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

window.saveGeoPackage = function() {
  geoPackage.export(function(err, data) {
    fileName = fileName || 'geopackage.gpkg';
    saveByteArray([data.buffer], fileName.substring(0, fileName.lastIndexOf('.')) + '.gpkg');
  });
}

window.loadGeoPackage = function(files) {
  var f = files[0];
  fileName = f.name;
  $('#choose-label').text(f.name);
  var r = new FileReader();
  r.onload = function() {
    var array = new Uint8Array(r.result);

    // if it is a GeoPackage file
    if (f.name.lastIndexOf('gpkg') === f.name.lastIndexOf('.')+1) {
      loadByteArray(array, function() {
        $('#download').removeClass('gone');
      });
    }
    // if it is a GeoJSON file
    else if (f.name.lastIndexOf('json') > f.name.lastIndexOf('.')) {
      var jsonString = '';
      var len = array.byteLength;
      for (var i = 0; i < len; i++) {
        jsonString += String.fromCharCode( array[ i ] );
      }
      var json = JSON.parse(jsonString);
      GeoJSONToGeoPackage.convert(json, function(err, gp) {
        geoPackage = gp;
        clearInfo();
        readGeoPackage(function() {
          $('#download').removeClass('gone');
        });
      });
    }
  }
  r.readAsArrayBuffer(f);
}

function clearInfo() {
  var tileTableNode = $('#tile-tables');
  tileTableNode.empty();
  var featureTableNode = $('#feature-tables');
  featureTableNode.empty();

  for (layerName in tableLayers) {
    map.removeLayer(tableLayers[layerName]);
  }
  tableLayers = {};
  if (imageOverlay) {
    map.removeLayer(imageOverlay);
  }
  $('#information').removeClass('hidden').addClass('visible');
}

function loadByteArray(array, callback) {
  clearInfo();

  GeoPackageAPI.openGeoPackageByteArray(array, function(err, gp) {
    geoPackage = gp;
    readGeoPackage(callback);
  });
}

function readGeoPackage(callback) {
  tableInfos = {};
  var featureTableTemplate = $('#feature-table-template').html();
  Mustache.parse(featureTableTemplate);

  var tileTableTemplate = $('#tile-table-template').html();
  Mustache.parse(tileTableTemplate);

  var tileTableNode = $('#tile-tables');
  var featureTableNode = $('#feature-tables');

  async.parallel([
    function(callback) {
      geoPackage.getTileTables(function(err, tables) {
        async.eachSeries(tables, function(table, callback) {
          geoPackage.getTileDaoWithTableName(table, function(err, tileDao) {
            geoPackage.getInfoForTable(tileDao, function(err, info) {
              tableInfos[table] = info;
              var rendered = Mustache.render(tileTableTemplate, info);
              tileTableNode.append(rendered);
              callback();
            });
          });
        }, callback);
      });
    }, function(callback) {
      geoPackage.getFeatureTables(function(err, tables) {
        async.eachSeries(tables, function(table, callback) {
          geoPackage.getFeatureDaoWithTableName(table, function(err, featureDao) {
            if (err) {
              return callback();
            }
            geoPackage.getInfoForTable(featureDao, function(err, info) {
              tableInfos[table] = info;
              var rendered = Mustache.render(featureTableTemplate, info);
              featureTableNode.append(rendered);
              callback();
            });
          });
        }, callback);
      });
    }
  ], callback);
}

window.zoomTo = function(minX, minY, maxX, maxY, projection) {
  try {
    var sw = proj4(projection, 'EPSG:4326', [minX, minY]);
    var ne = proj4(projection, 'EPSG:4326', [maxX, maxY]);
    map.fitBounds([[sw[1], sw[0]], [ne[1], ne[0]]]);
  } catch (e) {
    map.fitBounds([[minY, minX], [maxY, maxX]]);
  }
}

window.toggleLayer = function(layerType, table) {
  if (tableLayers[table]) {
    map.removeLayer(tableLayers[table]);
    delete tableLayers[table];
    return;
  }

  if (layerType === 'tile') {
    geoPackage.getTileDaoWithTableName(table, function(err, tileDao) {

      var maxZoom = tileDao.maxZoom;
      var minZoom = tileDao.minZoom;
      var tableLayer = L.tileLayer.canvas({noWrap: true, minZoom: minZoom, maxZoom: maxZoom});
      tableLayer.drawTile = function(canvas, tilePoint, zoom) {
        console.time('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + zoom);
        GeoPackageAPI.drawXYZTileInCanvas(geoPackage, table, tilePoint.x, tilePoint.y, zoom, 256, 256, canvas, function(err) {
          console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + zoom);
          tableLayer.tileDrawn(canvas);
        });
      };
      tableLayer.addTo(map);
      tableLayer.bringToFront();
      tableLayers[table] = tableLayer;
    });
  } else if (layerType === 'feature') {
    var geojsonLayer = L.geoJson([], {
        style: function (feature) {
            return {
              color: "#00F",
              weight: 2,
              opacity: 1
            };
        },
        onEachFeature: function (feature, layer) {
          var string = "";
          for (var key in feature.properties) {
            string += '
' + key + ': ' + feature.properties[key] + '
';
          }
          layer.bindPopup(string);
        }
    });
    var tableInfo = tableInfos[table];

    GeoPackageAPI.iterateGeoJSONFeaturesFromTable(geoPackage, table, function(err, geoJson, done) {
      geojsonLayer.addData(geoJson);
      done();
    }, function(err) {
      geojsonLayer.addTo(map);
      geojsonLayer.bringToFront();
      tableLayers[table] = geojsonLayer;
    });
  }
}

window.loadUrl = function(url, loadingElement, gpName) {
  fileName = url.split('/').pop();
  console.log(fileName)
  loadingElement.toggle();
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';

  $('#choose-label').text(gpName);

  xhr.onload = function(e) {
    var uInt8Array = new Uint8Array(this.response);
    loadByteArray(uInt8Array, function() {
      $('#download').removeClass('gone');
      loadingElement.toggle();
    });
  };
  xhr.send();
}

window.loadZooms = function(tableName, tilesElement) {
  var zoomsTemplate = $('#tile-zoom-levels-template').html();
  Mustache.parse(zoomsTemplate);

  geoPackage.getTileDaoWithTableName(tableName, function(err, tileDao) {
    var zooms = [];
    for (var i = tileDao.minZoom; i <= tileDao.maxZoom; i++) {
      zooms.push({zoom: i, tableName: tableName});
    }
    var zoomLevels = {
      zooms: zooms
    };
    var rendered = Mustache.render(zoomsTemplate, zoomLevels);
    tilesElement.empty();
    tilesElement.append(rendered);
  });
}

var visibleTileTables = {};

window.zoomMap = function(zoom) {
  map.setZoom(zoom);
}

window.registerTileTable = function(tableName, tilesElement) {
  visibleTileTables[tableName] = tilesElement;
  loadTiles(tableName, map.getZoom(), tilesElement);
}

window.unregisterTileTable = function(tableName) {
  delete visibleTileTables[tableName];
}

map.on('moveend', function() {
  for (var table in visibleTileTables) {
    window.loadTiles(table, map.getZoom(), visibleTileTables[table]);
  }
});

window.loadTiles = function(tableName, zoom, tilesElement) {
  map.setZoom(zoom);
  var mapBounds = map.getBounds();
  if (imageOverlay) map.removeLayer(imageOverlay);
  currentTile = {};

  var tilesTableTemplate = $('#all-tiles-template').html();
  Mustache.parse(tilesTableTemplate);

  GeoPackageAPI.getTilesInBoundingBox(geoPackage, tableName, zoom, Math.max(-180, mapBounds.getWest()), Math.min(mapBounds.getEast(), 180), mapBounds.getSouth(), mapBounds.getNorth(), function(err, tiles) {
    if (!tiles || !tiles.tiles || !tiles.tiles.length) {
      tilesElement.empty();
      tilesElement.html('
No tiles exist in the GeoPackage for the current bounds and zoom level. Min zoom: ' + tileDao.minZoom + ' Max Zoom: ' + tileDao.maxZoom + '
')
      return;
    }
    var rendered = Mustache.render(tilesTableTemplate, tiles);
    tilesElement.empty();
    tilesElement.append(rendered);
  });
}

window.zoomToTile = function(tileColumn, tileRow, zoom, minLongitude, minLatitude, maxLongitude, maxLatitude, projection, tableName) {
  if (imageOverlay) map.removeLayer(imageOverlay);
  if (tileColumn === currentTile.tileColumn
  && tileRow === currentTile.tileRow
  && zoom === currentTile.zoom
  && tableName === currentTile.tableName) {
    currentTile = {};
    return;
  }
  var sw = proj4(projection, 'EPSG:4326', [minLongitude, minLatitude]);
  var ne = proj4(projection, 'EPSG:4326', [maxLongitude, maxLatitude]);

  GeoPackageAPI.getTileFromTable(geoPackage, tableName, zoom, tileRow, tileColumn, function(err, tile) {
    var tileData = tile.getTileData();
    var type = fileType(tileData);
    var binary = '';
    var bytes = tileData;
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
      binary += String.fromCharCode( bytes[ i ] );
    }
    var base64Data = btoa( binary );
    var url = 'data:'+type.mime+';base64,' + base64Data;
    imageOverlay = L.imageOverlay(url, [[sw[1], sw[0]], [ne[1], ne[0]]]);
    currentTile.tileColumn = tileColumn;
    currentTile.tileRow = tileRow;
    currentTile.zoom = zoom;
    currentTile.tableName = tableName;
    imageOverlay.addTo(map);
  });
}

window.highlightTile = function(minLongitude, minLatitude, maxLongitude, maxLatitude, projection) {

  var sw = proj4(projection, 'EPSG:4326', [minLongitude, minLatitude]);
  var ne = proj4(projection, 'EPSG:4326', [maxLongitude, maxLatitude]);
  var poly =  {
    type: "Feature",
    geometry: {
      type: "Polygon",
      coordinates: [
        [[sw[0], sw[1]],
        [sw[0], ne[1]],
        [ne[0], ne[1]],
        [ne[0], sw[1]],
        [sw[0], sw[1]]]
      ]
    }
  };

  highlightLayer.clearLayers();
  highlightLayer.addData(poly);
  highlightLayer.bringToFront();
}

window.loadFeatures = function(tableName, featuresElement) {
  var featuresTableTemplate = $('#all-features-template').html();
  Mustache.parse(featuresTableTemplate);

  var features = {
    columns: tableInfos[tableName].columns,
    srs: tableInfos[tableName].srs,
    features: []
  };
  console.log('columns', features.columns);
  GeoPackageAPI.iterateGeoJSONFeaturesFromTable(geoPackage, tableName, function(err, feature, featureDone) {
    feature.tableName = tableName;
    feature.values = [];
    console.log('feature.properties', feature.properties);
    for (var i = 0; i < features.columns.length; i++) {
      var value = feature.properties[features.columns[i].name];
      if (value === null || value === 'null') {
        feature.values.push('');
      } else {
        feature.values.push(value.toString());
      }
    }
    features.features.push(feature);
    featureDone();
  }, function() {
    var rendered = Mustache.render(featuresTableTemplate, features);
    featuresElement.empty();
    featuresElement.append(rendered);
  });
}

var highlightLayer = L.geoJson([], {
    style: function (feature) {
        return {
          color: "#F00",
          weight: 3,
          opacity: 1
        };
    },
    onEachFeature: function (feature, layer) {
      var string = "";
      for (var key in feature.properties) {
        string += '
' + key + ': ' + feature.properties[key] + '
';
      }
      layer.bindPopup(string);
    }
});
map.addLayer(highlightLayer);

window.highlightFeature = function(featureId, tableName) {

  GeoPackageAPI.getFeature(geoPackage, tableName, featureId, function(err, geoJson) {
    highlightLayer.clearLayers();
    highlightLayer.addData(geoJson);
    highlightLayer.bringToFront();
  });
}

window.zoomToFeature = function(featureId, tableName) {
  window.toggleFeature(featureId, tableName, true, true);
}

var currentFeature;
var featureLayer = L.geoJson([], {
    style: function (feature) {
        return {
          color: "#8000FF",
          weight: 3,
          opacity: 1
        };
    },
    onEachFeature: function (feature, layer) {
      var string = "";
      for (var key in feature.properties) {
        string += '
' + key + ': ' + feature.properties[key] + '
';
      }
      layer.bindPopup(string);
    }
});
map.addLayer(featureLayer);

window.toggleFeature = function(featureId, tableName, zoom, force) {
  featureLayer.clearLayers();

  if (currentFeature === featureId && !force) {
    currentFeature = undefined;
    return;
  }

  currentFeature = featureId;

  GeoPackageAPI.getFeature(geoPackage, tableName, featureId, function(err, geoJson) {
    featureLayer.addData(geoJson);
    featureLayer.bringToFront();
    if (zoom) {
      map.fitBounds(featureLayer.getBounds());
    }
  });
}

window.clearHighlights = function() {
  highlightLayer.clearLayers();
}
<|endoftext|>


<commit_before>var eveShippingCalc = angular.module('eveShippingCalc',[]);

var tradeHubs = ["Amarr"];

eveShippingCalc.controller("CalcCtrl", ['$scope', '$window', '$location', function($scope, $window, $location) {
  $scope.location = $location
  $scope.cfg = $window.ESCconfig;

  $scope.init = function() {
    //Useful aliases:
    $scope.routes = $scope.cfg.routes;
    $scope.stations = $scope.cfg.stations;
    $scope.routesMeta = $scope.cfg.routesMeta;
    $scope.noneStation = $scope.stations["none"];
    $scope.unsetStation = $scope.stations["unset"];

    //Initialise routes/stations:

    //If there's only one route to choose (not counting the "unset" placeholder),
    //just set the route directly to that
    if ($scope.routes.length == 2)
      $scope.formRoute = $scope.routes[1];
    else
      $scope.formRoute = $scope.routes[0];
    $scope.pickupStations = [$scope.noneStation];
    $scope.destStations = [$scope.noneStation];
    $scope.formPickup = $scope.pickupStations[0];
    $scope.formDest = $scope.destStations[0];
    $scope.routeInfo = {};
    $scope.routeSecTypes = [];

    $scope.formVol = "";
    $scope.formVal = "";
    $scope.formCredit = "";
    $scope.errors = [];
    $scope.status = "Initial";
    $scope.volPrice = undefined;
    $scope.volPriceDesc = "";
    $scope.valPrice = undefined;
    $scope.valPriceDesc = "";
    $scope.containerPrice = undefined;
    $scope.totalPrice = undefined;

    $scope.desc = "";
    $scope.inEve = typeof CCPEVE === "object";

    var url = $scope.location.absUrl();
    var trustUrl = url.substring(0, url.lastIndexOf('/')) + "/*";

    if($scope.inEve) {
      console.log("requesting trust for " + trustUrl);
      var ret = CCPEVE.requestTrust(trustUrl);
    };

  };

  //******************************************************
  // Watches - react to model changes
  //******************************************************

  $scope.$watch('formRoute.name',
      function(newVal, oldVal) {
        console.log("formRoute changed from "+oldVal+" to "+newVal);
        $scope.pickupStations = $scope.filterStations(null);
        $scope.updateStations();
      });

  $scope.$watch('formPickup.id',
      function(newVal, oldVal) {
        $scope.logStationChange("Pickup", newVal, oldVal);
        $scope.updateStations();
      });

  $scope.$watch('formDest.id',
      function(newVal, oldVal) {
        $scope.logStationChange("Destination", newVal, oldVal);
        // Changing the destination station can't change the valid stations, so no
        // need to call updateStations()
        $scope.updateRouteInfo();
      });

  $scope.$watch('[calcForm.vol_input.$error, calcForm.val_input.$error, calcForm.credit_input.$error]',
      function(newVal, oldVal) {
        //console.log("Inputs changed validity:" + JSON.stringify(newVal))
        $scope.updateErrors(newVal, ["Volume", "Value", "Credit"]);
      }, true);

  // Keep the Volume price updated
  $scope.$watch('[routeInfo.volUnit, routeInfo.volCost, formVol, calcForm.vol_input.$valid]',
      function(newVal, oldVal) {
        $scope.updatePrice(
          $scope.routeInfo.volUnit,
          $scope.routeInfo.volCost,
          $scope.calcForm.vol_input,
          "volPrice",
          "volPriceDesc",
          "k m^3");
      }, true);

  // Keep the Value price updated
  $scope.$watch('[routeInfo.valUnit, routeInfo.valCost, formVal, calcForm.val_input.$valid]',
      function(newVal, oldVal) {
        $scope.updatePrice(
          $scope.routeInfo.valUnit,
          $scope.routeInfo.valCost,
          $scope.calcForm.val_input,
          "valPrice",
          "valPriceDesc",
          "Mil ISK");
      }, true);

  // Keep container price updated
  $scope.$watch('formContainer',
      function(newVal, oldVal) {
        console.log("Containers changed: " + newVal);
        $scope.updateContainerPrice();
      });

  // Keep total price updated
  $scope.$watch('[volPrice, valPrice, containerPrice, formCredit]',
      function(newVal, oldVal) {
        $scope.updateTotalPrice();
      }, true);

  //******************************************************
  // Routes and stations
  //******************************************************

  $scope.filterStations = function(skip) {
    var stns = [];
    var routeStns = $scope.routesMeta[$scope.formRoute.name].stns;

    for(var i in routeStns) {
      var routeStn = routeStns[i];
      var stn = $scope.stations[routeStn.id];
      if (skip !== null && skip.id !== "unset" && stn.id === skip.id) {
        continue;
      }
      stns.push(stn);
    };

    if (stns.length === 0) {
      return [$scope.noneStation];
    } else {
      // Prepend the "unset" station to the start of the list
      stns.unshift($scope.unsetStation);
      return stns;
    }
  }

  $scope.updateStations = function() {
    if (!$scope.findStation($scope.formPickup.id, $scope.pickupStations)) {
      // Only change the current pickup station if it isn't valid for the current route
      $scope.formPickup = $scope.pickupStations[0];
    };

    // Recalculate the valid destination stations
    $scope.destStations = $scope.filterStations($scope.formPickup);

    if (!$scope.findStation($scope.formDest.id, $scope.destStations)) {
      // Only change the current pickup station if it isn't valid for the current route
      $scope.formDest = $scope.destStations[0];
    };

    // If there's only one station to choose (not counting the "unset"
    // placeholder), just set destination directly to that
    if ($scope.destStations.length === 2) {
      $scope.formDest = $scope.destStations[1];
    };

    $scope.updateRouteInfo();
  };

  $scope.findStation = function(id, stations) {
    //console.log("findStation: id:"+id);
    var index = $scope.stationIndex(id, stations)
    return stations[index]
  };

  $scope.stationIndex = function(id, stations) {
    //console.log("stationIndex: id:"+id);
    for(var i=0; i < stations.length; i++) {
      var stn = stations[i];
      if(stn.id === id)
        return i;
    };
    return -1;
  };

  $scope.updateRouteInfo = function() {
    var routeInfo = {};
    $scope.routeSecTypes = [];

    var curRouteMeta = $scope.routesMeta[$scope.formRoute.name];
    var pickupIdx = $scope.stationIndex($scope.formPickup.id, curRouteMeta.stns);
    var destIdx = $scope.stationIndex($scope.formDest.id, curRouteMeta.stns);

    console.log(
        "updateRouteInfo: pickup Id:"
        +$scope.formPickup.id
        +" index:"
        +pickupIdx
        +" destination Id:"
        +$scope.formDest.id
        +" index:"
        +destIdx);
    if(pickupIdx < 0 || destIdx < 0) {
      $scope.routeInfo = {};
      return;
    }

    routeInfo.volUnit = curRouteMeta["volUnit"];
    routeInfo.volCost = 0;
    routeInfo.valUnit = curRouteMeta["valUnit"];
    routeInfo.valCost = 0;

    var step = 1;
    var start = pickupIdx;
    var end = destIdx + 1; //So we include the destIdx in the loop
    var valCostName = "valCostNext";
    var volCostName = "volCostNext";
    if (pickupIdx > destIdx) {
      step = -1;
      start = pickupIdx;
      end = destIdx -1; //So we include the pickupIdx in the loop
      valCostName = "valCostPrev";
      volCostName = "volCostPrev";
    };

    for(var i=start; i!=end; i+=step) {
      var stnId = curRouteMeta.stns[i].id;
      var name = $scope.stations[stnId].name;
      $scope.routeSecTypes.push($scope.stations[stnId].sec);
      console.log("Station:"+name);
      if(i !== destIdx) { // Don't include cost of final station.
        if(routeInfo.volUnit) {
          var cost = curRouteMeta.stns[i][volCostName] ||  curRouteMeta.stns[i]["volCost"];
          if(cost !== undefined)
            routeInfo.volCost += cost;
        }
        if(routeInfo.valUnit) {
          var cost = curRouteMeta.stns[i][valCostName] || curRouteMeta.stns[i]["valCost"];
          if(cost !== undefined)
            routeInfo.valCost += cost;
        }
      }
    };

    if(routeInfo.volCost === 0)
      routeInfo.volCost = undefined;
    if(routeInfo.valCost === 0)
      routeInfo.valCost = undefined;
    $scope.routeInfo = routeInfo;

    console.log("route info: "+JSON.stringify($scope.routeInfo));
    console.log("Sec types:"+$scope.routeSecTypes);
  };

  // TODO(kormat): can probably just remove this
  $scope.hasHighsecSection = function() {
    var highsec = 0;
    for(var i=0; i < $scope.routeSecTypes.length; i++) {
      if($scope.routeSecTypes[i] !== "high") {
        highsec = 0;
        continue;
      };
      highsec++;
      if(highsec > 1)
        return true;
    };
    return false;
  };

  //******************************************************
  // Cost calculations
  //******************************************************

  $scope.updatePrice = function(unit, cost, input, price, desc, unitDesc) {
    if(unit === undefined
       || cost === undefined) {
      $scope[price] = undefined;
      $scope[desc] = "";
    } else if(input.$valid === false) {
      $scope[price] = undefined;
    } else {
      $scope[price] = Math.max(1, Math.ceil(input.$modelValue / unit)) * cost;
      $scope[desc] = cost.toFixed(2)
             +"Mil per "
             +unit.toFixed(0)
             +unitDesc;
    };
  };

  $scope.updateContainerPrice = function() {
    if($scope.formContainer)
      $scope.containerPrice = $scope.cfg.rules.containerSurcharge;
    else
      $scope.containerPrice = 0;
  };

  $scope.updateTotalPrice = function() {
    if($scope.errors.length === 0) {
      var price = 0;
      var inputs = [$scope.volPrice, $scope.valPrice, $scope.containerPrice, -$scope.formCredit];
      for(var i=0; i<inputs.length; i++) {
        if(angular.isNumber(inputs[i]))
          price += inputs[i];
      };
      $scope.totalPrice = price;
    } else {
      $scope.totalPrice = undefined;
    };
  }

  $scope.updateCosts = function() {
    $scope.status = "updateCosts()";
    $scope.calcHighsecCost($scope.form_route, $scope.form_pickup, $scope.form_dest);
    $scope.calcNullsecCost($scope.form_route, $scope.form_pickup, $scope.form_dest);
    $scope.calcContainerCost();
    $scope.calcTotalCost($scope.form_pickup, $scope.form_dest);
    $scope.calcDescription();
  }

  $scope.calcHighsecCost = function(route, pickup, dest) {
    $scope.status = "calcHighsecCost()";
    if($scope.routeType(pickup, dest) != "incomplete") {
      if((tradeHubs.indexOf(pickup.name) > -1) ||
          (tradeHubs.indexOf(dest.name) > -1)) {
        $scope.highsecCost = Math.ceil($scope.form_val / 100);
        $scope.highsecRate = "1M per 100M ISK";
        return;
      }
    }
    $scope.highsecCost = 0;
    $scope.highsecRate = "";
  };

  $scope.calcNullsecCost = function(route, pickup, dest) {
    $scope.status = "calcNullsecCost()";
    switch($scope.routeType(pickup, dest)) {
      case "incomplete":
      case "high":
        $scope.nullsecCost = 0;
        $scope.nullsecRate = "";
        return;
    }

    if(route == "catch") {
      $scope.status = "calcNullsecCost() catch";
      if(pickup.sec == "high") {
        $scope.status = "calcNullsecCost() inbound to 4-07";
        $scope.nullsecCost = Math.ceil($scope.form_vol / 10) * 1.85;
        $scope.nullsecRate = "1.85M per 10k m^3";
      } else if (dest.sec == "high") {
        $scope.status = "calcNullsecCost() outbound from 4-07";
        $scope.nullsecCost = Math.ceil($scope.form_vol / 10) * 0.9;
        $scope.nullsecRate = "0.9M per 10k m^3";
      } else {
        $scope.nullsecCost = 1;
        $scope.nullsecRate = [
          "Error: unknown source/dest pair: ",
          $scope.form_pickup.name,
          $scope.form_dest.name].join(",");
      }
    }
  };

  $scope.calcContainerCost = function() {
    $scope.status = "calcContainerCost()";
    if($scope.form_container == true)
      $scope.containerCost = 5;
    else
      $scope.containerCost = 0;
  };

  $scope.calcTotalCost = function(pickup, dest) {
    $scope.status = "calcTotalCost()"
    if($scope.routeType(pickup, dest) != "incomplete")
      $scope.totalCost = $scope.highsecCost + $scope.nullsecCost + $scope.containerCost - $scope.creditDiscount;
    else
      $scope.totalCost = "";
  };

  $scope.calcDescription = function() {
    $scope.status = "calcDescription()";
    var desc = []
    if($scope.form_val)
      desc.push($scope.form_val+"M value");
    if($scope.creditDiscount)
      desc.push($scope.creditDiscount+"M credit");
    if($scope.form_container)
      desc.push("container");
    $scope.desc = desc.join(", ");
  };

  //******************************************************
  // IGB (In-Game Browser) utility functions
  //******************************************************

  $scope.showStn = function(id) {
    CCPEVE.showInfo(3867, id);
  };

  $scope.showCorp = function() {
    //FIXME(kormat): un-hardcode corp id
    CCPEVE.showInfo(2, 98237970)
  };

  $scope.createContract = function() {
    CCPEVE.createContract(3, $scope.formPickup.id);
  };

  //******************************************************
  // Utility functions
  //******************************************************

  $scope.logStationChange = function(name, newVal, oldVal) {
    console.log(name+" changed from "
      +oldVal
      +"("
      +($scope.stations[oldVal].name || "none")
      +") to "
      +newVal
      +"("
      +($scope.stations[newVal].name || "none")
      +")");
  };

  $scope.updateErrors = function(inputErrors, inputNames) {
    $scope.errors = [];
    for (var i=0; i<inputErrors.length; i++) {
      var inputError = inputErrors[i];
      var inputName = inputNames[i];
      if (inputError['number']) {
        $scope.errors.push(inputName+": not a valid number");
      } else if (inputError['min']) {
        $scope.errors.push(inputName+": too small");
      } else if (inputError['max']) {
        $scope.errors.push(inputName+": too large");
      }
    };
  }

  //Now that everything is defined, finally call init()
  $scope.init();
}]);
<commit_msg>Remove obsolete code<commit_after>var eveShippingCalc = angular.module('eveShippingCalc',[]);

var tradeHubs = ["Amarr"];

eveShippingCalc.controller("CalcCtrl", ['$scope', '$window', '$location', function($scope, $window, $location) {
  $scope.location = $location
  $scope.cfg = $window.ESCconfig;

  $scope.init = function() {
    //Useful aliases:
    $scope.routes = $scope.cfg.routes;
    $scope.stations = $scope.cfg.stations;
    $scope.routesMeta = $scope.cfg.routesMeta;
    $scope.noneStation = $scope.stations["none"];
    $scope.unsetStation = $scope.stations["unset"];

    //Initialise routes/stations:

    //If there's only one route to choose (not counting the "unset" placeholder),
    //just set the route directly to that
    if ($scope.routes.length == 2)
      $scope.formRoute = $scope.routes[1];
    else
      $scope.formRoute = $scope.routes[0];
    $scope.pickupStations = [$scope.noneStation];
    $scope.destStations = [$scope.noneStation];
    $scope.formPickup = $scope.pickupStations[0];
    $scope.formDest = $scope.destStations[0];
    $scope.routeInfo = {};
    $scope.routeSecTypes = [];

    $scope.formVol = "";
    $scope.formVal = "";
    $scope.formCredit = "";
    $scope.errors = [];
    $scope.status = "Initial";
    $scope.volPrice = undefined;
    $scope.volPriceDesc = "";
    $scope.valPrice = undefined;
    $scope.valPriceDesc = "";
    $scope.containerPrice = undefined;
    $scope.totalPrice = undefined;

    $scope.desc = "";
    $scope.inEve = typeof CCPEVE === "object";

    var url = $scope.location.absUrl();
    var trustUrl = url.substring(0, url.lastIndexOf('/')) + "/*";

    if($scope.inEve) {
      console.log("requesting trust for " + trustUrl);
      var ret = CCPEVE.requestTrust(trustUrl);
    };

  };

  //******************************************************
  // Watches - react to model changes
  //******************************************************

  $scope.$watch('formRoute.name',
      function(newVal, oldVal) {
        console.log("formRoute changed from "+oldVal+" to "+newVal);
        $scope.pickupStations = $scope.filterStations(null);
        $scope.updateStations();
      });

  $scope.$watch('formPickup.id',
      function(newVal, oldVal) {
        $scope.logStationChange("Pickup", newVal, oldVal);
        $scope.updateStations();
      });

  $scope.$watch('formDest.id',
      function(newVal, oldVal) {
        $scope.logStationChange("Destination", newVal, oldVal);
        // Changing the destination station can't change the valid stations, so no
        // need to call updateStations()
        $scope.updateRouteInfo();
      });

  $scope.$watch('[calcForm.vol_input.$error, calcForm.val_input.$error, calcForm.credit_input.$error]',
      function(newVal, oldVal) {
        //console.log("Inputs changed validity:" + JSON.stringify(newVal))
        $scope.updateErrors(newVal, ["Volume", "Value", "Credit"]);
      }, true);

  // Keep the Volume price updated
  $scope.$watch('[routeInfo.volUnit, routeInfo.volCost, formVol, calcForm.vol_input.$valid]',
      function(newVal, oldVal) {
        $scope.updatePrice(
          $scope.routeInfo.volUnit,
          $scope.routeInfo.volCost,
          $scope.calcForm.vol_input,
          "volPrice",
          "volPriceDesc",
          "k m^3");
      }, true);

  // Keep the Value price updated
  $scope.$watch('[routeInfo.valUnit, routeInfo.valCost, formVal, calcForm.val_input.$valid]',
      function(newVal, oldVal) {
        $scope.updatePrice(
          $scope.routeInfo.valUnit,
          $scope.routeInfo.valCost,
          $scope.calcForm.val_input,
          "valPrice",
          "valPriceDesc",
          "Mil ISK");
      }, true);

  // Keep container price updated
  $scope.$watch('formContainer',
      function(newVal, oldVal) {
        console.log("Containers changed: " + newVal);
        $scope.updateContainerPrice();
      });

  // Keep total price updated
  $scope.$watch('[volPrice, valPrice, containerPrice, formCredit]',
      function(newVal, oldVal) {
        $scope.updateTotalPrice();
      }, true);

  //******************************************************
  // Routes and stations
  //******************************************************

  $scope.filterStations = function(skip) {
    var stns = [];
    var routeStns = $scope.routesMeta[$scope.formRoute.name].stns;

    for(var i in routeStns) {
      var routeStn = routeStns[i];
      var stn = $scope.stations[routeStn.id];
      if (skip !== null && skip.id !== "unset" && stn.id === skip.id) {
        continue;
      }
      stns.push(stn);
    };

    if (stns.length === 0) {
      return [$scope.noneStation];
    } else {
      // Prepend the "unset" station to the start of the list
      stns.unshift($scope.unsetStation);
      return stns;
    }
  }

  $scope.updateStations = function() {
    if (!$scope.findStation($scope.formPickup.id, $scope.pickupStations)) {
      // Only change the current pickup station if it isn't valid for the current route
      $scope.formPickup = $scope.pickupStations[0];
    };

    // Recalculate the valid destination stations
    $scope.destStations = $scope.filterStations($scope.formPickup);

    if (!$scope.findStation($scope.formDest.id, $scope.destStations)) {
      // Only change the current pickup station if it isn't valid for the current route
      $scope.formDest = $scope.destStations[0];
    };

    // If there's only one station to choose (not counting the "unset"
    // placeholder), just set destination directly to that
    if ($scope.destStations.length === 2) {
      $scope.formDest = $scope.destStations[1];
    };

    $scope.updateRouteInfo();
  };

  $scope.findStation = function(id, stations) {
    //console.log("findStation: id:"+id);
    var index = $scope.stationIndex(id, stations)
    return stations[index]
  };

  $scope.stationIndex = function(id, stations) {
    //console.log("stationIndex: id:"+id);
    for(var i=0; i < stations.length; i++) {
      var stn = stations[i];
      if(stn.id === id)
        return i;
    };
    return -1;
  };

  $scope.updateRouteInfo = function() {
    var routeInfo = {};
    $scope.routeSecTypes = [];

    var curRouteMeta = $scope.routesMeta[$scope.formRoute.name];
    var pickupIdx = $scope.stationIndex($scope.formPickup.id, curRouteMeta.stns);
    var destIdx = $scope.stationIndex($scope.formDest.id, curRouteMeta.stns);

    console.log(
        "updateRouteInfo: pickup Id:"
        +$scope.formPickup.id
        +" index:"
        +pickupIdx
        +" destination Id:"
        +$scope.formDest.id
        +" index:"
        +destIdx);
    if(pickupIdx < 0 || destIdx < 0) {
      $scope.routeInfo = {};
      return;
    }

    routeInfo.volUnit = curRouteMeta["volUnit"];
    routeInfo.volCost = 0;
    routeInfo.valUnit = curRouteMeta["valUnit"];
    routeInfo.valCost = 0;

    var step = 1;
    var start = pickupIdx;
    var end = destIdx + 1; //So we include the destIdx in the loop
    var valCostName = "valCostNext";
    var volCostName = "volCostNext";
    if (pickupIdx > destIdx) {
      step = -1;
      start = pickupIdx;
      end = destIdx -1; //So we include the pickupIdx in the loop
      valCostName = "valCostPrev";
      volCostName = "volCostPrev";
    };

    for(var i=start; i!=end; i+=step) {
      var stnId = curRouteMeta.stns[i].id;
      var name = $scope.stations[stnId].name;
      $scope.routeSecTypes.push($scope.stations[stnId].sec);
      console.log("Station:"+name);
      if(i !== destIdx) { // Don't include cost of final station.
        if(routeInfo.volUnit) {
          var cost = curRouteMeta.stns[i][volCostName] ||  curRouteMeta.stns[i]["volCost"];
          if(cost !== undefined)
            routeInfo.volCost += cost;
        }
        if(routeInfo.valUnit) {
          var cost = curRouteMeta.stns[i][valCostName] || curRouteMeta.stns[i]["valCost"];
          if(cost !== undefined)
            routeInfo.valCost += cost;
        }
      }
    };

    if(routeInfo.volCost === 0)
      routeInfo.volCost = undefined;
    if(routeInfo.valCost === 0)
      routeInfo.valCost = undefined;
    $scope.routeInfo = routeInfo;

    console.log("route info: "+JSON.stringify($scope.routeInfo));
    console.log("Sec types:"+$scope.routeSecTypes);
  };

  // TODO(kormat): can probably just remove this
  $scope.hasHighsecSection = function() {
    var highsec = 0;
    for(var i=0; i < $scope.routeSecTypes.length; i++) {
      if($scope.routeSecTypes[i] !== "high") {
        highsec = 0;
        continue;
      };
      highsec++;
      if(highsec > 1)
        return true;
    };
    return false;
  };

  //******************************************************
  // Cost calculations
  //******************************************************

  $scope.updatePrice = function(unit, cost, input, price, desc, unitDesc) {
    if(unit === undefined
       || cost === undefined) {
      $scope[price] = undefined;
      $scope[desc] = "";
    } else if(input.$valid === false) {
      $scope[price] = undefined;
    } else {
      $scope[price] = Math.max(1, Math.ceil(input.$modelValue / unit)) * cost;
      $scope[desc] = cost.toFixed(2)
             +"Mil per "
             +unit.toFixed(0)
             +unitDesc;
    };
  };

  $scope.updateContainerPrice = function() {
    if($scope.formContainer)
      $scope.containerPrice = $scope.cfg.rules.containerSurcharge;
    else
      $scope.containerPrice = 0;
  };

  $scope.updateTotalPrice = function() {
    if($scope.errors.length === 0) {
      var price = 0;
      var inputs = [$scope.volPrice, $scope.valPrice, $scope.containerPrice, -$scope.formCredit];
      for(var i=0; i<inputs.length; i++) {
        if(angular.isNumber(inputs[i]))
          price += inputs[i];
      };
      $scope.totalPrice = price;
    } else {
      $scope.totalPrice = undefined;
    };
  };

  $scope.calcDescription = function() {
    $scope.status = "calcDescription()";
    var desc = []
    if($scope.form_val)
      desc.push($scope.form_val+"M value");
    if($scope.creditDiscount)
      desc.push($scope.creditDiscount+"M credit");
    if($scope.form_container)
      desc.push("container");
    $scope.desc = desc.join(", ");
  };

  //******************************************************
  // IGB (In-Game Browser) utility functions
  //******************************************************

  $scope.showStn = function(id) {
    CCPEVE.showInfo(3867, id);
  };

  $scope.showCorp = function() {
    //FIXME(kormat): un-hardcode corp id
    CCPEVE.showInfo(2, 98237970)
  };

  $scope.createContract = function() {
    CCPEVE.createContract(3, $scope.formPickup.id);
  };

  //******************************************************
  // Utility functions
  //******************************************************

  $scope.logStationChange = function(name, newVal, oldVal) {
    console.log(name+" changed from "
      +oldVal
      +"("
      +($scope.stations[oldVal].name || "none")
      +") to "
      +newVal
      +"("
      +($scope.stations[newVal].name || "none")
      +")");
  };

  $scope.updateErrors = function(inputErrors, inputNames) {
    $scope.errors = [];
    for (var i=0; i<inputErrors.length; i++) {
      var inputError = inputErrors[i];
      var inputName = inputNames[i];
      if (inputError['number']) {
        $scope.errors.push(inputName+": not a valid number");
      } else if (inputError['min']) {
        $scope.errors.push(inputName+": too small");
      } else if (inputError['max']) {
        $scope.errors.push(inputName+": too large");
      }
    };
  }

  //Now that everything is defined, finally call init()
  $scope.init();
}]);
<|endoftext|>


<commit_before>/**
* Copyright 2010 PolicyPad
*
* 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.
*/

/**
 * Takes oldText and applies the given changeset to it.
 * @param {String} oldText The original text to modify.
 * @param {String} changeset The changeset to apply the document
 * @return A new document, transformed by the changeset
 */
function applyChangeset(oldText, changeset) {
  var trueChangeset = changeset;
  var res = '';
  var parts = changeset.split('$');

  if (changeset.substring(0,2) != "Z:")  {
      return null;
  }
  if (parts.length != 2) {
      return null;
  }

  var bank = parts[1];
  changeset = parts[0].substring(2);

  convBase36 = function(str) { return parseInt(str, 36); }

  parts = changeset.match(/^(\w+)([><])(\w+)/);
  if (!parts) {
    return null;
  }
  oldlen = convBase36(parts[1]);
  newlen = convBase36(parts[3]);
  switch (parts[2])
  {
    case '<':
      newlen = oldlen - newlen;
      break;
    case '>':
      newlen += oldlen;
      break;
    default:
      return null;
  }

  if (oldText.length != oldlen) {
    return null;
  }

  changeset = changeset.substring(parts[0].length);

  function OpIterator(changeset) {
    this._lens = changeset.split(/[|=+*-]/);
    this._ops = changeset.split(/\w+/);
    this._lens.shift();
    this._ops.pop();
  }
  OpIterator.prototype.next = function() {
    if (this._lens.length == 0)
      throw StopIteration;
    return {op: this._ops.shift(), len: convBase36(this._lens.shift())};
  }
  OpIterator.prototype.__iterator__ = function() { return this; }

  var ops = new OpIterator(changeset);
  var i = 0;
  var attribs = [];
  var newlines = 0;
  for (var part in ops) {
    switch (part.op) {
      case '=':
        change = oldText.substring(i, i + part.len);
        if (change.split('\n').length-1 != newlines) {
          return null;
        }
        res += change;
        i += part.len;
        newlines = 0;
        break;
      case '*':
        //TODO: update attribs
        break;
      case '|':
        newlines = part.len;
        break;
      case '+':
        res += bank.substring(0, part.len);
        bank = bank.substring(part.len);
        break;
      case '-':
        if (oldText.substring(i, i + part.len).split('\n').length-1 != newlines) {
          return null;
        }
        i += part.len;
        newlines = 0;
        break;
    }
  }

  //The rest of the document is unchanged
  res += oldText.substring(i);

  if (res.length != newlen) {
    return null;
  }

  return res;
}

/**
 * Generates a changeset that conveys the changes from the old text (o)
 * to the new text (n)
 *
 * Based on John Resig's JavaScript diff algorithm
 */
function generateChangeset(o,n){

    function _newlines(t) {
        var newlines = t.match(/\n/);
        if (newlines == null) {
            return "";
        }
        return '|' + newlines.length;
    }

    function _diff(o,n){
        var ns={},os={},i,x=null
        for(i=0;i<n.length;i++){if(ns[n[i]]==x)ns[n[i]]={rows:[],o:x};ns[n[i]].rows.push(i)}
        for(i=0;i<o.length;i++){if(os[o[i]]==x)os[o[i]]={rows:[],n:x};os[o[i]].rows.push(i)}
        for(i in ns){
            if(ns[i].rows.length==1 && typeof(os[i])!='undefined' && os[i].rows.length==1){
                n[ns[i].rows[0]]={text:n[ns[i].rows[0]],row:os[i].rows[0]}
                o[os[i].rows[0]]={text:o[os[i].rows[0]],row:ns[i].rows[0]}
            }
        }
        for(i=0;i<n.length-1;i++){
            if(n[i].text!=x && n[i+1].text==x && n[i].row+1<o.length && o[n[i].row+1].text==x &&
            n[i+1]==o[n[i].row+1]){
                n[i+1]={text:n[i+1],row:n[i].row+1}
                o[n[i].row+1]={text:o[n[i].row+1],row:i+1}
            }
        }
        for(i=n.length-1;i>0;i--){
            if(n[i].text!=x && n[i-1].text==x && n[i].row>0 && o[n[i].row-1].text==x &&
            n[i-1]==o[n[i].row-1]){
                n[i-1]={text:n[i-1],row:n[i].row-1}
                o[n[i].row-1]={text:o[n[i].row-1],row:i-1}
            }
        }
        return {o:o,n:n}
    }

    var packNum = function(num) { return num.toString(36).toLowerCase(); };
    var out = _diff(o == '' ? [] : o.split(/\s+/), n== '' ? [] : n.split(/\s+/));
    var str = 'Z:' + packNum(o.length);
    str += n.length > o.length
        ? '>' + packNum(n.length - o.length)
        : '<' + packNum(o.length - n.length);
    var pot = '';
    var i;
    var x = null;
    var pre;
    var currentText;
    var oSpace = o.match(/\s+/g);
    var nSpace = n.match(/\s+/g);
    var start = true;

    if (oSpace == x) {
        oSpace=[];
    }

    if (nSpace == x) {
        nSpace=[];
    }

    if (out.n.length==0) {
        for(i=0; i<out.o.length; i++) {
            currentText = out.o[i] + (i >= oSpace.length ? '' : oSpace[i]);
            str += _newlines(currentText) + '-' + packNum(currentText.length);
            start = false;
        }
    }
    else {
        if (out.n[0].text==x) {
            for(n=0; n<out.o.length && out.o[n].text==x; n++) {
                currentText = out.o[n] + (n >= oSpace.length ? '' : oSpace[n]);
                str += _newlines(currentText) + '-' + packNum(currentText.length);
                start = false;
            }
        }
        for (i=0; i<out.n.length; i++) {
            if (out.n[i].text==x) {
                currentText = out.n[i] + (i >= nSpace.length ? '' : nSpace[i]);
                str += '*0' + _newlines(currentText) + '+' + packNum(currentText.length);
                pot += currentText;
                start = false;
            }
            else {
                pre='';
                for (n=out.n[i].row+1; n<out.o.length && out.o[n].text==x; n++) {
                    currentText = out.o[n] + (n >= oSpace.length ? '' : oSpace[n]);
                    pre += '-' + packNum(currentText.length);
                }
                currentText = (start ? '' : " ") + out.n[i].text + (i >= nSpace.length ? '' : nSpace[i]);
                start = false;
                str += _newlines(currentText) + '=' + packNum(currentText.length) + pre;
            }
        }
    }
    return str + '$' + pot;
}

function mergeChangeset(cs1, cs2) {
    // TODO: Check if code like this already exists
    // Particularly check changeset.js in same directory - written by our team???
    return '';
}
<commit_msg>Fix the double newline bug<commit_after>/**
* Copyright 2010 PolicyPad
*
* 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.
*/

/**
 * Takes oldText and applies the given changeset to it.
 * @param {String} oldText The original text to modify.
 * @param {String} changeset The changeset to apply the document
 * @return A new document, transformed by the changeset
 */
function applyChangeset(oldText, changeset) {
  var trueChangeset = changeset;
  var res = '';
  var parts = changeset.split('$');

  if (changeset.substring(0,2) != "Z:")  {
      return null;
  }
  if (parts.length != 2) {
      return null;
  }

  var bank = parts[1];
  changeset = parts[0].substring(2);

  convBase36 = function(str) { return parseInt(str, 36); }

  parts = changeset.match(/^(\w+)([><])(\w+)/);
  if (!parts) {
    return null;
  }
  oldlen = convBase36(parts[1]);
  newlen = convBase36(parts[3]);
  switch (parts[2])
  {
    case '<':
      newlen = oldlen - newlen;
      break;
    case '>':
      newlen += oldlen;
      break;
    default:
      return null;
  }

  if (oldText.length != oldlen) {
    return null;
  }

  changeset = changeset.substring(parts[0].length);

  function OpIterator(changeset) {
    this._lens = changeset.split(/[|=+*-]/);
    this._ops = changeset.split(/\w+/);
    this._lens.shift();
    this._ops.pop();
  }
  OpIterator.prototype.next = function() {
    if (this._lens.length == 0)
      throw StopIteration;
    return {op: this._ops.shift(), len: convBase36(this._lens.shift())};
  }
  OpIterator.prototype.__iterator__ = function() { return this; }

  var ops = new OpIterator(changeset);
  var i = 0;
  var attribs = [];
  var newlines = 0;
  for (var part in ops) {
    switch (part.op) {
      case '=':
        change = oldText.substring(i, i + part.len);
        if (change.split('\n').length-1 != newlines) {
          return null;
        }
        res += change;
        i += part.len;
        newlines = 0;
        break;
      case '*':
        //TODO: update attribs
        break;
      case '|':
        newlines = part.len;
        break;
      case '+':
        res += bank.substring(0, part.len);
        bank = bank.substring(part.len);
        break;
      case '-':
        if (oldText.substring(i, i + part.len).split('\n').length-1 != newlines) {
          return null;
        }
        i += part.len;
        newlines = 0;
        break;
    }
  }

  //The rest of the document is unchanged
  res += oldText.substring(i);

  if (res.length != newlen) {
    return null;
  }

  return res;
}

/**
 * Generates a changeset that conveys the changes from the old text (o)
 * to the new text (n)
 *
 * Based on John Resig's JavaScript diff algorithm
 */
function generateChangeset(o,n){

    function _newlines(t) {
        var newlines = t.match(/\n/g);
        if (newlines == null) {
            return "";
        }
        return '|' + newlines.length;
    }

    function _diff(o,n){
        var ns={},os={},i,x=null
        for(i=0;i<n.length;i++){if(ns[n[i]]==x)ns[n[i]]={rows:[],o:x};ns[n[i]].rows.push(i)}
        for(i=0;i<o.length;i++){if(os[o[i]]==x)os[o[i]]={rows:[],n:x};os[o[i]].rows.push(i)}
        for(i in ns){
            if(ns[i].rows.length==1 && typeof(os[i])!='undefined' && os[i].rows.length==1){
                n[ns[i].rows[0]]={text:n[ns[i].rows[0]],row:os[i].rows[0]}
                o[os[i].rows[0]]={text:o[os[i].rows[0]],row:ns[i].rows[0]}
            }
        }
        for(i=0;i<n.length-1;i++){
            if(n[i].text!=x && n[i+1].text==x && n[i].row+1<o.length && o[n[i].row+1].text==x &&
            n[i+1]==o[n[i].row+1]){
                n[i+1]={text:n[i+1],row:n[i].row+1}
                o[n[i].row+1]={text:o[n[i].row+1],row:i+1}
            }
        }
        for(i=n.length-1;i>0;i--){
            if(n[i].text!=x && n[i-1].text==x && n[i].row>0 && o[n[i].row-1].text==x &&
            n[i-1]==o[n[i].row-1]){
                n[i-1]={text:n[i-1],row:n[i].row-1}
                o[n[i].row-1]={text:o[n[i].row-1],row:i-1}
            }
        }
        return {o:o,n:n}
    }

    var packNum = function(num) { return num.toString(36).toLowerCase(); };
    var out = _diff(o == '' ? [] : o.split(/\s+/), n== '' ? [] : n.split(/\s+/));
    var str = 'Z:' + packNum(o.length);
    str += n.length > o.length
        ? '>' + packNum(n.length - o.length)
        : '<' + packNum(o.length - n.length);
    var pot = '';
    var i;
    var x = null;
    var pre;
    var currentText;
    var oSpace = o.match(/\s+/g);
    var nSpace = n.match(/\s+/g);
    var start = true;

    if (oSpace == x) {
        oSpace=[];
    }

    if (nSpace == x) {
        nSpace=[];
    }

    if (out.n.length==0) {
        for(i=0; i<out.o.length; i++) {
            currentText = out.o[i] + (i >= oSpace.length ? '' : oSpace[i]);
            str += _newlines(currentText) + '-' + packNum(currentText.length);
            start = false;
        }
    }
    else {
        if (out.n[0].text==x) {
            for(n=0; n<out.o.length && out.o[n].text==x; n++) {
                currentText = out.o[n] + (n >= oSpace.length ? '' : oSpace[n]);
                str += _newlines(currentText) + '-' + packNum(currentText.length);
                start = false;
            }
        }
        for (i=0; i<out.n.length; i++) {
            if (out.n[i].text==x) {
                currentText = out.n[i] + (i >= nSpace.length ? '' : nSpace[i]);
                str += '*0' + _newlines(currentText) + '+' + packNum(currentText.length);
                pot += currentText;
                start = false;
            }
            else {
                pre='';
                for (n=out.n[i].row+1; n<out.o.length && out.o[n].text==x; n++) {
                    currentText = out.o[n] + (n >= oSpace.length ? '' : oSpace[n]);
                    pre += '-' + packNum(currentText.length);
                }
                currentText = (start ? '' : " ") + out.n[i].text + (i >= nSpace.length ? '' : nSpace[i]);
                start = false;
                str += _newlines(currentText) + '=' + packNum(currentText.length) + pre;
            }
        }
    }
    return str + '$' + pot;
}

function mergeChangeset(cs1, cs2) {
    // TODO: Check if code like this already exists
    // Particularly check changeset.js in same directory - written by our team???
    return '';
}
<|endoftext|>


<commit_before>MODEL({
  name: 'mdDetailView',
  extendsModel: 'DetailView',

  properties: [
    {
      name: 'className',
      defaultValue: 'mdDetailView'
    }
  ],
  methods: {
    init: function() {
      // Register MD PropertyViews
      this.X = this.X.sub();
      this.X.registerModel(mdTextFieldView, 'TextFieldView');
      this.X.registerModel(mdIntFieldView, 'IntFieldView');
      this.SUPER();
    },
    titleHTML:    function() { return ''; },
    startForm:    function() { return ''; },
    endForm:      function() { return ''; },
    startColumns: function() { return ''; },
    nextColumn:   function() { return ''; },
    endColumns:   function() { return ''; },
    rowToHTML: function(prop, view) {
      /* HTML formatter for each $$DOC{ref:'Property'} row. */
      var str = "";

      str += view.toHTML();
      str += '
';

      return str;
    }
  }

});

MODEL({
  name: 'mdTextFieldView',
  extendsModel: 'View',

  properties: [
    {
      name: 'className',
      defaultValue: 'md-text-field-container'
    },
    { name: 'data' },
    { name: 'softData' },
    { name: 'inputId' },
    { name: '$input', getter: function() { return this.X.$(this.inputId); } },
    { name: 'labelId' },
    { name: '$label', getter: function() { return this.X.$(this.labelId); } },
    { model_: 'BooleanProperty', name: 'focused', defaultValue: false },
    'label'
  ],
  methods: {
    initHTML: function() {
      this.SUPER();
      this.softValue = DomValue.create(this.$input, 'input');
      this.softValue.set(this.data);
      Events.link(this.data$, this.softValue);
    }
  },
  templates: [
    function CSS() {/*
    .md-text-field-container {
      width: 100%;
      display: flex;
      position: relative;
    }
    .md-text-field-label {
      position: absolute;
      top: 40px;
      font-size: 16px;
      transition: font-size 0.5s, top 0.5s;
      flex-grow: 1;
      opacity: 0.3;
      z-index: 0;
    }
    .md-text-field-input {
      font-size: 16px;
      flex-grow: 1;
      z-index: 1;
      background: transparent;
      border: none;
      border-bottom: 1px solid #B3E5FC;
      margin: 0 0 8px 0;
      padding: 40px 0 7 0;
    }
    .md-text-field-input:focus {
      border-bottom: 2px solid #0288D1;
      padding: 40px 0 6 0;
      outline: none;
    }
    .md-text-field-label-offset {
      font-size: 12px;
      top: 16px;
    }
    */},
    function toHTML() {/*
      <%
        var input = this.inputId = this.nextID();
        this.on('focus', this.onFocus, input);
        this.on('blur', this.onBlur, input);
        this.on('input', this.onInput, input);
        this.on('change', this.onChange, input);
        this.on('click', this.onClick, input);
        this.on('keydown', this.onKeyDown, input);
        var label = this.labelId = this.nextID();
        this.setClass('md-text-field-label-offset',
          function() {
            var focused = self.focused;
            var data = self.data;
            return focused || ('' + data).length > 0;
          }, label);
      %>

        <label id="<%= label %>" class="md-text-field-label"><%= escapeHTML(this.label) %>Label
        <input id="<%= input %>" type="text" class="md-text-field-input">

    */}
  ],

  listeners: [
    {
      name: 'onFocus',
      code: function() {
        this.focused = true;
      }
    },
    {
      name: 'onBlur',
      code: function() {
        this.focused = false;
      }
    },
    {
      name: 'onInput',
      code: function() {
      }
    },
    {
      name: 'onChange',
      code: function() {
        this.data = this.softData;
      }
    },
    {
      name: 'onKeyDown',
      code: function() {
      }
    },
    {
      name: 'onClick',
      code: function() {
        this.$input.focus();
      }
    }
  ]
});

MODEL({
  name: 'mdIntFieldView',
  extendsModel: 'mdTextFieldView'
});
<commit_msg>Fixed mdTextFieldView label.<commit_after>MODEL({
  name: 'mdDetailView',
  extendsModel: 'DetailView',

  properties: [
    {
      name: 'className',
      defaultValue: 'mdDetailView'
    }
  ],
  methods: {
    init: function() {
      // Register MD PropertyViews
      this.X = this.X.sub();
      this.X.registerModel(mdTextFieldView, 'TextFieldView');
      this.X.registerModel(mdIntFieldView,  'IntFieldView');
      this.SUPER();
    },
    titleHTML:    function() { return ''; },
    startForm:    function() { return ''; },
    endForm:      function() { return ''; },
    startColumns: function() { return ''; },
    nextColumn:   function() { return ''; },
    endColumns:   function() { return ''; },
    rowToHTML: function(prop, view) {
      /* HTML formatter for each $$DOC{ref:'Property'} row. */
      var str = "";

      str += view.toHTML();
      str += '
';

      return str;
    }
  }

});

MODEL({
  name: 'mdTextFieldView',
  extendsModel: 'View',

  properties: [
    {
      name: 'className',
      defaultValue: 'md-text-field-container'
    },
    { name: 'data' },
    { name: 'softData' },
    { name: 'inputId' },
    { name: '$input', getter: function() { return this.X.$(this.inputId); } },
    { name: 'labelId' },
    { name: '$label', getter: function() { return this.X.$(this.labelId); } },
    { model_: 'BooleanProperty', name: 'focused', defaultValue: false },
    { name: 'label', defaultValueFn: function() { return this.prop.label; } }
  ],
  methods: {
    initHTML: function() {
      this.SUPER();
      this.softValue = DomValue.create(this.$input, 'input');
      this.softValue.set(this.data);
      Events.link(this.data$, this.softValue);
    }
  },
  templates: [
    function CSS() {/*
    .md-text-field-container {
      width: 100%;
      display: flex;
      position: relative;
    }
    .md-text-field-label {
      position: absolute;
      top: 40px;
      font-size: 16px;
      transition: font-size 0.5s, top 0.5s;
      flex-grow: 1;
      opacity: 0.3;
      z-index: 0;
    }
    .md-text-field-input {
      font-size: 16px;
      flex-grow: 1;
      z-index: 1;
      background: transparent;
      border: none;
      border-bottom: 1px solid #B3E5FC;
      margin: 0 0 8px 0;
      padding: 40px 0 7 0;
    }
    .md-text-field-input:focus {
      border-bottom: 2px solid #0288D1;
      padding: 40px 0 6 0;
      outline: none;
    }
    .md-text-field-label-offset {
      font-size: 12px;
      top: 16px;
    }
    */},
    function toHTML() {/*
      <%
        var input = this.inputId = this.nextID();
        this.on('focus',   this.onFocus, input);
        this.on('blur',    this.onBlur, input);
        this.on('input',   this.onInput, input);
        this.on('change',  this.onChange, input);
        this.on('click',   this.onClick, input);
        this.on('keydown', this.onKeyDown, input);
        var label = this.labelId = this.nextID();
        this.setClass('md-text-field-label-offset',
          function() {
            var focused = self.focused;
            var data = self.data;
            return focused || ('' + data).length > 0;
          }, label);
      %>

        <label id="<%= label %>" class="md-text-field-label">{{this.label}}
        <input id="<%= input %>" type="text" class="md-text-field-input">

    */}
  ],

  listeners: [
    {
      name: 'onFocus',
      code: function() {
        this.focused = true;
      }
    },
    {
      name: 'onBlur',
      code: function() {
        this.focused = false;
      }
    },
    {
      name: 'onInput',
      code: function() {
      }
    },
    {
      name: 'onChange',
      code: function() {
        this.data = this.softData;
      }
    },
    {
      name: 'onKeyDown',
      code: function() {
      }
    },
    {
      name: 'onClick',
      code: function() {
        this.$input.focus();
      }
    }
  ]
});

MODEL({
  name: 'mdIntFieldView',
  extendsModel: 'mdTextFieldView'
});
<|endoftext|>


<commit_before>var EXPORTED_SYMBOLS = ['initScriptProtocol'];

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import('chrome://greasemonkey-modules/content/util.js');

var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
var schemeName = 'greasemonkey-script';

var gHaveDoneInit = false;
var gScope = this;

function initScriptProtocol() {
  if (gHaveDoneInit) return;
  gHaveDoneInit = true;
  ScriptProtocol.init();
}

////////////////////////////////////////////////////////////////////////////////

function DummyChannel(aUri, aScript) {
  // nsIRequest
  this.loadFlags = 0;
  this.loadGroup = null;
  this.name = aUri.spec;
  this.status = 404;
  this.content = '';

  // nsIChannel
  this.contentCharset = 'utf-8';
  this.contentLength = this.content.length;
  this.contentType = 'application/javascript';
  this.notificationCallbacks = null;
  this.originalURI = aUri;
  this.owner = null;
  this.securityInfo = null;
  this.URI = aUri;
}

// nsIChannel
DummyChannel.prototype.asyncOpen = function(aListener, aContext) { };

////////////////////////////////////////////////////////////////////////////////

var ScriptProtocol = {
  _classDescription: 'Protocol handler for "greasemonkey-script:"',
  _classID: Components.ID('20d898f3-2fb8-4b3a-b8c7-7ad6c2c48598'),
  _contractID:  '@mozilla.org/network/protocol;1?name=' + schemeName,

  QueryInterface: XPCOMUtils.generateQI([
      Ci.nsIFactory,
      Ci.nsIProtocolHandler,
      Ci.nsISupportsWeakReference
      ]),

  init: function() {
    try {
      var registrar = Components.manager.QueryInterface(
          Ci.nsIComponentRegistrar);
      registrar.registerFactory(
          this._classID, this._classDescription, this._contractID, this);
    } catch (e) {
      if ('NS_ERROR_FACTORY_EXISTS' == e.name) {
        // No-op, ignore these.  But why do they happen!?
      } else {
        dump('Error registering ScriptProtocol factory:\n' + e + '\n');
      }
      return;
    };
  },

////////////////////////////////// nsIFactory //////////////////////////////////

  createInstance: function(outer, iid) {
    if (outer) {
      throw Cr.NS_ERROR_NO_AGGREGATION;
    }
    return this.QueryInterface(iid);
  },

////////////////////////////// nsIProtocolHandler //////////////////////////////

  scheme: schemeName,
  defaultPort: -1,
  protocolFlags: 0
      | Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT
      | Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE
      | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE
      | Ci.nsIProtocolHandler.URI_NOAUTH
      | Ci.nsIProtocolHandler.URI_NON_PERSISTABLE
      | Ci.nsIProtocolHandler.URI_NORELATIVE
      ,

  allowPort: function(aPort, aScheme) {
    return false;
  },

  newURI: function(aSpec, aCharset, aBaseUri) {
    var uri = Cc['@mozilla.org/network/simple-uri;1']
        .createInstance(Ci.nsIURI);
    uri.spec = aSpec;
    return uri;
  },

  newChannel: function(aUri) {
    var m = aUri.spec.match(/greasemonkey-script:([-0-9a-f]+)\/(.*)/);
    var dummy = new DummyChannel(aUri);

    // Incomplete URI, send a 404.
    if (!m) return dummy;

    var script = null;
    // If we're serving (e.g.) a favicon image, this request can be coming
    // from the parent process!
    var runtime = Cc["@mozilla.org/xre/app-info;1"]
        .getService(Ci.nsIXULRuntime);
    if (runtime.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
      var scripts = GM_util.getService().config.getMatchingScripts(
          function(script) { return script.uuid == m[1]; }
      );
      script = scripts && scripts.length && scripts[0];
    } else {
      var mm = Cc["@mozilla.org/childprocessmessagemanager;1"]
          .getService(Ci.nsISyncMessageSender);
      var response = mm.sendSyncMessage(
          'greasemonkey:scripts-for-uuid', {'uuid': m[1]});
      // We expect exactly one response, listing exactly one script.
      if (response.length != 1) return dummy;
      if (response[0].length != 1) return dummy;
      script = response[0][0];
    }

    // Fail fast if we couldn't find the script.
    if (!script) return dummy;

    for (var i = 0, resource = null; resource = script.resources[i]; i++) {
      if (resource.name == m[2]) {
        var uri = null;
        if (resource.url) {
          // In child scope, IPCScript gives us the URL to the file.
          uri = GM_util.uriFromUrl(resource.url);
        } else {
          // In parent scope we have the raw script, with file intact.
          uri = GM_util.getUriFromFile(resource.file);
        }

        // Get the channel for the file URI, but set its originalURI to the
        // greasemonkey-script: protocol URI, to ensure it can still be loaded
        // in unprivileged contexts (bug #2326).
        var channel = GM_util.channelFromUri(uri);
        channel.originalURI = aUri;

        return channel;
      }
    }

    // Default fall-through case, send a 404.
    return dummy;
  }
};
<commit_msg>Fix @resource<commit_after>var EXPORTED_SYMBOLS = ['initScriptProtocol'];

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import('chrome://greasemonkey-modules/content/util.js');

var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
var schemeName = 'greasemonkey-script';

var gHaveDoneInit = false;
var gScope = this;

function initScriptProtocol() {
  if (gHaveDoneInit) return;
  gHaveDoneInit = true;
  ScriptProtocol.init();
}

////////////////////////////////////////////////////////////////////////////////

function DummyChannel(aUri, aScript) {
  // nsIRequest
  this.loadFlags = 0;
  this.loadGroup = null;
  this.name = aUri.spec;
  this.status = 404;
  this.content = '';

  // nsIChannel
  this.contentCharset = 'utf-8';
  this.contentLength = this.content.length;
  this.contentType = 'application/javascript';
  this.notificationCallbacks = null;
  this.originalURI = aUri;
  this.owner = null;
  this.securityInfo = null;
  this.URI = aUri;
}

// nsIChannel
DummyChannel.prototype.asyncOpen = function(aListener, aContext) { };

////////////////////////////////////////////////////////////////////////////////

var ScriptProtocol = {
  _classDescription: 'Protocol handler for "greasemonkey-script:"',
  _classID: Components.ID('20d898f3-2fb8-4b3a-b8c7-7ad6c2c48598'),
  _contractID:  '@mozilla.org/network/protocol;1?name=' + schemeName,

  QueryInterface: XPCOMUtils.generateQI([
      Ci.nsIFactory,
      Ci.nsIProtocolHandler,
      Ci.nsISupportsWeakReference
      ]),

  init: function() {
    try {
      var registrar = Components.manager.QueryInterface(
          Ci.nsIComponentRegistrar);
      registrar.registerFactory(
          this._classID, this._classDescription, this._contractID, this);
    } catch (e) {
      if ('NS_ERROR_FACTORY_EXISTS' == e.name) {
        // No-op, ignore these.  But why do they happen!?
      } else {
        dump('Error registering ScriptProtocol factory:\n' + e + '\n');
      }
      return;
    };
  },

////////////////////////////////// nsIFactory //////////////////////////////////

  createInstance: function(outer, iid) {
    if (outer) {
      throw Cr.NS_ERROR_NO_AGGREGATION;
    }
    return this.QueryInterface(iid);
  },

////////////////////////////// nsIProtocolHandler //////////////////////////////

  scheme: schemeName,
  defaultPort: -1,
  protocolFlags: 0
      | Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT
      | Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE
      | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE
      | Ci.nsIProtocolHandler.URI_NOAUTH
      | Ci.nsIProtocolHandler.URI_NON_PERSISTABLE
      | Ci.nsIProtocolHandler.URI_NORELATIVE
      ,

  allowPort: function(aPort, aScheme) {
    return false;
  },

  newURI: function(aSpec, aCharset, aBaseUri) {
    var uri = Cc['@mozilla.org/network/simple-uri;1']
        .createInstance(Ci.nsIURI);
    uri.spec = aSpec;
    return uri;
  },

  newChannel: function(aUri) {
    var m = aUri.spec.match(/greasemonkey-script:([-0-9a-f]+)\/(.*)/);
    var dummy = new DummyChannel(aUri);

    // Incomplete URI, send a 404.
    if (!m) return dummy;

    var script = null;
    // If we're serving (e.g.) a favicon image, this request can be coming
    // from the parent process!
    var runtime = Cc["@mozilla.org/xre/app-info;1"]
        .getService(Ci.nsIXULRuntime);
    if (runtime.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
      var scripts = GM_util.getService().config.getMatchingScripts(
          function(script) { return script.uuid == m[1]; }
      );
      script = scripts && scripts.length && scripts[0];
    } else {
      var mm = Cc["@mozilla.org/childprocessmessagemanager;1"]
          .getService(Ci.nsISyncMessageSender);
      var response = mm.sendSyncMessage(
          'greasemonkey:scripts-for-uuid', {'uuid': m[1]});
      // We expect exactly one response, listing exactly one script.
      if (response.length != 1) return dummy;
      if (response[0].length != 1) return dummy;
      script = response[0][0];
    }

    // Fail fast if we couldn't find the script.
    if (!script) return dummy;

    for (var i = 0, resource = null; resource = script.resources[i]; i++) {
      if (resource.name == m[2]) {
        var uri = null;
        if (resource.file_url) {
          // In child scope, IPCScript gives us the URL to the file.
          uri = GM_util.uriFromUrl(resource.file_url);
        } else {
          // In parent scope we have the raw script, with file intact.
          uri = GM_util.getUriFromFile(resource.file);
        }

        // Get the channel for the file URI, but set its originalURI to the
        // greasemonkey-script: protocol URI, to ensure it can still be loaded
        // in unprivileged contexts (bug #2326).
        var channel = GM_util.channelFromUri(uri);
        channel.originalURI = aUri;

        return channel;
      }
    }

    // Default fall-through case, send a 404.
    return dummy;
  }
};
<|endoftext|>


<commit_before>const babelConfig = require('babel-preset-hobbes');
const babelJest = require('babel-jest');

module.exports = babelJest.createTransformer(babelConfig);
<commit_msg>:bug: more namespace fixes<commit_after>const babelConfig = require('@shanewilson/babel-preset-hobbes');
const babelJest = require('babel-jest');

module.exports = babelJest.createTransformer(babelConfig);
<|endoftext|>


<commit_before>'use strict';

var Backbone = require('backbone');
var _ = require("lodash");
var fs = require("fs");
var $ = require("jquery");
require('swiper');
var template = fs.readFileSync(__dirname + '/../templates/main.ejs', 'utf8');

module.exports = Backbone.View.extend({
  className: 'o-feature-slider',
  showcaseItems: [],

  render: function render() {
    this.$el.html(_.template(template)({
      items: this.showcaseItems,
    }));
    return this;
  },

  initSwiper: function() {
    // Needs to be triggered after Virtual DOM is attached.
    if (this.$('.swiper-container').length) {
      this.swiper = new Swiper('.swiper-container', {
          pagination: '.swiper-pagination',
          paginationClickable: true,
          preventClicks: false,
          nextButton: '.swiper-button-next',
          prevButton: '.swiper-button-prev',
          keyboardControl: true,
          autoplay: 5000,
      });
    }
  },

  getShowcaseItems: function getShowcaseItems() {
    // Return maximum of 5 episodes to showcase on the main page.
    $.getJSON('/api/v1.0/episodes/released')
      .done((data) => {
        console.log(data)
        this.showcaseItems = data.items;
        this.render();
        this.initSwiper();
      });
  },
});
<commit_msg>Fix slider api call.<commit_after>'use strict';

var Backbone = require('backbone');
var _ = require("lodash");
var fs = require("fs");
var $ = require("jquery");
require('swiper');
var template = fs.readFileSync(__dirname + '/../templates/main.ejs', 'utf8');

module.exports = Backbone.View.extend({
  className: 'o-feature-slider',
  episodes: [],

  render: function render() {
    this.$el.html(_.template(template)({
      items: this.episodes,
    }));
    return this;
  },

  initSwiper: function initSwiper() {
    // Needs to be triggered after Virtual DOM is attached.
    if (this.$('.swiper-container').length) {
      this.swiper = new Swiper('.swiper-container', {
        pagination: '.swiper-pagination',
        paginationClickable: true,
        preventClicks: false,
        nextButton: '.swiper-button-next',
        prevButton: '.swiper-button-prev',
        keyboardControl: true,
        autoplay: 5000,
      });
    }
  },

  getShowcaseItems: function getShowcaseItems() {
    // Return maximum of 5 episodes to showcase on the main page.
    $.getJSON('/api/v1.0/episodes/released?length=5&showcase=true')
      .done((data) => {
        console.log(data)
        this.episodes = data.episodes;
        this.render();
        this.initSwiper();
      });
  },
});
<|endoftext|>