diff --git a/karma.conf.js b/karma.conf.js index 5c31efb91..82881e037 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -23,6 +23,7 @@ module.exports = function (config) { 'spec/Layers/BasemapLayerSpec.js', 'spec/Layers/TiledMapLayerSpec.js', 'spec/Layers/RasterLayerSpec.js', + 'spec/Layers/FeatureLayer/*Spec.js', // 'spec/Layers/*Spec.js', 'spec/Tasks/*Spec.js', 'spec/Services/*Spec.js', diff --git a/package-lock.json b/package-lock.json index 3fbaf9073..6a23ee3dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@esri/arcgis-to-geojson-utils": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@esri/arcgis-to-geojson-utils/-/arcgis-to-geojson-utils-1.0.4.tgz", - "integrity": "sha512-+8qR95frMscZNn2sK/1v8vmwgviu2JERAs9rNUNzsZpP2jZymKij1l13YA5qxo1wVsKJ/7k6dBT32tcw8+Ei+w==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@esri/arcgis-to-geojson-utils/-/arcgis-to-geojson-utils-1.0.5.tgz", + "integrity": "sha512-vG4Ih7WyRuwWSuu6HzjDgj8lnVQ0IZK2JjF1bn+HpdNHc1KN/WLsLjGu7A/hdsShVsiWTPdKVa0mDYVrUOXbhw==" }, "abbrev": { "version": "1.0.9", diff --git a/package.json b/package.json index 0bae5bfe9..bcda59eee 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "John Gravois (http://johngravois.com)" ], "dependencies": { - "@esri/arcgis-to-geojson-utils": "^1.0.4", + "@esri/arcgis-to-geojson-utils": "^1.0.5", "leaflet-virtual-grid": "^1.0.3", "tiny-binary-search": "^1.0.2" }, diff --git a/spec/Layers/DynamicMapLayerSpec.js b/spec/Layers/DynamicMapLayerSpec.js index f590610dd..9d78ab37c 100644 --- a/spec/Layers/DynamicMapLayerSpec.js +++ b/spec/Layers/DynamicMapLayerSpec.js @@ -22,8 +22,10 @@ describe('L.esri.DynamicMapLayer', function () { var WithTimeTimeOptions = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MkU1NjVENzgyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MkU1NjVENzkyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyOUVEREI3NTIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyOUVEREI3NjIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pno8yQ0AAABgUExURb29va6urqysrKioqLKyssvLy7Gxsbm5ucjIyLe3t7W1tcLCwr6+vsbGxrOzs8XFxbS0tMHBwaqqqsDAwLu7u7i4uLq6usfHx8nJyaurq8PDw8rKyqenp6Ojo7CwsMzMzDDnGUgAAAEDSURBVHja7NTbUoMwFIXhBhJCoJwLbT2t939L02A7elEdO2ov/JkMJGTtfMAAG91z26Cjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6PfTS//Xp/DnOYbyUou231I74+DpndXtTfT2mm+8UA/CbbPrbSVcicT5apMozDH3RKJQqpL1SEc5MKjdpOR+kGHY4r5hxiNx8rdqBd5n+761Oyqn7qFlRt90n0n39pB9VhrqV/iube4nF2rnLlV7324omvcXvS+HdTknbosLvVUnSvMslZl5c+/8+7K2H6Z/M0vzvG3QUdHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dH//f6qwADAEAoWKnzLlffAAAAAElFTkSuQmCC'; var WithDefs = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjlFRERCNkYyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjlFRERCNzAyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyOUVEREI2RDIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyOUVEREI2RTIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pg3iWmcAAABgUExURa6urr+/v8HBwcfHx7u7u56enrW1taWlpby8vLe3t7i4uMPDw8LCwqioqKamppmZmcjIyKurq7Kysq2trZaWlsrKypqampycnKOjo5eXl8vLy52dnZubm6KiorCwsMzMzADumocAAAFCSURBVHja7NXLbsMgEEBRMAH8KHEc41cch///yxLXSVrJm0p2uuhlhzTSYWYYEOEvl0BHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR//FurxHb1q1Yk/jHvo1vXhV+CYk+UP3s37wpT09w4pB7qFbo3ya6hCMjbsse+ltoW/PMHndpe9CpIMxbtnV4psezKvasttFz47nqarPUTvG+pZlEXWh5aynQwxIJhdPY30sTTJ2G+uJrkRv0xDy/pl7crzNuvSx8TZzZsm9EmpjvRl62Wn1Q1d1/aUPccy6qq8W/VAmW0/c2F7G+5Va0fM7eTXy49H3vD1trDsd7LSqH3RMOkzmLBZdqbbYWL+5IKo13bfuNJdbF4tuBvf2l7Z5vbENfxw6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6+r/XPwUYAAXsVASA6AUmAAAAAElFTkSuQmCC'; var WithToken = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjlFRERCNzMyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjlFRERCNzQyMjZBMTFFNUI1NTc5NjAwMkVENUQwM0IiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyOUVEREI3MTIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyOUVEREI3MjIyNkExMUU1QjU1Nzk2MDAyRUQ1RDAzQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhEp84oAAABgUExURcjIyJycnLa2tsTExL+/v7i4uJ+fn5mZmbS0tK6urqmpqbGxsaamppqamsDAwLKysrOzs6WlpcrKyqurq6Kioq2trby8vMvLy8PDw6SkpKqqqqysrKOjo8HBwbq6uszMzKcQTFcAAAEoSURBVHja7NTbboMwDIDhhHOABginAm39/m/ZsFGpmqpdQVdpfy4Qsi2+WDhR8pdLoaOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojf5iu7I9AGB6oF2MUqcpXb+W2WZ+BMcNWUNUH6km4GDuJ9IXIOXrow2W279DzoSljI+JGkbh/6NIG8g69zrqu8FSWiUxaiU2aetNdrqNVN/596Hxe9FLuqw/z1OXX7xa/er/Yy6Zfm1vuE23i/MZU4qOpS8dd9VD3uXZPenPuNj2eIz8QlV7WrvPSfy+Vk9v3xKVBnchL3ZY3H6iKk1qH04xH6J0dyte6axK7JqrWj4Vu5Qj9t/X0k90/uGnR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dE/X78LMAB6zVaMpfGcowAAAABJRU5ErkJggg=='; + var WithParams = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAYFBMVEWurq6/v7/BwcHHx8e7u7uenp61tbWlpaW8vLy3t7e4uLjDw8PCwsKoqKimpqaZmZnIyMirq6uysrKtra2WlpbKysqampqcnJyjo6OXl5fLy8udnZ2bm5uioqKwsLDMzMwA7pqHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QweFBARX6eWJQAAAN5JREFUaN7t1UsOgkAMAFAO0X3vf0tjEJjyS0YFFz5CRjogj3aoDvnLbaDT6XQ6nU6n0+l0Op1Op9PpdDqdTqfT/1KPWIYYD+bpcTLmyQtyf947xmF6jI0e9+jNzLo09+Q+5jqlXBZm+oidKJdLLtCjYaNGNejWX3uu131mYrskS1Rfmt6Om5M51rMtcq6iUp5v61lbr3mUtX7in+rNmPWWTeeVE9FWfvrOcXt06bGXe5bcc7/y3XotXfv71lv5NzrOfxydTqfT6XQ6nU6n0+l0Op1Op9PpdDqdTv9gewCL6FN9G6INjAAAAABJRU5ErkJggg=='; var url = 'http://services.arcgis.com/mock/arcgis/rest/services/MockMapService/MapServer'; + var urlWithParams = 'http://services.arcgis.com/mock/arcgis/rest/services/MockMapService/MapServer?foo=bar'; var layer; var server; var map; @@ -103,6 +105,33 @@ describe('L.esri.DynamicMapLayer', function () { server.respond(); }); + it('should store additional params passed in url', function () { + layer = L.esri.dynamicMapLayer({ + url: urlWithParams + }).addTo(map); + + expect(layer.options.requestParams).to.deep.equal({ foo: 'bar' }); + expect(layer.options.url).to.deep.equal(url + '/'); + }); + + it('should use additional params passed in options', function (done) { + server.respondWith('GET', new RegExp(/http:\/\/services.arcgis.com\/mock\/arcgis\/rest\/services\/MockMapService\/MapServer\/export\?bbox=-?\d+\.\d+%2C-?\d+\.\d+%2C-?\d+\.\d+%2C-?\d+\.\d+&size=500%2C500&dpi=96&format=png24&transparent=true&bboxSR=3857&imageSR=3857&foo=bar&f=json/), JSON.stringify({ + href: WithParams + })); + layer = L.esri.dynamicMapLayer({ + url: url, + requestParams: { + foo: 'bar' + } + }); + layer.addTo(map); + layer.on('load', function () { + expect(layer._currentImage._url).to.equal(WithParams); + done(); + }); + server.respond(); + }); + it('will load a new image when the map moves', function (done) { layer.addTo(map); diff --git a/spec/Layers/FeatureLayer/FeatureLayerSpec.js b/spec/Layers/FeatureLayer/FeatureLayerSpec.js index 1a1fa5420..1e8ed32ab 100644 --- a/spec/Layers/FeatureLayer/FeatureLayerSpec.js +++ b/spec/Layers/FeatureLayer/FeatureLayerSpec.js @@ -105,6 +105,15 @@ describe('L.esri.FeatureLayer', function () { expect(layer).to.be.an.instanceof(L.esri.FeatureLayer); }); + it('should store additional params passed in url', function () { + layer = L.esri.featureLayer({ + url: 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0?foo=bar' + }).addTo(map); + + expect(layer.options.requestParams).to.deep.equal({ foo: 'bar' }); + expect(layer.options.url).to.deep.equal('http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/'); + }); + it('should create features on a map', function () { expect(map.hasLayer(layer.getFeature(1))).to.equal(true); expect(map.hasLayer(layer.getFeature(2))).to.equal(true); diff --git a/spec/Layers/FeatureLayer/FeatureManagerSpec.js b/spec/Layers/FeatureLayer/FeatureManagerSpec.js index e19bed45d..9e02e341d 100644 --- a/spec/Layers/FeatureLayer/FeatureManagerSpec.js +++ b/spec/Layers/FeatureLayer/FeatureManagerSpec.js @@ -19,6 +19,7 @@ describe('L.esri.FeatureManager', function () { } var url = 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0'; + var urlWithParams = 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0?foo=bar'; var layer; var sandbox; var server; @@ -218,6 +219,51 @@ describe('L.esri.FeatureManager', function () { expect(map.attributionControl._container.innerHTML).to.contain('Esri'); }); + it('should store additional params passed in url', function () { + layer = new MockLayer({ + url: urlWithParams + }).addTo(map); + + expect(layer.options.requestParams).to.deep.equal({ foo: 'bar' }); + expect(layer.options.url).to.deep.equal(url + '/'); + }); + + it('should use additional params passed in options', function () { + server.respondWith('GET', 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSr=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6953125%2C%22ymin%22%3A45.521743896993634%2C%22xmax%22%3A-122.6513671875%2C%22ymax%22%3A45.55252525134013%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&foo=bar&f=json', JSON.stringify({ + fields: fields, + features: [feature2], + objectIdFieldName: 'OBJECTID' + })); + + layer = new MockLayer({ + url: url, + requestParams: { + foo: 'bar' + } + }); + + layer.addTo(map); + + server.respond(); + + expect(layer.createLayers).to.have.been.calledWith([ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [-122.673342, 45.537161] + }, + 'properties': { + 'OBJECTID': 2, + 'Name': 'Site 2', + 'Type': 'Inactive', + 'Time': new Date('January 15 2014 GMT-0800').valueOf() + }, + 'id': 2 + } + ]); + }); + it('should be able to remove itself from a map', function () { layer.addTo(map); map.removeLayer(layer); diff --git a/spec/Layers/TiledMapLayerSpec.js b/spec/Layers/TiledMapLayerSpec.js index 9fd081a92..b18742618 100644 --- a/spec/Layers/TiledMapLayerSpec.js +++ b/spec/Layers/TiledMapLayerSpec.js @@ -15,6 +15,7 @@ describe('L.esri.TiledMapLayer', function () { } var url = 'http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer'; + var urlWithParams = 'http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer?foo=bar'; var subdomainsUrl = 'http://{s}.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer'; var subdomainsArray = ['server', 'services']; var layer; @@ -110,6 +111,26 @@ describe('L.esri.TiledMapLayer', function () { expect(layer.tileUrl).to.equal('http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer/tile/{z}/{y}/{x}?token=foo'); }); + it('should store additional params passed in url', function () { + layer = L.esri.tiledMapLayer({ + url: urlWithParams + }); + + expect(layer.options.requestParams).to.deep.equal({ foo: 'bar' }); + expect(layer.tileUrl).to.equal('http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer/tile/{z}/{y}/{x}?foo=bar'); + }); + + it('should use additional params passed in options', function () { + layer = L.esri.tiledMapLayer({ + url: url, + requestParams: { + foo: 'bar' + } + }); + + expect(layer.tileUrl).to.equal('http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer/tile/{z}/{y}/{x}?foo=bar'); + }); + it('should use a token passed with authenticate()', function () { layer = L.esri.tiledMapLayer({ url: url diff --git a/spec/Tasks/FindSpec.js b/spec/Tasks/FindSpec.js index 67423da4f..d6a70c220 100644 --- a/spec/Tasks/FindSpec.js +++ b/spec/Tasks/FindSpec.js @@ -223,5 +223,28 @@ describe('L.esri.Find', function () { window._EsriLeafletCallbacks[request.id](sampleResponse); }); + + it('should pass through arbitrary request parameters', function (done) { + var myTask = L.esri.find({ + url: mapServiceUrl, + requestParams: { + foo: 'bar' + } + }); + + server.respondWith('GET', mapServiceUrl + 'find?sr=4326&contains=true&returnGeometry=true&returnZ=true&returnM=false&layers=0&searchText=Site&foo=bar&f=json', JSON.stringify(sampleResponse)); + + var request = myTask.layers('0').text('Site').run(function (error, featureCollection, raw) { + expect(featureCollection).to.deep.equal(sampleFeatureCollection); + expect(raw).to.deep.equal(sampleResponse); + done(); + }); + + console.log(request.url); + + expect(request).to.be.an.instanceof(XMLHttpRequest); + + server.respond(); + }); }); /* eslint-enable handle-callback-err */ diff --git a/spec/Tasks/IdentifyFeaturesSpec.js b/spec/Tasks/IdentifyFeaturesSpec.js index 5ff435998..91b8c4bf4 100644 --- a/spec/Tasks/IdentifyFeaturesSpec.js +++ b/spec/Tasks/IdentifyFeaturesSpec.js @@ -320,5 +320,27 @@ describe('L.esri.IdentifyFeatures', function () { request.respond(200, { 'Content-Type': 'text/plain; charset=utf-8' }, JSON.stringify(sampleResponse)); }); + + it('should identify features passing through arbitrary request parameters', function (done) { + var polygonTask = L.esri.identifyFeatures({ + url: mapServiceUrl, + requestParams: { + foo: 'bar' + } + }).on(map).at(geoJsonPolygon); + + var request = polygonTask.run(function (error, featureCollection, raw) { + expect(featureCollection).to.deep.equal(sampleFeatureCollection); + expect(raw).to.deep.equal(sampleResponse); + done(); + }); + + expect(request.url).to.contain('geometry=%7B%22rings%22%3A%5B%5B%5B-97%2C39%5D%2C%5B-97%2C41%5D%2C%5B-94%2C41%5D%2C%5B-94%2C39%5D%2C%5B-97%2C39%5D%5D%5D%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D'); + expect(request.url).to.contain('geometryType=esriGeometryPolygon'); + expect(request.url).to.contain('sr=4326'); + expect(request.url).to.contain('foo=bar'); + + request.respond(200, { 'Content-Type': 'text/plain; charset=utf-8' }, JSON.stringify(sampleResponse)); + }); }); /* eslint-enable handle-callback-err */ diff --git a/spec/Tasks/IdentifyImageSpec.js b/spec/Tasks/IdentifyImageSpec.js index b298d70b3..8f43045a6 100644 --- a/spec/Tasks/IdentifyImageSpec.js +++ b/spec/Tasks/IdentifyImageSpec.js @@ -459,21 +459,40 @@ describe('L.esri.IdentifyImage', function () { it('should return catalog items w/o geometry', function (done) { var sampleResponseWithCatalogItemsNoGeometry = deepClone(sampleResponseWithCatalogItems); - var sampleResutlsWithCatalogItemsNoGeomerty = deepClone(sampleResultsWithCatlaogItems); + var sampleResultsWithCatalogItemsNoGeomerty = deepClone(sampleResultsWithCatlaogItems); for (var i = sampleResponseWithCatalogItemsNoGeometry.catalogItems.features.length - 1; i >= 0; i--) { delete (sampleResponseWithCatalogItemsNoGeometry.catalogItems.features[i].geometry); - sampleResutlsWithCatalogItemsNoGeomerty.catalogItems.features[i].geometry = null; + sampleResultsWithCatalogItemsNoGeomerty.catalogItems.features[i].geometry = null; } server.respondWith('GET', imageServiceUrl + 'identify?returnGeometry=false&geometry=%7B%22x%22%3A-122.66%2C%22y%22%3A45.51%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryPoint&returnCatalogItems=true&f=json', JSON.stringify(sampleResponseWithCatalogItemsNoGeometry)); task.returnCatalogItems(true); task.run(function (error, results, raw) { - expect(results).to.deep.equal(sampleResutlsWithCatalogItemsNoGeomerty); + expect(results).to.deep.equal(sampleResultsWithCatalogItemsNoGeomerty); expect(raw).to.deep.equal(sampleResponseWithCatalogItemsNoGeometry); done(); }); server.respond(); }); + + it('should pass through arbitrary parameters', function (done) { + var customTask = L.esri.identifyImage({ + url: imageServiceUrl, + requestParams: { + foo: 'bar' + } + }).at(latlng); + + server.respondWith('GET', imageServiceUrl + 'identify?returnGeometry=false&geometry=%7B%22x%22%3A-122.66%2C%22y%22%3A45.51%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryPoint&foo=bar&f=json', JSON.stringify(sampleResponse)); + + customTask.run(function (error, results, raw) { + expect(results).to.deep.equal(sampleResults); + expect(raw).to.deep.equal(sampleResponse); + done(); + }); + + server.respond(); + }); }); /* eslint-enable handle-callback-err */ diff --git a/spec/Tasks/QuerySpec.js b/spec/Tasks/QuerySpec.js index db493d3f6..45b2d9812 100644 --- a/spec/Tasks/QuerySpec.js +++ b/spec/Tasks/QuerySpec.js @@ -270,6 +270,33 @@ describe('L.esri.Query', function () { ] }; + var dumbLongQuery = 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters' + + 'this is a dumb way to make sure the request is more than 2000 characters'; + beforeEach(function () { server = sinon.fakeServer.create(); task = L.esri.query({url: featureLayerUrl}); @@ -859,45 +886,38 @@ describe('L.esri.Query', function () { }); it('query tasks without services should make POST requests', function (done) { - // var longString - server.respondWith('POST', mapServiceUrl + '0/query', JSON.stringify(sampleMapServiceQueryResponse)); var queryTask = new L.esri.Query({url: mapServiceUrl + '0'}); - queryTask.where( - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters' + - 'this is a dumb way to make sure the request is more than 2000 characters').run(function (error, featureCollection, raw) { - expect(featureCollection).to.deep.equal(sampleMapServiceCollection); - expect(raw).to.deep.equal(sampleMapServiceQueryResponse); - done(); - }); + queryTask.where(dumbLongQuery).run(function (error, featureCollection, raw) { + expect(featureCollection).to.deep.equal(sampleMapServiceCollection); + expect(raw).to.deep.equal(sampleMapServiceQueryResponse); + done(); + }); server.respond(); }); + it('query tasks should pass through arbitrary parameters when POSTing too', function (done) { + server.respondWith('POST', mapServiceUrl + '0/query', JSON.stringify(sampleMapServiceQueryResponse)); + var queryTask = new L.esri.Query({ + url: mapServiceUrl + '0', + requestParams: { + foo: 'bar' + } + }); + queryTask.where(dumbLongQuery); + + var request = queryTask.run(function (error, featureCollection, raw) { + expect(featureCollection).to.deep.equal(sampleMapServiceCollection); + expect(raw).to.deep.equal(sampleMapServiceQueryResponse); + done(); + }); + + console.log(request); + expect(request.requestBody).to.contain('foo=bar'); + server.respond(); + }); + it('should query GeoJSON from ArcGIS Online', function (done) { task = L.esri.query({url: 'http://services.arcgis.com/mock/arcgis/rest/services/MockFeatureService/FeatureServer/0/'}); @@ -929,5 +949,26 @@ describe('L.esri.Query', function () { server.respond(); }); + + it('should pass through arbitrary request parameters', function (done) { + task = L.esri.query({ + url: 'http://services.arcgis.com/mock/arcgis/rest/services/MockFeatureService/FeatureServer/0', + requestParams: { + foo: 'bar' + } + }); + + server.respondWith('GET', 'http://services.arcgis.com/mock/arcgis/rest/services/MockFeatureService/FeatureServer/0/query?returnGeometry=true&where=1%3D1&outSr=4326&outFields=*&f=geojson&foo=bar', JSON.stringify(sampleFeatureCollection)); + + var request = task.run(function (error, featureCollection, raw) { + expect(featureCollection).to.deep.equal(sampleFeatureCollection); + expect(raw).to.deep.equal(sampleFeatureCollection); + done(); + }); + + expect(request).to.be.an.instanceof(XMLHttpRequest); + + server.respond(); + }); }); /* eslint-enable handle-callback-err */ diff --git a/spec/UtilSpec.js b/spec/UtilSpec.js index ce1f20cd8..f356186fd 100644 --- a/spec/UtilSpec.js +++ b/spec/UtilSpec.js @@ -42,6 +42,17 @@ describe('L.esri.Util', function () { expect(url).to.equal('http://arcgis.com/'); }); + it('should store in requestParams option, additional parameters passed in url', function () { + var options = { + url: 'http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer?foo=bar', + maxZoom: 15 + }; + options = L.esri.Util.getUrlParams(options); + + expect(options.url).to.equal('http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer/'); + expect(options.requestParams).to.deep.equal({ foo: 'bar' }); + }); + it('should add a trailing slash to the url with cleanUrl', function () { var url = L.esri.Util.cleanUrl('http://arcgis.com'); expect(url).to.equal('http://arcgis.com/'); diff --git a/src/Layers/DynamicMapLayer.js b/src/Layers/DynamicMapLayer.js index dbe25585a..1d6c41f2c 100644 --- a/src/Layers/DynamicMapLayer.js +++ b/src/Layers/DynamicMapLayer.js @@ -1,6 +1,6 @@ import { Util } from 'leaflet'; import { RasterLayer } from './RasterLayer'; -import { cleanUrl } from '../Util'; +import { getUrlParams } from '../Util'; import mapService from '../Services/MapService'; export var DynamicMapLayer = RasterLayer.extend({ @@ -16,7 +16,7 @@ export var DynamicMapLayer = RasterLayer.extend({ }, initialize: function (options) { - options.url = cleanUrl(options.url); + options = getUrlParams(options); this.service = mapService(options); this.service.addEventParent(this); diff --git a/src/Layers/FeatureLayer/FeatureManager.js b/src/Layers/FeatureLayer/FeatureManager.js index eb21e31ae..0c485b7e0 100644 --- a/src/Layers/FeatureLayer/FeatureManager.js +++ b/src/Layers/FeatureLayer/FeatureManager.js @@ -1,6 +1,6 @@ import { Util } from 'leaflet'; import featureLayerService from '../../Services/FeatureLayerService'; -import { cleanUrl, warn, setEsriAttribution } from '../../Util'; +import { getUrlParams, warn, setEsriAttribution } from '../../Util'; import VirtualGrid from 'leaflet-virtual-grid'; import BinarySearchIndex from 'tiny-binary-search'; @@ -28,7 +28,7 @@ export var FeatureManager = VirtualGrid.extend({ initialize: function (options) { VirtualGrid.prototype.initialize.call(this, options); - options.url = cleanUrl(options.url); + options = getUrlParams(options); options = Util.setOptions(this, options); this.service = featureLayerService(options); @@ -200,6 +200,10 @@ export var FeatureManager = VirtualGrid.extend({ .fields(this.options.fields) .precision(this.options.precision); + if (this.options.requestParams) { + L.extend(query.params, this.options.requestParams); + } + if (this.options.simplifyFactor) { query.simplify(this._map, this.options.simplifyFactor); } diff --git a/src/Layers/ImageMapLayer.js b/src/Layers/ImageMapLayer.js index 7b2ec9053..82a1d48da 100644 --- a/src/Layers/ImageMapLayer.js +++ b/src/Layers/ImageMapLayer.js @@ -1,6 +1,6 @@ import { Util } from 'leaflet'; import { RasterLayer } from './RasterLayer'; -import { cleanUrl } from '../Util'; +import { getUrlParams } from '../Util'; import imageService from '../Services/ImageService'; export var ImageMapLayer = RasterLayer.extend({ @@ -21,7 +21,7 @@ export var ImageMapLayer = RasterLayer.extend({ }, initialize: function (options) { - options.url = cleanUrl(options.url); + options = getUrlParams(options); this.service = imageService(options); this.service.addEventParent(this); diff --git a/src/Layers/RasterLayer.js b/src/Layers/RasterLayer.js index dbd20aa73..4c3d99add 100644 --- a/src/Layers/RasterLayer.js +++ b/src/Layers/RasterLayer.js @@ -254,6 +254,7 @@ export var RasterLayer = Layer.extend({ } var params = this._buildExportParams(); + L.extend(params, this.options.requestParams); if (params) { this._requestExport(params, bounds); diff --git a/src/Layers/TiledMapLayer.js b/src/Layers/TiledMapLayer.js index 28f46db71..e38bbd727 100644 --- a/src/Layers/TiledMapLayer.js +++ b/src/Layers/TiledMapLayer.js @@ -1,5 +1,5 @@ import { TileLayer, Util } from 'leaflet'; -import { warn, cleanUrl, setEsriAttribution } from '../Util'; +import { warn, getUrlParams, setEsriAttribution } from '../Util'; import mapService from '../Services/MapService'; export var TiledMapLayer = TileLayer.extend({ @@ -38,11 +38,11 @@ export var TiledMapLayer = TileLayer.extend({ }, initialize: function (options) { - options.url = cleanUrl(options.url); options = Util.setOptions(this, options); // set the urls - this.tileUrl = options.url + 'tile/{z}/{y}/{x}'; + options = getUrlParams(options); + this.tileUrl = options.url + 'tile/{z}/{y}/{x}' + (options.requestParams && Object.keys(options.requestParams).length > 0 ? Util.getParamString(options.requestParams) : ''); // Remove subdomain in url // https://github.com/Esri/esri-leaflet/issues/991 if (options.url.indexOf('{s}') !== -1 && options.subdomains) { diff --git a/src/Services/Service.js b/src/Services/Service.js index b7a146f9b..9f880b5be 100644 --- a/src/Services/Service.js +++ b/src/Services/Service.js @@ -1,6 +1,6 @@ import { Util, Evented } from 'leaflet'; import {cors} from '../Support'; -import {cleanUrl} from '../Util'; +import {cleanUrl, getUrlParams} from '../Util'; import Request from '../Request'; export var Service = Evented.extend({ @@ -62,7 +62,9 @@ export var Service = Evented.extend({ if (this.options.token) { params.token = this.options.token; } - + if (this.options.requestParams) { + L.extend(params, this.options.requestParams); + } if (this._authenticating) { this._requestQueue.push([method, path, params, callback, context]); return; @@ -131,6 +133,7 @@ export var Service = Evented.extend({ }); export function service (options) { + options = getUrlParams(options); return new Service(options); } diff --git a/src/Tasks/Task.js b/src/Tasks/Task.js index 8bb29907f..507111b7a 100644 --- a/src/Tasks/Task.js +++ b/src/Tasks/Task.js @@ -1,6 +1,6 @@ import { Class, Util } from 'leaflet'; import {cors} from '../Support'; -import {cleanUrl} from '../Util'; +import { cleanUrl, getUrlParams } from '../Util'; import Request from '../Request'; export var Task = Class.extend({ @@ -57,6 +57,9 @@ export var Task = Class.extend({ }, request: function (callback, context) { + if (this.options.requestParams) { + L.extend(this.params, this.options.requestParams); + } if (this._service) { return this._service.request(this.path, this.params, callback, context); } @@ -76,6 +79,7 @@ export var Task = Class.extend({ }); export function task (options) { + options = getUrlParams(options); return new Task(options); } diff --git a/src/Util.js b/src/Util.js index e494b7688..925637aa8 100644 --- a/src/Util.js +++ b/src/Util.js @@ -119,6 +119,19 @@ export function cleanUrl (url) { return url; } +/* Extract url params if any and store them in requestParams attribute. + Return the options params updated */ +export function getUrlParams (options) { + if (options.url.indexOf('?') !== -1) { + options.requestParams = options.requestParams || {}; + var queryString = options.url.substring(options.url.indexOf('?') + 1); + options.url = options.url.split('?')[0]; + options.requestParams = JSON.parse('{"' + decodeURI(queryString).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}'); + } + options.url = cleanUrl(options.url.split('?')[0]); + return options; +} + export function isArcgisOnline (url) { /* hosted feature services support geojson as an output format utility.arcgis.com services are proxied from a variety of ArcGIS Server vintages, and may not */ @@ -338,6 +351,7 @@ export function _updateMapAttribution (evt) { export var EsriUtil = { warn: warn, cleanUrl: cleanUrl, + getUrlParams: getUrlParams, isArcgisOnline: isArcgisOnline, geojsonTypeToArcGIS: geojsonTypeToArcGIS, responseToFeatureCollection: responseToFeatureCollection,