From 5fc7a47f6daf5c05da31794b6ba5a7c7dfd0c931 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Mon, 10 Jun 2013 15:04:07 -0700 Subject: [PATCH] Use querystring, stop manually building urls --- app/assets/javascripts/application.js | 74 ++------ app/assets/javascripts/browse.js | 16 +- app/assets/javascripts/index.js | 13 +- app/assets/javascripts/querystring.js | 256 ++++++++++++++++++++++++++ app/views/site/_search.html.erb | 2 +- 5 files changed, 297 insertions(+), 64 deletions(-) create mode 100644 app/assets/javascripts/querystring.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ee9b16ff1..eb338aa93 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,6 +16,9 @@ //= require richtext //= require resize //= require geocoder +//= require querystring + +var querystring = require('querystring'); function zoomPrecision(zoom) { var decimals = Math.pow(10, Math.floor(zoom/3)); @@ -54,13 +57,15 @@ function updatelinks(loc, zoom, layers, bounds, object) { $("#shortlinkanchor").each(setShortlink); function setGeolink(index, link) { - var args = getArgs(link.href); + var base = link.href.split('?')[0]; + var qs = link.href.split('?')[1]; + var args = querystring.parse(qs); if ($(link).hasClass("llz")) { $.extend(args, { - lat: lat, - lon: lon, - zoom: zoom + lat: '' + lat, + lon: '' + lon, + zoom: '' + zoom }); } else if (minlon && $(link).hasClass("bbox")) { $.extend(args, { @@ -68,13 +73,8 @@ function updatelinks(loc, zoom, layers, bounds, object) { }); } - if (layers && $(link).hasClass("layers")) { - args.layers = layers; - } - - if (object && $(link).hasClass("object")) { - args[object.type] = object.id; - } + if (layers && $(link).hasClass("layers")) args.layers = layers; + if (object && $(link).hasClass("object")) args[object.type] = object.id; var minzoom = $(link).data("minzoom"); if (minzoom) { @@ -92,14 +92,16 @@ function updatelinks(loc, zoom, layers, bounds, object) { } } - link.href = setArgs(link.href, args); + link.href = base + '?' + querystring.stringify(args); } function setShortlink() { - var args = getArgs(this.href); - var code = makeShortCode(lat, lon, zoom); - var prefix = shortlinkPrefix(); + var base = link.href.split('?')[0], + qs = link.href.split('?')[1], + args = querystring.parse(qs), + code = makeShortCode(lat, lon, zoom), + prefix = shortlinkPrefix(); // Add ?{node,way,relation}=id to the arguments if (object) { @@ -118,7 +120,7 @@ function updatelinks(loc, zoom, layers, bounds, object) { // which encodes lat/lon/zoom. If new URL parameters are added to // the main slippy map this needs to be changed. if (args.layers || object) { - this.href = setArgs(prefix + "/go/" + code, args); + this.href = prefix + "/go/" + code + '?' + querystring.stringify(args); } else { this.href = prefix + "/go/" + code; } @@ -140,46 +142,6 @@ function shortlinkPrefix() { } } -/* - * Called to get the arguments from a URL as a hash. - */ -function getArgs(url) { - var args = {}; - var querystart = url.indexOf("?"); - - if (querystart >= 0) { - var querystring = url.substring(querystart + 1); - var queryitems = querystring.split("&"); - - for (var i = 0; i < queryitems.length; i++) { - if (match = queryitems[i].match(/^(.*)=(.*)$/)) { - args[unescape(match[1])] = unescape(match[2]); - } else { - args[unescape(queryitems[i])] = null; - } - } - } - - return args; -} - -/* - * Called to set the arguments on a URL from the given hash. - */ -function setArgs(url, args) { - var queryitems = []; - - for (arg in args) { - if (args[arg] == null) { - queryitems.push(escape(arg)); - } else { - queryitems.push(escape(arg) + "=" + escape(args[arg])); - } - } - - return url.replace(/\?.*$/, "") + "?" + queryitems.join("&"); -} - /* * Called to interlace the bits in x and y, making a Morton code. */ diff --git a/app/assets/javascripts/browse.js b/app/assets/javascripts/browse.js index e21cbd672..4edee5952 100644 --- a/app/assets/javascripts/browse.js +++ b/app/assets/javascripts/browse.js @@ -9,9 +9,21 @@ $(document).ready(function () { $("#linkloader").load(function () { loaded = true; }); if (select) { - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + left + "&top=" + top + "&right=" + right + "&bottom=" + bottom + "&select=" + select); + $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?" + + querystring.stringify({ + left: left, + top: top, + right: right, + bottom: bottom, + select: select + })); } else { - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + left + "&top=" + top + "&right=" + right + "&bottom=" + bottom); + $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?" + querystring.stringify({ + left: left, + top: top, + right: right, + bottom: bottom + })); } setTimeout(function () { diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index f95510f6c..5d6947d35 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -65,7 +65,7 @@ $(document).ready(function () { L.control.share({ getUrl: function(map) { - return setArgs('http://osm.org/', { + return 'http://osm.org/' + querystring.stringify({ lon: map.getCenter().lng, lat: map.getCenter().lat }); @@ -159,10 +159,13 @@ $(document).ready(function () { var loaded = false; $("#linkloader").load(function () { loaded = true; }); - $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?left=" + extent.getWest() - + "&bottom=" + extent.getSouth() - + "&right=" + extent.getEast() - + "&top=" + extent.getNorth()); + $("#linkloader").attr("src", "http://127.0.0.1:8111/load_and_zoom?" + + querystring.stringify({ + left: extent.getWest(), + bottom: extent.getSouth(), + right: extent.getEast(), + top: extent.getNorth() + })); setTimeout(function () { if (!loaded) alert(I18n.t('site.index.remote_failed')); diff --git a/app/assets/javascripts/querystring.js b/app/assets/javascripts/querystring.js new file mode 100644 index 000000000..16aa63c45 --- /dev/null +++ b/app/assets/javascripts/querystring.js @@ -0,0 +1,256 @@ +require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s + * MIT Licensed + */ + +/** + * Library version. + */ + +exports.version = '0.3.1'; + +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Cache non-integer test regexp. + */ + +var notint = /[^0-9]/; + +/** + * Parse the given query `str`, returning an object. + * + * @param {String} str + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + + function promote(parent, key) { + if (parent[key].length == 0) return parent[key] = {}; + var t = {}; + for (var i in parent[key]) t[i] = parent[key][i]; + parent[key] = t; + return t; + } + + return String(str) + .split('&') + .reduce(function(ret, pair){ + try{ + pair = decodeURIComponent(pair.replace(/\+/g, ' ')); + } catch(e) { + // ignore + } + + var eql = pair.indexOf('=') + , brace = lastBraceInKey(pair) + , key = pair.substr(0, brace || eql) + , val = pair.substr(brace || eql, pair.length) + , val = val.substr(val.indexOf('=') + 1, val.length) + , parent = ret; + + // ?foo + if ('' == key) key = pair, val = ''; + + // nested + if (~key.indexOf(']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + + function parse(parts, parent, key) { + var part = parts.shift(); + + // end + if (!part) { + if (isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + // array + } else { + obj = parent[key] = parent[key] || []; + if (']' == part) { + if (isArray(obj)) { + if ('' != val) obj.push(val); + } else if ('object' == typeof obj) { + obj[objectKeys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + // prop + } else if (~part.indexOf(']')) { + part = part.substr(0, part.length - 1); + if(notint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part); + // key + } else { + if(notint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part); + } + } + } + + parse(parts, parent, 'base'); + // optimize + } else { + if (notint.test(key) && isArray(parent.base)) { + var t = {}; + for(var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + set(parent.base, key, val); + } + + return ret; + }, {base: {}}).base; +}; + +/** + * Turn the given `obj` into a query string + * + * @param {Object} obj + * @return {String} + * @api public + */ + +var stringify = exports.stringify = function(obj, prefix) { + if (isArray(obj)) { + return stringifyArray(obj, prefix); + } else if ('[object Object]' == toString.call(obj)) { + return stringifyObject(obj, prefix); + } else if ('string' == typeof obj) { + return stringifyString(obj, prefix); + } else { + return prefix; + } +}; + +/** + * Stringify the given `str`. + * + * @param {String} str + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyString(str, prefix) { + if (!prefix) throw new TypeError('stringify expects an object'); + return prefix + '=' + encodeURIComponent(str); +} + +/** + * Stringify the given `arr`. + * + * @param {Array} arr + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyArray(arr, prefix) { + var ret = []; + if (!prefix) throw new TypeError('stringify expects an object'); + for (var i = 0; i < arr.length; i++) { + ret.push(stringify(arr[i], prefix + '[]')); + } + return ret.join('&'); +} + +/** + * Stringify the given `obj`. + * + * @param {Object} obj + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyObject(obj, prefix) { + var ret = [] + , keys = objectKeys(obj) + , key; + for (var i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + } + return ret.join('&'); +} + +/** + * Set `obj`'s `key` to `val` respecting + * the weird and wonderful syntax of a qs, + * where "foo=bar&foo=baz" becomes an array. + * + * @param {Object} obj + * @param {String} key + * @param {String} val + * @api private + */ + +function set(obj, key, val) { + var v = obj[key]; + if (undefined === v) { + obj[key] = val; + } else if (isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } +} + +/** + * Locate last brace in `str` within the key. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function lastBraceInKey(str) { + var len = str.length + , brace + , c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } +} + +},{}]},{},[]) +; \ No newline at end of file diff --git a/app/views/site/_search.html.erb b/app/views/site/_search.html.erb index c074a49a3..52adf66e1 100644 --- a/app/views/site/_search.html.erb +++ b/app/views/site/_search.html.erb @@ -1,7 +1,7 @@