├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── W3W.Geocoder.js └── W3W.Geocoder.min.js ├── package.json ├── src └── js │ ├── Bootstrap.js │ ├── Geocoder.js │ ├── Utils.js │ └── Xhr.js └── test └── js ├── specs ├── environment.spec.js ├── geocoder.fr.spec.js ├── geocoder.spec.js └── multiple_requests.spec.js └── templates └── SpecRunner.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globalstrict": false, 3 | "globals": { 4 | "define": false, 5 | "module": false, 6 | "window": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | before_install: npm install -g grunt-cli 3 | install: npm install 4 | before_script: grunt build 5 | env: 6 | matrix: 7 | secure: hpC35rZJAy0nWdEO99KjQw+wmS9q2TVyORpj17PdC5ZHBxdfT+HzJ6E0DPQSxBl2o9TSs3Y/gPC+yMF4SyUqqXTNIBf0fHTyA+Rq5c0NUdxdrAzQ9IPDOMKb3fl4mvywL56FciOfn0n074DVBFNF7GVeOs9wMPEEAydQjfGePKJdNAs4fpz36UgWh6QArc7yXh9DEfRFZhbogaY3HDZihQIwR6PU0whLQvNrXjpn9wht6959AjFufmuIAtFz2hQSi+j+A2VMoSw4k/xn9hPZB8h21LSciW8065iBGgta9o64AZcD8Mol6qh5hViYFkF6XiVSUkpwCXoA10yu7wiXIIE3SOfSbuPM4u2WuSftq0sQSdIRCOCsngS1fmCJfAr/tWQEt1jXYmkx8BeS6QXzBwBbwWh+HetHJTxZrIU+17h2mN06+xmExlaYElcKyEJ+17OyIMKRdG5OtcwBj62OpTnYUrhF0eIyOn8UP3T+PLujpyg0pcSZoqX604Kvf2U2CN6T2uyVr7BsIy4G9pUGfyc/gQSK5CKA1jSsNB9aKQTXbtMLsot2qIvNOLD9WDBoCT7zJUrTrZ2ohWH0P8SjtZyNYKVvcozgQ5coEj33+wJgzaCb/cMx7EluYONTyLHME0vORN6y149+1ORtG0bLr7abi5nap8pJ3GzTDPFfuh8= 8 | notifications: 9 | slack: 10 | secure: g1ccWDarVcARm6KYl4hJYKzGrTmA9Ck/MjIM/G+jEBiIQ9QdpCum42FEfh/Hc64aP6WYpOjf416QWKbq3GcwXToWWQikZIIBbARhApmKeOcsw7yWhOFyPD0bJW0bO371VigQYxc9i80tGXsZ43JhY2mcIMGBYhVEpipT+9XRLQ1JavX2n1LXAA/u+8kWHAOJ4LGTahP89JnNbvbFehLpXVzk4mhJt/n+6XU23LYI3g9csd04uXXhcBTAqUzSC+eRnjQjCPKnBTtusigxt4Vl8SX9WYWnk12WuysO1b6oKTELprX/2F+q+8TPr/TKEqSmoW70ZY2Bw/sjFz+MpVLUIgbuDjFMQ+96HvY5BOLKwefC8paWmisMLuK4Iv83DNJabMDhZrO3rmc8MpE+AgKyMRQZH8Z0ezWM3BpV36hJvxIJ0ryVCYwiu2ZC9we3CpiDUEaEVebvNT+EepVTLo8zc/McsSbB2YqasiBGdOthybYHK+jviFqy9cEz8jMubr1pF3jQmNL7g5adsWT2312H9xG7Sa60YXoOd44E2XNgAdrc61GmqBhCBe8+bmSPLJRBdtj6CZemt9wRwZ3n4uKeb2hvjrszfuGCXjuU3yYE6eGPYlSF0kFxyozLdYcgnb1OFymmETymFm5rUQyfRUBIR0ACa/yhNciImQYLkyAm8jU= 11 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | require('load-grunt-tasks')(grunt); 3 | 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | clean: { 7 | rebuild: ['dist/*'] 8 | }, 9 | concat: { 10 | options: { 11 | banner: '(function() {\n', 12 | footer: '})();' 13 | }, 14 | js: { 15 | src: [ 16 | 'src/js/Bootstrap.js', 17 | 'src/js/Xhr.js', 18 | 'src/js/Utils.js', 19 | 'src/js/Geocoder.js' 20 | ], 21 | dest: 'dist/W3W.Geocoder.js' 22 | } 23 | }, 24 | jshint: { 25 | options: { 26 | jshintrc: true 27 | }, 28 | beforeconcat: ['src/js/**/*.js', 'test/js/**/*.js'], 29 | afterconcat: ['dist/W3W.Geocoder.js'], 30 | grunt: ['Gruntfile.js'] 31 | }, 32 | uglify: { 33 | js: { 34 | files: { 35 | 'dist/W3W.Geocoder.min.js': ['dist/W3W.Geocoder.js'] 36 | } 37 | } 38 | }, 39 | jasmine: { 40 | js: { 41 | src: 'dist/W3W.Geocoder.js', 42 | options: { 43 | specs: 'test/js/**/*.spec.js', 44 | vendor: ['node_modules/jasmine-expect/dist/jasmine-matchers.js'], 45 | template: 'test/js/templates/SpecRunner.tmpl', 46 | templateOptions: { 47 | api_key: process.env.W3W_API_KEY 48 | }, 49 | '--web-security' : false, 50 | '--local-to-remote-url-access' : true, 51 | '--ignore-ssl-errors' : true 52 | } 53 | } 54 | }, 55 | version: { 56 | project: { 57 | src: ['bower.json', 'src/js/Bootstrap.js', 'package.json'] 58 | } 59 | }, 60 | watch: { 61 | options: { 62 | livereload: true, 63 | }, 64 | grunt: { 65 | files: ['Gruntfile.js'], 66 | tasks: ['jshint:grunt', 'build'], 67 | }, 68 | js: { 69 | files: ['src/js/**/*.js'], 70 | tasks: ['jshint', 'concat'] 71 | }, 72 | uglify: { 73 | files: ['dist/*.js', '!dist/*.min.js'], 74 | tasks: ['uglify'] 75 | }, 76 | test: { 77 | files: ['dist/*.js', '!dist/*.min.js', 'test/js/**/*.tmpl', 'test/js/specs/**/*.js'], 78 | tasks: ['jshint', 'test'] 79 | } 80 | } 81 | }); 82 | 83 | grunt.registerTask('default', ['watch']); 84 | grunt.registerTask('nodsstore', function() { 85 | grunt.file.expand({ 86 | filter: 'isFile', 87 | cwd: '.' 88 | }, ['**/.DS_Store']).forEach(function(file) { 89 | grunt.file.delete(file); 90 | }); 91 | }); 92 | grunt.registerTask('test', ['build', 'jasmine']); 93 | grunt.registerTask('build', ['nodsstore', 'jshint', 'concat', 'uglify']); 94 | grunt.registerTask('rebuild', ['clean', 'build', 'test']); 95 | }; 96 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 what3words 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [DEPRECATED] Please use our [JavaScript Wrapper](https://docs.what3words.com/wrapper/javascript/). -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "w3w-javascript-wrapper", 3 | "version": "3.1.3", 4 | "homepage": "https://github.com/what3words/w3w-javascript-wrapper", 5 | "authors": [ 6 | "Will Henderson ", 7 | "Gary Gale ", 8 | "Arnaud Ferrand ", 9 | "David Piesse", 10 | "Oliver Svenson" 11 | ], 12 | "description": "Javascript wrapper for the what3words API", 13 | "main": "dist/W3W.Geocoder.js", 14 | "moduleType": [ 15 | "globals" 16 | ], 17 | "keywords": [ 18 | "what3words", 19 | "javascript", 20 | "api" 21 | ], 22 | "license": "MIT", 23 | "ignore": [ 24 | "**/.*", 25 | "node_modules", 26 | "bower_components" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /dist/W3W.Geocoder.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | /*jshint -W097 */ 3 | 'use strict'; 4 | 5 | var W3W = { 6 | version: '3.2.0' 7 | }; 8 | 9 | if (typeof module === 'object' && typeof module.exports === 'object') { 10 | module.exports = W3W; 11 | } 12 | 13 | else if (typeof define === 'function' && define.amd) { 14 | define(W3W); 15 | } 16 | 17 | if (typeof window !== 'undefined') { 18 | var oldW3W = window.W3W; 19 | 20 | W3W.noConflict = function() { 21 | window.W3W = oldW3W; 22 | return this; 23 | }; 24 | 25 | window.W3W = W3W; 26 | } 27 | 28 | W3W.Xhr = { 29 | getXhr: function() { 30 | if (window.XMLHttpRequest) { 31 | return window.XMLHttpRequest; 32 | } 33 | else { 34 | if (window.ActiveXObject) { 35 | try { 36 | return new ActiveXObject('MSxml2.XMLHTTP'); 37 | } 38 | catch (e) { 39 | try { 40 | return new ActiveXObject('Microsoft.XMLHTTP'); 41 | } 42 | catch (exc) { 43 | return false; 44 | } 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | }, 51 | 52 | handleRequest: function(url, callback, method, body) { 53 | var xhr = new XMLHttpRequest(); 54 | method = (method) ? method : 'GET'; 55 | 56 | xhr.open(method, url, true); 57 | xhr.onreadystatechange = function(event) { 58 | var json; 59 | if (xhr.readyState == 4) { 60 | if (xhr.status == 200) { 61 | json = JSON.parse(xhr.responseText); 62 | if (json.hasOwnProperty('error') && callback.onFailure) { 63 | callback.onFailure(json); 64 | } 65 | else if (callback.onSuccess) { 66 | callback.onSuccess(json); 67 | } 68 | } 69 | else { 70 | if (callback.onFailure) { 71 | json = JSON.parse(xhr.responseText); 72 | callback.onFailure(json); 73 | } 74 | } 75 | } 76 | }; 77 | 78 | if (body) { 79 | xhr.setRequestHeader('Content-Length', body.length); 80 | xhr.send(body); 81 | } 82 | else { 83 | xhr.send(); 84 | } 85 | } 86 | }; 87 | 88 | W3W.Utils = { 89 | mergeOptions: function(dest) { 90 | var i; 91 | var j; 92 | var len; 93 | var src; 94 | 95 | var options = JSON.parse(JSON.stringify(dest)); 96 | 97 | for (i=1, len = arguments.length; i (http://www.garygale.com)", 19 | "contributors": [ 20 | { 21 | "name": "Gary Gale", 22 | "email": "gary@vicchi.org" 23 | }, 24 | { 25 | "name": "Will Henderson", 26 | "email": "will@what3words.com" 27 | }, 28 | { 29 | "name": "David Piesse" 30 | }, 31 | { 32 | "name": "Oliver Svenson" 33 | }, 34 | { 35 | "name": "Arnaud Ferrand", 36 | "email": "arnaud@what3words.com" 37 | } 38 | ], 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/what3words/w3w-javascript-wrapper/issues" 42 | }, 43 | "homepage": "https://github.com/what3words/w3w-javascript-wrapper#readme", 44 | "devDependencies": { 45 | "grunt": "^0.4.5", 46 | "grunt-contrib-clean": "^1.0.0", 47 | "grunt-contrib-concat": "^0.5.1", 48 | "grunt-contrib-jasmine": "^1.0.3", 49 | "grunt-contrib-jshint": "^0.11.2", 50 | "grunt-contrib-uglify": "^0.9.1", 51 | "grunt-contrib-watch": "^0.6.1", 52 | "grunt-version": "^1.1.1", 53 | "jasmine-expect": "^2.0.2", 54 | "load-grunt-tasks": "^3.5.0" 55 | }, 56 | "dependencies": {} 57 | } 58 | -------------------------------------------------------------------------------- /src/js/Bootstrap.js: -------------------------------------------------------------------------------- 1 | /*jshint -W097 */ 2 | 'use strict'; 3 | 4 | var W3W = { 5 | version: '3.2.0' 6 | }; 7 | 8 | if (typeof module === 'object' && typeof module.exports === 'object') { 9 | module.exports = W3W; 10 | } 11 | 12 | else if (typeof define === 'function' && define.amd) { 13 | define(W3W); 14 | } 15 | 16 | if (typeof window !== 'undefined') { 17 | var oldW3W = window.W3W; 18 | 19 | W3W.noConflict = function() { 20 | window.W3W = oldW3W; 21 | return this; 22 | }; 23 | 24 | window.W3W = W3W; 25 | } 26 | -------------------------------------------------------------------------------- /src/js/Geocoder.js: -------------------------------------------------------------------------------- 1 | W3W.Geocoder = function(options) { 2 | this.base_url = 'https://api.what3words.com/v2/' ; 3 | 4 | if (typeof options === 'undefined') { 5 | throw new Error('Missing what3words options'); 6 | } 7 | else if (options && !options.hasOwnProperty('key')) { 8 | throw new Error('Missing what3words API key'); 9 | } 10 | this.options = { 11 | lang: 'en', 12 | format: 'json' 13 | }; 14 | this.options = W3W.Utils.mergeOptions(this.options, options); 15 | if (this.options.hasOwnProperty('base_url')) { 16 | this.base_url = this.options.base_url; 17 | delete this.options.base_url; 18 | } 19 | this.urls = { 20 | forward: this.base_url + 'forward', 21 | reverse: this.base_url + 'reverse', 22 | autosuggest: this.base_url + 'autosuggest', 23 | standardblend: this.base_url + 'standardblend', 24 | autosuggest_ml: this.base_url + 'autosuggest-ml', 25 | standardblend_ml: this.base_url + 'standardblend-ml', 26 | grid: this.base_url + 'grid', 27 | languages: this.base_url + 'languages' 28 | }; 29 | }; 30 | 31 | // var params = { 32 | // addr: '3-word-address', 33 | // lang: 'en', 34 | // format: 'json|geojson' 35 | // }; 36 | W3W.Geocoder.prototype.forward = function(params, callback) { 37 | if (typeof params === 'undefined' || typeof params !== 'object') { 38 | throw new Error('Missing or invalid params object'); 39 | } 40 | 41 | if (params) { 42 | if (!params.hasOwnProperty('addr')) { 43 | throw new Error('The params object is missing required addr property'); 44 | } 45 | else if (typeof params.addr !== 'string') { 46 | throw new Error('params.addr must be a string'); 47 | } 48 | 49 | if (params.hasOwnProperty('lang') && typeof params.lang !== 'string') { 50 | throw new Error('params.lang must be a string'); 51 | } 52 | 53 | if (params.hasOwnProperty('format')) { 54 | if (typeof params.format !== 'string') { 55 | throw new Error('params.format must be a string'); 56 | } 57 | else if (params.format !== 'json' && params.format !== 'geojson') { 58 | throw new Error('params.format must have a value of "json" or "geojson"'); 59 | } 60 | } 61 | } 62 | 63 | if (typeof callback === 'undefined') { 64 | throw new Error('Missing callback parameter'); 65 | } 66 | else if (typeof callback !== 'object') { 67 | throw new Error('Missing or invalid callback parameter'); 68 | } 69 | 70 | params = W3W.Utils.mergeOptions(this.options, params); 71 | var url = this.urls.forward + '?' + W3W.Utils.assembleQuery(params); 72 | W3W.Xhr.handleRequest(url, callback); 73 | }; 74 | 75 | // var params = { 76 | // coords: [lat, long], 77 | // coords: 'lat,long', 78 | // lang: 'en', 79 | // format: 'json|geojson' 80 | // }; 81 | W3W.Geocoder.prototype.reverse = function(params, callback) { 82 | if (typeof params === 'undefined' || typeof params !== 'object') { 83 | throw new Error('Missing or invalid params object'); 84 | } 85 | 86 | if (params) { 87 | if (!params.hasOwnProperty('coords')) { 88 | throw new Error('The params object is missing required coords property'); 89 | } 90 | else { 91 | params.coords = this._formatCoords(params.coords); 92 | if (null === params.coords) { 93 | throw new Error('Invalid format coordinates for params.coords'); 94 | } 95 | } 96 | 97 | if (params.hasOwnProperty('lang') && typeof params.lang !== 'string') { 98 | throw new Error('params.lang must be a string'); 99 | } 100 | 101 | if (params.hasOwnProperty('format')) { 102 | if (typeof params.format !== 'string') { 103 | throw new Error('params.format must be a string'); 104 | } 105 | else if (params.format !== 'json' && params.format !== 'geojson') { 106 | throw new Error('params.format must have a value of "json" or "geojson"'); 107 | } 108 | } 109 | } 110 | 111 | if (typeof callback === 'undefined') { 112 | throw new Error('Missing callback parameter'); 113 | } 114 | else if (typeof callback !== 'object') { 115 | throw new Error('Missing or invalid callback parameter'); 116 | } 117 | 118 | params = W3W.Utils.mergeOptions(this.options, params); 119 | var url = this.urls.reverse + '?' + W3W.Utils.assembleQuery(params); 120 | W3W.Xhr.handleRequest(url, callback); 121 | }; 122 | 123 | // var params = { 124 | // lang: 'en', 125 | // addr: '3-word-address' 126 | // focus: [lat, lng], 127 | // focus: 'lat,lng', 128 | // clip: { 129 | // type: 'none' 130 | // } 131 | // clip: { 132 | // type: 'radius', 133 | // focus: [lat, lng], 134 | // focus: 'lat,lng', 135 | // distance: km 136 | // }, 137 | // clip: { 138 | // type: 'focus' 139 | // distance: km 140 | // }, 141 | // clip: { 142 | // type: 'bbox', 143 | // bbox: [lat,lng,lat,lng], 144 | // bbox: 'lat,lng,lat,lng' 145 | // } 146 | // }; 147 | W3W.Geocoder.prototype.autosuggest = function(params, callback) { 148 | if (typeof params === 'undefined' || typeof params !== 'object') { 149 | throw new Error('Missing or invalid params object'); 150 | } 151 | 152 | var clip = {}; 153 | 154 | if (params) { 155 | if (!params.hasOwnProperty('addr')) { 156 | throw new Error('The params object is missing required addr property'); 157 | } 158 | else if (typeof params.addr !== 'string') { 159 | throw new Error('params.addr must be a string'); 160 | } 161 | 162 | if (params.hasOwnProperty('focus')) { 163 | params.focus = this._formatCoords(params.focus); 164 | if (null === params.focus) { 165 | throw new Error('Invalid format coordinates for params.focus'); 166 | } 167 | } 168 | 169 | if (!params.hasOwnProperty('lang')) { 170 | throw new Error('The params object is missing required lang property'); 171 | } 172 | else if (typeof params.lang !== 'string') { 173 | throw new Error('params.lang must be a string'); 174 | } 175 | 176 | if (params.hasOwnProperty('format')) { 177 | if (typeof params.format !== 'string') { 178 | throw new Error('params.format must be a string'); 179 | } 180 | else if (params.format !== 'json') { 181 | throw new Error('params.format must have a value of "json"'); 182 | } 183 | } 184 | 185 | if (params.hasOwnProperty('clip')) { 186 | if (!params.clip.hasOwnProperty('type')) { 187 | throw new Error('Invalid clipping policy type for params.clip'); 188 | } 189 | 190 | switch (params.clip.type) { 191 | case 'none': 192 | clip = { 193 | clip: 'none' 194 | }; 195 | break; 196 | 197 | case 'radius': 198 | if (!params.clip.hasOwnProperty('distance')) { 199 | throw new Error('Invalid clipping policy for type radius; missing distance property'); 200 | } 201 | 202 | else if (!params.clip.hasOwnProperty('focus')) { 203 | throw new Error('Invalid clipping policy for type radius; missing focus property'); 204 | 205 | } 206 | 207 | else { 208 | params.clip.focus = this._formatCoords(params.clip.focus); 209 | if (null === params.focus) { 210 | throw new Error('Invalid format coordinates for params.clip.focus'); 211 | } 212 | } 213 | 214 | clip = { 215 | clip: 'radius(' + params.clip.focus + ',' + params.clip.distance + ')' 216 | }; 217 | break; 218 | 219 | case 'focus': 220 | if (!params.clip.hasOwnProperty('distance')) { 221 | throw new Error('Invalid clipping policy for type focus; missing distance property'); 222 | } 223 | else if (!params.hasOwnProperty('focus') || params.focus === null) { 224 | throw new Error('Invalid clipping policy for type focus; missing or invalid focus property'); 225 | } 226 | 227 | clip = { 228 | clip: 'focus(' + params.clip.distance + ')' 229 | }; 230 | break; 231 | 232 | case 'bbox': 233 | if (!params.clip.hasOwnProperty('bbox')) { 234 | throw new Error('Invalid clipping policy for type bbox; missing bbox property'); 235 | } 236 | params.clip.bbox = this._formatBoundingBox(params.clip.bbox); 237 | if (null === params.clip.bbox) { 238 | throw new Error('Invalid format coordinates for params.clip.bbox'); 239 | } 240 | 241 | clip = { 242 | clip: 'bbox(' + params.clip.bbox + ')' 243 | }; 244 | break; 245 | 246 | default: 247 | throw new Error('Invalid or unrecognised clipping policy type'); 248 | } 249 | } 250 | } 251 | 252 | if (typeof callback === 'undefined') { 253 | throw new Error('Missing callback parameter'); 254 | } 255 | else if (typeof callback !== 'object') { 256 | throw new Error('Missing or invalid callback parameter'); 257 | } 258 | 259 | params = W3W.Utils.mergeOptions(this.options, params, clip); 260 | var url = this.urls.autosuggest + '?' + W3W.Utils.assembleQuery(params); 261 | W3W.Xhr.handleRequest(url, callback); 262 | }; 263 | 264 | // var params = { 265 | // lang: 'en', 266 | // addr: '3-word-address' 267 | // focus: [lat, lng], 268 | // focus: 'lat,lng', 269 | // clip: { 270 | // type: 'none' 271 | // } 272 | // clip: { 273 | // type: 'radius', 274 | // focus: [lat, lng], 275 | // focus: 'lat,lng', 276 | // distance: km 277 | // }, 278 | // clip: { 279 | // type: 'focus' 280 | // distance: km 281 | // }, 282 | // clip: { 283 | // type: 'bbox', 284 | // bbox: [lat,lng,lat,lng], 285 | // bbox: 'lat,lng,lat,lng' 286 | // } 287 | // }; 288 | W3W.Geocoder.prototype.autosuggest_ml = function(params, callback) { 289 | if (typeof params === 'undefined' || typeof params !== 'object') { 290 | throw new Error('Missing or invalid params object'); 291 | } 292 | 293 | var clip = {}; 294 | 295 | if (params) { 296 | if (!params.hasOwnProperty('addr')) { 297 | throw new Error('The params object is missing required addr property'); 298 | } 299 | else if (typeof params.addr !== 'string') { 300 | throw new Error('params.addr must be a string'); 301 | } 302 | 303 | if (params.hasOwnProperty('focus')) { 304 | params.focus = this._formatCoords(params.focus); 305 | if (null === params.focus) { 306 | throw new Error('Invalid format coordinates for params.focus'); 307 | } 308 | } 309 | 310 | if (!params.hasOwnProperty('lang')) { 311 | throw new Error('The params object is missing required lang property'); 312 | } 313 | else if (typeof params.lang !== 'string') { 314 | throw new Error('params.lang must be a string'); 315 | } 316 | 317 | if (params.hasOwnProperty('format')) { 318 | if (typeof params.format !== 'string') { 319 | throw new Error('params.format must be a string'); 320 | } 321 | else if (params.format !== 'json') { 322 | throw new Error('params.format must have a value of "json"'); 323 | } 324 | } 325 | 326 | if (params.hasOwnProperty('clip')) { 327 | if (!params.clip.hasOwnProperty('type')) { 328 | throw new Error('Invalid clipping policy type for params.clip'); 329 | } 330 | 331 | switch (params.clip.type) { 332 | case 'none': 333 | clip = { 334 | clip: 'none' 335 | }; 336 | break; 337 | 338 | case 'radius': 339 | if (!params.clip.hasOwnProperty('distance')) { 340 | throw new Error('Invalid clipping policy for type radius; missing distance property'); 341 | } 342 | 343 | else if (!params.clip.hasOwnProperty('focus')) { 344 | throw new Error('Invalid clipping policy for type radius; missing focus property'); 345 | 346 | } 347 | 348 | else { 349 | params.clip.focus = this._formatCoords(params.clip.focus); 350 | if (null === params.focus) { 351 | throw new Error('Invalid format coordinates for params.clip.focus'); 352 | } 353 | } 354 | 355 | clip = { 356 | clip: 'radius(' + params.clip.focus + ',' + params.clip.distance + ')' 357 | }; 358 | break; 359 | 360 | case 'focus': 361 | if (!params.clip.hasOwnProperty('distance')) { 362 | throw new Error('Invalid clipping policy for type focus; missing distance property'); 363 | } 364 | else if (!params.hasOwnProperty('focus') || params.focus === null) { 365 | throw new Error('Invalid clipping policy for type focus; missing or invalid focus property'); 366 | } 367 | 368 | clip = { 369 | clip: 'focus(' + params.clip.distance + ')' 370 | }; 371 | break; 372 | 373 | case 'bbox': 374 | if (!params.clip.hasOwnProperty('bbox')) { 375 | throw new Error('Invalid clipping policy for type bbox; missing bbox property'); 376 | } 377 | params.clip.bbox = this._formatBoundingBox(params.clip.bbox); 378 | if (null === params.clip.bbox) { 379 | throw new Error('Invalid format coordinates for params.clip.bbox'); 380 | } 381 | 382 | clip = { 383 | clip: 'bbox(' + params.clip.bbox + ')' 384 | }; 385 | break; 386 | 387 | default: 388 | throw new Error('Invalid or unrecognised clipping policy type'); 389 | } 390 | } 391 | } 392 | 393 | if (typeof callback === 'undefined') { 394 | throw new Error('Missing callback parameter'); 395 | } 396 | else if (typeof callback !== 'object') { 397 | throw new Error('Missing or invalid callback parameter'); 398 | } 399 | 400 | params = W3W.Utils.mergeOptions(this.options, params, clip); 401 | var url = this.urls.autosuggest_ml + '?' + W3W.Utils.assembleQuery(params); 402 | W3W.Xhr.handleRequest(url, callback); 403 | }; 404 | 405 | // var params = { 406 | // addr: '3-word-address', 407 | // lang: 'en', 408 | // focus: '[lat, lng] 409 | // }; 410 | W3W.Geocoder.prototype.standardblend = function(params, callback) { 411 | if (typeof params === 'undefined' || typeof params !== 'object') { 412 | throw new Error('Missing or invalid params object'); 413 | } 414 | 415 | if (params) { 416 | if (!params.hasOwnProperty('addr')) { 417 | throw new Error('The params object is missing required addr property'); 418 | } 419 | else if (typeof params.addr !== 'string') { 420 | throw new Error('params.addr must be a string'); 421 | } 422 | 423 | if (params.hasOwnProperty('focus')) { 424 | params.focus = this._formatCoords(params.focus); 425 | if (null === params.focus) { 426 | throw new Error('Invalid format coordinates for params.focus'); 427 | } 428 | } 429 | 430 | if (!params.hasOwnProperty('lang')) { 431 | throw new Error('The params object is missing required lang property'); 432 | } 433 | else if (typeof params.lang !== 'string') { 434 | throw new Error('params.lang must be a string'); 435 | } 436 | 437 | if (params.hasOwnProperty('format')) { 438 | if (typeof params.format !== 'string') { 439 | throw new Error('params.format must be a string'); 440 | } 441 | else if (params.format !== 'json') { 442 | throw new Error('params.format must have a value of "json"'); 443 | } 444 | } 445 | } 446 | 447 | if (typeof callback === 'undefined') { 448 | throw new Error('Missing callback parameter'); 449 | } 450 | else if (typeof callback !== 'object') { 451 | throw new Error('Missing or invalid callback parameter'); 452 | } 453 | 454 | params = W3W.Utils.mergeOptions(this.options, params); 455 | var url = this.urls.standardblend + '?' + W3W.Utils.assembleQuery(params); 456 | W3W.Xhr.handleRequest(url, callback); 457 | }; 458 | 459 | // var params = { 460 | // addr: '3-word-address', 461 | // lang: 'en', 462 | // focus: '[lat, lng] 463 | // }; 464 | W3W.Geocoder.prototype.standardblend_ml = function(params, callback) { 465 | if (typeof params === 'undefined' || typeof params !== 'object') { 466 | throw new Error('Missing or invalid params object'); 467 | } 468 | 469 | if (params) { 470 | if (!params.hasOwnProperty('addr')) { 471 | throw new Error('The params object is missing required addr property'); 472 | } 473 | else if (typeof params.addr !== 'string') { 474 | throw new Error('params.addr must be a string'); 475 | } 476 | 477 | if (params.hasOwnProperty('focus')) { 478 | params.focus = this._formatCoords(params.focus); 479 | if (null === params.focus) { 480 | throw new Error('Invalid format coordinates for params.focus'); 481 | } 482 | } 483 | 484 | if (!params.hasOwnProperty('lang')) { 485 | throw new Error('The params object is missing required lang property'); 486 | } 487 | else if (typeof params.lang !== 'string') { 488 | throw new Error('params.lang must be a string'); 489 | } 490 | 491 | if (params.hasOwnProperty('format')) { 492 | if (typeof params.format !== 'string') { 493 | throw new Error('params.format must be a string'); 494 | } 495 | else if (params.format !== 'json') { 496 | throw new Error('params.format must have a value of "json"'); 497 | } 498 | } 499 | } 500 | 501 | if (typeof callback === 'undefined') { 502 | throw new Error('Missing callback parameter'); 503 | } 504 | else if (typeof callback !== 'object') { 505 | throw new Error('Missing or invalid callback parameter'); 506 | } 507 | 508 | params = W3W.Utils.mergeOptions(this.options, params); 509 | var url = this.urls.standardblend_ml + '?' + W3W.Utils.assembleQuery(params); 510 | W3W.Xhr.handleRequest(url, callback); 511 | }; 512 | 513 | // var params = { 514 | // bbox: [nelat, nelng, swlat, swlng], 515 | // format: 'json|geojson' 516 | // }; 517 | W3W.Geocoder.prototype.grid = function(params, callback) { 518 | if (typeof params === 'undefined' || typeof params !== 'object') { 519 | throw new Error('Missing or invalid params object'); 520 | } 521 | 522 | if (params) { 523 | if (!params.hasOwnProperty('bbox')) { 524 | throw new Error('The params object is missing required bbox property'); 525 | } 526 | 527 | params.bbox = this._formatBoundingBox(params.bbox); 528 | if (null === params.bbox) { 529 | throw new Error('Invalid format coordinates for params.bbox'); 530 | } 531 | 532 | if (params.hasOwnProperty('format')) { 533 | if (typeof params.format !== 'string') { 534 | throw new Error('params.format must be a string'); 535 | } 536 | else if (params.format !== 'json' && params.format !== 'geojson') { 537 | throw new Error('params.format must have a value of "json" or "geojson"'); 538 | } 539 | } 540 | } 541 | 542 | if (typeof callback === 'undefined') { 543 | throw new Error('Missing callback parameter'); 544 | } 545 | else if (typeof callback !== 'object') { 546 | throw new Error('Missing or invalid callback parameter'); 547 | } 548 | 549 | params = W3W.Utils.mergeOptions(this.options, params); 550 | var url = this.urls.grid + '?' + W3W.Utils.assembleQuery(params); 551 | W3W.Xhr.handleRequest(url, callback); 552 | }; 553 | 554 | W3W.Geocoder.prototype.languages = function(callback) { 555 | if (typeof callback === 'undefined') { 556 | throw new Error('Missing callback parameter'); 557 | } 558 | else if (typeof callback !== 'object') { 559 | throw new Error('Missing or invalid callback parameter'); 560 | } 561 | 562 | var params = { 563 | key: this.options.key 564 | }; 565 | var url = this.urls.languages + '?' + W3W.Utils.assembleQuery(params); 566 | W3W.Xhr.handleRequest(url, callback); 567 | }; 568 | 569 | W3W.Geocoder.prototype._formatCoords = function(coords) { 570 | if (typeof coords === 'object' && coords instanceof Array && coords.length === 2) { 571 | return coords.join(','); 572 | } 573 | else if (typeof coords !== 'string' && !coords.match(/^[-.0-9]{1,},[-.0-9]{1,}$/)) { 574 | return coords; 575 | } 576 | 577 | return null; 578 | }; 579 | 580 | W3W.Geocoder.prototype._formatBoundingBox = function(coords) { 581 | if (typeof coords === 'object' && coords instanceof Array && coords.length === 4) { 582 | return coords.join(','); 583 | } 584 | else if (typeof coords !== 'string' && !coords.match(/^[-.0-9]{1,},[-.0-9]{1,},[-.0-9]{1,},[-.0-9]{1,}$/)) { 585 | return coords; 586 | } 587 | 588 | return null; 589 | }; 590 | -------------------------------------------------------------------------------- /src/js/Utils.js: -------------------------------------------------------------------------------- 1 | W3W.Utils = { 2 | mergeOptions: function(dest) { 3 | var i; 4 | var j; 5 | var len; 6 | var src; 7 | 8 | var options = JSON.parse(JSON.stringify(dest)); 9 | 10 | for (i=1, len = arguments.length; i 2 | 3 | 4 | 5 | 6 | Jasmine Spec Runner 7 | 8 | <% css.forEach(function(style){ %> 9 | 10 | <% }) %> 11 | 14 | 15 | 16 | 17 | <% with (scripts) { %> 18 | <% [].concat(polyfills, jasmine, boot, vendor, helpers, src, specs,reporters).forEach(function(script){ %> 19 | 20 | <% }) %> 21 | <% }; %> 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------