diff --git a/external/KML.js b/external/KML.js
new file mode 100755
index 00000000..22659777
--- /dev/null
+++ b/external/KML.js
@@ -0,0 +1,336 @@
+/*global L: true */
+
+L.KML = L.FeatureGroup.extend({
+ options: {
+ async: true
+ },
+
+ initialize: function(kml, options) {
+ L.Util.setOptions(this, options);
+ this._kml = kml;
+ this._layers = {};
+
+ if (kml) {
+ this.addKML(kml, options, this.options.async);
+ }
+ },
+
+ loadXML: function(url, cb, options, async) {
+ if (async == undefined) async = this.options.async;
+ if (options == undefined) options = this.options;
+
+ var req = new window.XMLHttpRequest();
+ req.open('GET', url, async);
+ try {
+ req.overrideMimeType('text/xml'); // unsupported by IE
+ } catch(e) {}
+ req.onreadystatechange = function() {
+ if (req.readyState != 4) return;
+ if(req.status == 200) cb(req.responseXML, options);
+ };
+ req.send(null);
+ },
+
+ addKML: function(url, options, async) {
+ var _this = this;
+ var cb = function(gpx, options) { _this._addKML(gpx, options) };
+ this.loadXML(url, cb, options, async);
+ },
+
+ _addKML: function(xml, options) {
+ var layers = L.KML.parseKML(xml);
+ if (!layers || !layers.length) return;
+ for (var i = 0; i < layers.length; i++)
+ {
+ this.fire('addlayer', {
+ layer: layers[i]
+ });
+ this.addLayer(layers[i]);
+ }
+ this.latLngs = L.KML.getLatLngs(xml);
+ this.fire("loaded");
+ },
+
+ latLngs: []
+});
+
+L.Util.extend(L.KML, {
+
+ parseKML: function (xml) {
+ var style = this.parseStyle(xml);
+ var el = xml.getElementsByTagName("Folder");
+ var layers = [], l;
+ for (var i = 0; i < el.length; i++) {
+ if (!this._check_folder(el[i])) { continue; }
+ l = this.parseFolder(el[i], style);
+ if (l) { layers.push(l); }
+ }
+ el = xml.getElementsByTagName('Placemark');
+ for (var j = 0; j < el.length; j++) {
+ if (!this._check_folder(el[j])) { continue; }
+ l = this.parsePlacemark(el[j], xml, style);
+ if (l) { layers.push(l); }
+ }
+ return layers;
+ },
+
+ // Return false if e's first parent Folder is not [folder]
+ // - returns true if no parent Folders
+ _check_folder: function (e, folder) {
+ e = e.parentElement;
+ while (e && e.tagName !== "Folder")
+ {
+ e = e.parentElement;
+ }
+ return !e || e === folder;
+ },
+
+ parseStyle: function (xml) {
+ var style = {};
+ var sl = xml.getElementsByTagName("Style");
+
+ //for (var i = 0; i < sl.length; i++) {
+ var attributes = {color: true, width: true, Icon: true, href: true,
+ hotSpot: true};
+
+ function _parse(xml) {
+ var options = {};
+ for (var i = 0; i < xml.childNodes.length; i++) {
+ var e = xml.childNodes[i];
+ var key = e.tagName;
+ if (!attributes[key]) { continue; }
+ if (key === 'hotSpot')
+ {
+ for (var j = 0; j < e.attributes.length; j++) {
+ options[e.attributes[j].name] = e.attributes[j].nodeValue;
+ }
+ } else {
+ var value = e.childNodes[0].nodeValue;
+ if (key === 'color') {
+ options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
+ options.color = "#" + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4);
+ } else if (key === 'width') {
+ options.weight = value;
+ } else if (key === 'Icon') {
+ ioptions = _parse(e);
+ if (ioptions.href) { options.href = ioptions.href; }
+ } else if (key === 'href') {
+ options.href = value;
+ }
+ }
+ }
+ return options;
+ }
+
+ for (var i = 0; i < sl.length; i++) {
+ var e = sl[i], el;
+ var options = {}, poptions = {}, ioptions = {};
+ el = e.getElementsByTagName("LineStyle");
+ if (el && el[0]) { options = _parse(el[0]); }
+ el = e.getElementsByTagName("PolyStyle");
+ if (el && el[0]) { poptions = _parse(el[0]); }
+ if (poptions.color) { options.fillColor = poptions.color; }
+ if (poptions.opacity) { options.fillOpacity = poptions.opacity; }
+ el = e.getElementsByTagName("IconStyle");
+ if (el && el[0]) { ioptions = _parse(el[0]); }
+ if (ioptions.href) {
+ // save anchor info until the image is loaded
+ options.icon = new L.KMLIcon({
+ iconUrl: ioptions.href,
+ shadowUrl: null,
+ iconAnchorRef: {x: ioptions.x, y: ioptions.y},
+ iconAnchorType: {x: ioptions.xunits, y: ioptions.yunits}
+ });
+ }
+ style['#' + e.getAttribute('id')] = options;
+ }
+ return style;
+ },
+
+ parseFolder: function (xml, style) {
+ var el, layers = [], l;
+ el = xml.getElementsByTagName('Folder');
+ for (var i = 0; i < el.length; i++) {
+ if (!this._check_folder(el[i], xml)) { continue; }
+ l = this.parseFolder(el[i], style);
+ if (l) { layers.push(l); }
+ }
+ el = xml.getElementsByTagName('Placemark');
+ for (var j = 0; j < el.length; j++) {
+ if (!this._check_folder(el[j], xml)) { continue; }
+ l = this.parsePlacemark(el[j], xml, style);
+ if (l) { layers.push(l); }
+ }
+ if (!layers.length) { return; }
+ if (layers.length === 1) { return layers[0]; }
+ return new L.FeatureGroup(layers);
+ },
+
+ parsePlacemark: function (place, xml, style) {
+ var i, j, el, options = {};
+ el = place.getElementsByTagName('styleUrl');
+ for (i = 0; i < el.length; i++) {
+ var url = el[i].childNodes[0].nodeValue;
+ for (var a in style[url])
+ {
+ // for jshint
+ if (true)
+ {
+ options[a] = style[url][a];
+ }
+ }
+ }
+ var layers = [];
+
+ var parse = ['LineString', 'Polygon', 'Point'];
+ for (j in parse) {
+ // for jshint
+ if (true)
+ {
+ var tag = parse[j];
+ el = place.getElementsByTagName(tag);
+ for (i = 0; i < el.length; i++) {
+ var l = this["parse" + tag](el[i], xml, options);
+ if (l) { layers.push(l); }
+ }
+ }
+ }
+
+ if (!layers.length) {
+ return;
+ }
+ var layer = layers[0];
+ if (layers.length > 1) {
+ layer = new L.FeatureGroup(layers);
+ }
+
+ var name, descr = "";
+ el = place.getElementsByTagName('name');
+ if (el.length) {
+ name = el[0].childNodes[0].nodeValue;
+ }
+ el = place.getElementsByTagName('description');
+ for (i = 0; i < el.length; i++) {
+ for (j = 0; j < el[i].childNodes.length; j++) {
+ descr = descr + el[i].childNodes[j].nodeValue;
+ }
+ }
+
+ if (name) {
+ layer.bindPopup("
" + name + "
" + descr);
+ }
+
+ return layer;
+ },
+
+ parseCoords: function (xml) {
+ var el = xml.getElementsByTagName('coordinates');
+ return this._read_coords(el[0]);
+ },
+
+ parseLineString: function (line, xml, options) {
+ var coords = this.parseCoords(line);
+ if (!coords.length) { return; }
+ return new L.Polyline(coords, options);
+ },
+
+ parsePoint: function (line, xml, options) {
+ var el = line.getElementsByTagName('coordinates');
+ if (!el.length) {
+ return;
+ }
+ var ll = el[0].childNodes[0].nodeValue.split(',');
+ return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options);
+ },
+
+ parsePolygon: function (line, xml, options) {
+ var el, polys = [], inner = [], i, coords;
+ el = line.getElementsByTagName('outerBoundaryIs');
+ for (i = 0; i < el.length; i++) {
+ coords = this.parseCoords(el[i]);
+ if (coords) {
+ polys.push(coords);
+ }
+ }
+ el = line.getElementsByTagName('innerBoundaryIs');
+ for (i = 0; i < el.length; i++) {
+ coords = this.parseCoords(el[i]);
+ if (coords) {
+ inner.push(coords);
+ }
+ }
+ if (!polys.length) {
+ return;
+ }
+ if (options.fillColor) {
+ options.fill = true;
+ }
+ if (polys.length === 1) {
+ return new L.Polygon(polys.concat(inner), options);
+ }
+ return new L.MultiPolygon(polys, options);
+ },
+
+ getLatLngs: function (xml) {
+ var el = xml.getElementsByTagName('coordinates');
+ var coords = [];
+ for (var j = 0; j < el.length; j++) {
+ // text might span many childnodes
+ coords = coords.concat(this._read_coords(el[j]));
+ }
+ return coords;
+ },
+
+ _read_coords: function (el) {
+ var text = "", coords = [], i;
+ for (i = 0; i < el.childNodes.length; i++) {
+ text = text + el.childNodes[i].nodeValue;
+ }
+ text = text.split(/[\s\n]+/);
+ for (i = 0; i < text.length; i++) {
+ var ll = text[i].split(',');
+ if (ll.length < 2) {
+ continue;
+ }
+ coords.push(new L.LatLng(ll[1], ll[0]));
+ }
+ return coords;
+ }
+
+});
+
+L.KMLIcon = L.Icon.extend({
+
+ createIcon: function () {
+ var img = this._createIcon('icon');
+ img.onload = function () {
+ var i = new Image();
+ i.src = this.src;
+ this.style.width = i.width + 'px';
+ this.style.height = i.height + 'px';
+
+ if (this.anchorType.x === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
+ img.style.marginLeft = (-this.anchor.x * i.width) + 'px';
+ }
+ if (this.anchorType.y === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
+ img.style.marginTop = (-(1 - this.anchor.y) * i.height) + 'px';
+ }
+ this.style.display = "";
+ };
+ return img;
+ },
+
+ _setIconStyles: function (img, name) {
+ L.Icon.prototype._setIconStyles.apply(this, [img, name])
+ // save anchor information to the image
+ img.anchor = this.options.iconAnchorRef;
+ img.anchorType = this.options.iconAnchorType;
+ }
+});
+
+
+L.KMLMarker = L.Marker.extend({
+ options: {
+ icon: new L.KMLIcon.Default()
+ }
+});
\ No newline at end of file
diff --git a/external/leaflet.filelayer.js b/external/leaflet.filelayer.js
new file mode 100755
index 00000000..7eab6a50
--- /dev/null
+++ b/external/leaflet.filelayer.js
@@ -0,0 +1,168 @@
+/*
+ * Load files *locally* (GeoJSON, KML, GPX) into the map
+ * using the HTML5 File API.
+ *
+ * Requires Pavel Shramov's GPX.js
+ * https://github.com/shramov/leaflet-plugins/blob/d74d67/layer/vector/GPX.js
+ */
+var FileLoader = L.Class.extend({
+ includes: L.Mixin.Events,
+ options: {
+ layerOptions: {}
+ },
+
+ initialize: function (map, options) {
+ this._map = map;
+ L.Util.setOptions(this, options);
+
+ this._parsers = {
+ 'geojson': this._loadGeoJSON,
+ 'gpx': this._convertToGeoJSON,
+ 'kml': this._convertToGeoJSON
+ };
+ },
+
+ load: function (file /* File */) {
+ // Check file extension
+ var ext = file.name.split('.').pop(),
+ parser = this._parsers[ext];
+ if (!parser) {
+ window.alert("Unsupported file type " + file.type + '(' + ext + ')');
+ return;
+ }
+ // Read selected file using HTML5 File API
+ var reader = new FileReader();
+ reader.onload = L.Util.bind(function (e) {
+ this.fire('data:loading', {filename: file.name, format: ext});
+ var layer = parser.call(this, e.target.result, ext);
+ this.fire('data:loaded', {layer: layer, filename: file.name, format: ext});
+ }, this);
+ reader.readAsText(file);
+ },
+
+ _loadGeoJSON: function (content) {
+ if (typeof content == 'string') {
+ content = JSON.parse(content);
+ }
+ return L.geoJson(content, this.options.layerOptions).addTo(this._map);
+ },
+
+ _convertToGeoJSON: function (content, format) {
+ // Format is either 'gpx' or 'kml'
+ if (typeof content == 'string') {
+ content = ( new window.DOMParser() ).parseFromString(content, "text/xml");
+ }
+ var geojson = toGeoJSON[format](content);
+ return this._loadGeoJSON(geojson);
+ }
+});
+
+
+L.Control.FileLayerLoad = L.Control.extend({
+ statics: {
+ TITLE: 'Load local file (GPX, KML, GeoJSON)',
+ LABEL: '⌅'
+ },
+ options: {
+ position: 'topleft',
+ fitBounds: true,
+ layerOptions: {}
+ },
+
+ initialize: function (options) {
+ L.Util.setOptions(this, options);
+ this.loader = null;
+ },
+
+ onAdd: function (map) {
+ this.loader = new FileLoader(map, {layerOptions: this.options.layerOptions});
+
+ this.loader.on('data:loaded', function (e) {
+ // Fit bounds after loading
+ if (this.options.fitBounds) {
+ window.setTimeout(function () {
+ map.fitBounds(e.layer.getBounds()).zoomOut();
+ }, 500);
+ }
+ }, this);
+
+ // Initialize Drag-and-drop
+ this._initDragAndDrop(map);
+
+ // Initialize map control
+ return this._initContainer();
+ },
+
+ _initDragAndDrop: function (map) {
+ var fileLoader = this.loader,
+ dropbox = map._container;
+
+ var callbacks = {
+ dragenter: function () {
+ map.scrollWheelZoom.disable();
+ },
+ dragleave: function () {
+ map.scrollWheelZoom.enable();
+ },
+ dragover: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ },
+ drop: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ var files = Array.prototype.slice.apply(e.dataTransfer.files),
+ i = files.length;
+ setTimeout(function(){
+ fileLoader.load(files.shift());
+ if (files.length > 0) {
+ setTimeout(arguments.callee, 25);
+ }
+ }, 25);
+ map.scrollWheelZoom.enable();
+ }
+ };
+ for (var name in callbacks)
+ dropbox.addEventListener(name, callbacks[name], false);
+ },
+
+ _initContainer: function () {
+ // Create an invisible file input
+ var fileInput = L.DomUtil.create('input', 'hidden', container);
+ fileInput.type = 'file';
+ fileInput.accept = '.gpx,.kml,.geojson';
+ fileInput.style.display = 'none';
+ // Load on file change
+ var fileLoader = this.loader;
+ fileInput.addEventListener("change", function (e) {
+ fileLoader.load(this.files[0]);
+ }, false);
+
+ // Create a button, and bind click on hidden file input
+ var zoomName = 'leaflet-control-filelayer leaflet-control-zoom',
+ barName = 'leaflet-bar',
+ partName = barName + '-part',
+ container = L.DomUtil.create('div', zoomName + ' ' + barName);
+ var link = L.DomUtil.create('a', zoomName + '-in ' + partName, container);
+ link.innerHTML = L.Control.FileLayerLoad.LABEL;
+ link.href = '#';
+ link.title = L.Control.FileLayerLoad.TITLE;
+
+ var stop = L.DomEvent.stopPropagation;
+ L.DomEvent
+ .on(link, 'click', stop)
+ .on(link, 'mousedown', stop)
+ .on(link, 'dblclick', stop)
+ .on(link, 'click', L.DomEvent.preventDefault)
+ .on(link, 'click', function (e) {
+ fileInput.click();
+ e.preventDefault();
+ });
+ return container;
+ }
+});
+
+L.Control.fileLayerLoad = function (options) {
+ return new L.Control.FileLayerLoad(options);
+};
\ No newline at end of file
diff --git a/external/togeojson.js b/external/togeojson.js
new file mode 100755
index 00000000..cd980b92
--- /dev/null
+++ b/external/togeojson.js
@@ -0,0 +1,224 @@
+toGeoJSON = (function() {
+ 'use strict';
+
+ var removeSpace = (/\s*/g),
+ trimSpace = (/^\s*|\s*$/g),
+ splitSpace = (/\s+/);
+ // generate a short, numeric hash of a string
+ function okhash(x) {
+ if (!x || !x.length) return 0;
+ for (var i = 0, h = 0; i < x.length; i++) {
+ h = ((h << 5) - h) + x.charCodeAt(i) | 0;
+ } return h;
+ }
+ // all Y children of X
+ function get(x, y) { return x.getElementsByTagName(y); }
+ function attr(x, y) { return x.getAttribute(y); }
+ function attrf(x, y) { return parseFloat(attr(x, y)); }
+ // one Y child of X, if any, otherwise null
+ function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
+ function norm(el) { if (el.normalize) { el.normalize(); } return el; }
+ // cast array x into numbers
+ function numarray(x) {
+ for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
+ return o;
+ }
+ function clean(x) {
+ var o = {};
+ for (var i in x) if (x[i]) o[i] = x[i];
+ return o;
+ }
+ // get the content of a text node, if any
+ function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
+ // get one coordinate from a coordinate array, if any
+ function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
+ // get all coordinates from a coordinate array as [[],[]]
+ function coord(v) {
+ var coords = v.replace(trimSpace, '').split(splitSpace),
+ o = [];
+ for (var i = 0; i < coords.length; i++) {
+ o.push(coord1(coords[i]));
+ }
+ return o;
+ }
+ function coordPair(x) { return [attrf(x, 'lon'), attrf(x, 'lat')]; }
+
+ // create a new feature collection parent object
+ function fc() {
+ return {
+ type: 'FeatureCollection',
+ features: []
+ };
+ }
+
+ var serializer;
+ if (typeof XMLSerializer !== 'undefined') {
+ serializer = new XMLSerializer();
+ } else if (typeof require !== 'undefined') {
+ serializer = new (require('xmldom').XMLSerializer)();
+ }
+ function xml2str(str) { return serializer.serializeToString(str); }
+
+ var t = {
+ kml: function(doc, o) {
+ o = o || {};
+
+ var gj = fc(),
+ // styleindex keeps track of hashed styles in order to match features
+ styleIndex = {},
+ // atomic geospatial types supported by KML - MultiGeometry is
+ // handled separately
+ geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
+ // all root placemarks in the file
+ placemarks = get(doc, 'Placemark'),
+ styles = get(doc, 'Style');
+
+ for (var k = 0; k < styles.length; k++) {
+ styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
+ }
+ for (var j = 0; j < placemarks.length; j++) {
+ gj.features = gj.features.concat(getPlacemark(placemarks[j]));
+ }
+ function gxCoord(v) { return numarray(v.split(' ')); }
+ function gxCoords(root) {
+ var elems = get(root, 'coord', 'gx'), coords = [];
+ for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
+ return coords;
+ }
+ function getGeometry(root) {
+ var geomNode, geomNodes, i, j, k, geoms = [];
+ if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
+ if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
+ for (i = 0; i < geotypes.length; i++) {
+ geomNodes = get(root, geotypes[i]);
+ if (geomNodes) {
+ for (j = 0; j < geomNodes.length; j++) {
+ geomNode = geomNodes[j];
+ if (geotypes[i] == 'Point') {
+ geoms.push({
+ type: 'Point',
+ coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
+ });
+ } else if (geotypes[i] == 'LineString') {
+ geoms.push({
+ type: 'LineString',
+ coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
+ });
+ } else if (geotypes[i] == 'Polygon') {
+ var rings = get(geomNode, 'LinearRing'),
+ coords = [];
+ for (k = 0; k < rings.length; k++) {
+ coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
+ }
+ geoms.push({
+ type: 'Polygon',
+ coordinates: coords
+ });
+ } else if (geotypes[i] == 'Track') {
+ geoms.push({
+ type: 'LineString',
+ coordinates: gxCoords(geomNode)
+ });
+ }
+ }
+ }
+ }
+ return geoms;
+ }
+ function getPlacemark(root) {
+ var geoms = getGeometry(root), i, properties = {},
+ name = nodeVal(get1(root, 'name')),
+ styleUrl = nodeVal(get1(root, 'styleUrl')),
+ description = nodeVal(get1(root, 'description')),
+ extendedData = get1(root, 'ExtendedData');
+
+ if (!geoms.length) return [];
+ if (name) properties.name = name;
+ if (styleUrl && styleIndex[styleUrl]) {
+ properties.styleUrl = styleUrl;
+ properties.styleHash = styleIndex[styleUrl];
+ }
+ if (description) properties.description = description;
+ if (extendedData) {
+ var datas = get(extendedData, 'Data'),
+ simpleDatas = get(extendedData, 'SimpleData');
+
+ for (i = 0; i < datas.length; i++) {
+ properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
+ }
+ for (i = 0; i < simpleDatas.length; i++) {
+ properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
+ }
+ }
+ return [{
+ type: 'Feature',
+ geometry: (geoms.length === 1) ? geoms[0] : {
+ type: 'GeometryCollection',
+ geometries: geoms
+ },
+ properties: properties
+ }];
+ }
+ return gj;
+ },
+ gpx: function(doc, o) {
+ var i,
+ tracks = get(doc, 'trk'),
+ routes = get(doc, 'rte'),
+ waypoints = get(doc, 'wpt'),
+ // a feature collection
+ gj = fc();
+ for (i = 0; i < tracks.length; i++) {
+ gj.features.push(getLinestring(tracks[i], 'trkpt'));
+ }
+ for (i = 0; i < routes.length; i++) {
+ gj.features.push(getLinestring(routes[i], 'rtept'));
+ }
+ for (i = 0; i < waypoints.length; i++) {
+ gj.features.push(getPoint(waypoints[i]));
+ }
+ function getLinestring(node, pointname) {
+ var j, pts = get(node, pointname), line = [];
+ for (j = 0; j < pts.length; j++) {
+ line.push(coordPair(pts[j]));
+ }
+ return {
+ type: 'Feature',
+ properties: getProperties(node),
+ geometry: {
+ type: 'LineString',
+ coordinates: line
+ }
+ };
+ }
+ function getPoint(node) {
+ var prop = getProperties(node);
+ prop.ele = nodeVal(get1(node, 'ele'));
+ prop.sym = nodeVal(get1(node, 'sym'));
+ return {
+ type: 'Feature',
+ properties: prop,
+ geometry: {
+ type: 'Point',
+ coordinates: coordPair(node)
+ }
+ };
+ }
+ function getProperties(node) {
+ var meta = ['name', 'desc', 'author', 'copyright', 'link',
+ 'time', 'keywords'],
+ prop = {},
+ k;
+ for (k = 0; k < meta.length; k++) {
+ prop[meta[k]] = nodeVal(get1(node, meta[k]));
+ }
+ return clean(prop);
+ }
+ return gj;
+ }
+ };
+ return t;
+})();
+
+if (typeof module !== 'undefined') module.exports = toGeoJSON;
diff --git a/plugins/kml_plugin.user.js b/plugins/kml_plugin.user.js
new file mode 100755
index 00000000..d87199a3
--- /dev/null
+++ b/plugins/kml_plugin.user.js
@@ -0,0 +1,62 @@
+// ==UserScript==
+// @id overlay-kml@danielatkins
+// @name IITC plugin: overlay KML
+// @category Info
+// @version 0.1.@@DATETIMEVERSION@@
+// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
+// @updateURL @@UPDATEURL@@
+// @downloadURL @@DOWNLOADURL@@
+// @description [@@BUILDNAME@@-@@BUILDDATE@@] Allows users to overlay their own KML / GPX files on top of IITC
+// @include https://www.ingress.com/intel*
+// @include http://www.ingress.com/intel*
+// @match https://www.ingress.com/intel*
+// @match http://www.ingress.com/intel*
+// @grant none
+// ==/UserScript==
+
+@@PLUGINSTART@@
+
+// PLUGIN START ////////////////////////////////////////////////////////
+
+// use own namespace for plugin
+window.plugin.overlayKML = function() {};
+
+window.plugin.overlayKML.loadExternals = function() {
+ try { console.log('Loading leaflet.filelayer JS now'); } catch(e) {}
+ @@INCLUDERAW:external/leaflet.filelayer.js@@
+ try { console.log('done loading leaflet.filelayer JS'); } catch(e) {}
+
+ try { console.log('Loading KML JS now'); } catch(e) {}
+ @@INCLUDERAW:external/KML.js@@
+ try { console.log('done loading KML JS'); } catch(e) {}
+
+ try { console.log('Loading togeojson JS now'); } catch(e) {}
+ @@INCLUDERAW:external/togeojson.js@@
+ try { console.log('done loading togeojson JS'); } catch(e) {}
+
+ window.plugin.overlayKML.load();
+}
+
+// window.plugin.overlayKML.setupCallback = function() {
+// $('#toolbox').append(' Overlay KML');
+// }
+
+window.plugin.overlayKML.load = function() {
+ // Provide popup window allow user to select KML to overlay
+L.Control.FileLayerLoad.LABEL = 'O';
+L.Control.fileLayerLoad({
+ fitBounds: true,
+ layerOptions: {
+ pointToLayer: function (data, latlng) {
+ return L.marker(latlng);
+ }},
+}).addTo(map);
+}
+
+var setup = function() {
+ window.plugin.overlayKML.loadExternals();
+}
+
+// PLUGIN END //////////////////////////////////////////////////////////
+
+@@PLUGINEND@@
\ No newline at end of file