Skip to content

Commit b7de73c

Browse files
committed
Fix parsing where no '?' in a uri is present (ie path only)
- also add tests for this scenario
1 parent b8b1771 commit b7de73c

File tree

2 files changed

+67
-42
lines changed

2 files changed

+67
-42
lines changed

jquery.querystring.js

+23-21
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
(function($) {
2-
2+
33
// Naive method of yanking the querystring portion from a string (just splits on the first '?', if present).
44
function extractQuery(string) {
55
if(string.indexOf('?') >= 0) {
66
return string.split('?')[1];
7-
} else {
7+
} else if(string.indexOf('=') >= 0) {
88
return string;
9+
} else {
10+
return '';
911
}
1012
};
11-
13+
1214
// Returns the JavaScript value of a querystring parameter.
1315
// Decodes the string & coerces it to the appropriate JavaScript type.
1416
// Examples:
@@ -23,7 +25,7 @@
2325
return value;
2426
}
2527
}
26-
28+
2729
// Takes a URL (or fragment) and parses the querystring portion into an object.
2830
// Returns an empty object if there is no querystring.
2931
function parse(url) {
@@ -33,40 +35,40 @@
3335
if(!query) {
3436
return params;
3537
}
36-
38+
3739
$.each(query.split('&'), function(idx, pair) {
3840
pair = pair.split('=');
3941
params[pair[0]] = parseValue(pair[1] || '');
4042
});
4143

4244
return params;
4345
};
44-
46+
4547
// Takes an object and converts it to a URL fragment suitable for use as a querystring.
4648
function serialize(params) {
4749
var pairs = [], currentKey, currentValue;
48-
50+
4951
for(key in params) {
5052
if(params.hasOwnProperty(key)) {
5153
currentKey = key;
5254
currentValue = params[key];
53-
55+
5456
if(typeof currentValue === 'object') {
5557
for(subKey in currentValue) {
5658
if(currentValue.hasOwnProperty(subKey)) {
5759
// If subKey is an integer, we have an array. In that case, use `person[]` instead of `person[0]`.
58-
pairs.push(currentKey + '[' + (isNaN(subKey, 10) ? subKey : '') + ']=' + encodeURIComponent(currentValue[subKey]));
60+
pairs.push(currentKey + '[' + (isNaN(subKey, 10) ? subKey : '') + ']=' + encodeURIComponent(currentValue[subKey]));
5961
}
6062
}
6163
} else {
62-
pairs.push(currentKey + '=' + encodeURIComponent(currentValue));
64+
pairs.push(currentKey + '=' + encodeURIComponent(currentValue));
6365
}
6466
}
6567
}
66-
68+
6769
return pairs.join("&");
6870
};
69-
71+
7072
// Public interface.
7173
$.querystring = function(param) {
7274
if(typeof param === 'string') {
@@ -75,7 +77,7 @@
7577
return serialize(param);
7678
}
7779
};
78-
80+
7981
// Adds a method to jQuery objects to get & querystring.
8082
// $('#my_link').querystring(); // => {name: "Joe", job: "Plumber"}
8183
// $('#my_link').querystring({name: 'Jack'}); // => Appends `?name=Jack` to href.
@@ -84,27 +86,27 @@
8486
existingData,
8587
newData = arguments[0] || {},
8688
clearExisting = arguments[1] || false;
87-
89+
8890
if(!elm.attr('href')) {
8991
return;
9092
}
91-
93+
9294
existingData = parse(elm.attr('href'));
93-
95+
9496
// Get the querystring & bail.
9597
if(arguments.length === 0) {
9698
return existingData;
9799
}
98-
100+
99101
// Set the querystring.
100102
if(clearExisting) {
101103
existingData = newData;
102104
} else {
103-
$.extend(existingData, newData);
105+
$.extend(existingData, newData);
104106
}
105107
elm.attr('href', elm.attr('href').split("?")[0] + "?" + serialize(existingData));
106108
return elm;
107-
109+
108110
};
109-
110-
})(jQuery);
111+
112+
})(jQuery);

tests/tests.js

+44-21
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
11
$(function() {
22

3-
3+
44
module("Serialize");
55

66
test("simple properties", function() {
77
equals($.querystring({name: "John"}), "name=John");
88
equals($.querystring({name: "John", age:59}), "name=John&age=59");
99
});
10-
10+
1111
test("properties requiring URI encoding", function() {
1212
equals($.querystring({name: "John Doe"}), "name=John%20Doe");
1313
equals($.querystring({name: "John Doe", garble: " /# #/ "}), "name=John%20Doe&garble=%20%2F%23%20%23%2F%20");
1414
});
15-
15+
1616
test("empty values", function() {
1717
equals($.querystring({}), "", "Empty objects serialize to empty strings.");
1818
equals($.querystring({name:null}), "", "Properties with null values are omitted from resulting string.");
1919
equals($.querystring({name:''}), "name=", 'Blank strings are included in result.');
2020
equals($.querystring({boring:false}), "boring=false", '`false` literal is included in result.');
2121
});
22-
22+
2323
test("arrays", function() {
2424
equals($.querystring({people: ['Larry', 'Curly', 'Moe']}), "people[]=Larry&people[]=Curly&people[]=Moe");
2525
});
26-
26+
2727
test("simple objects", function() {
2828
equals($.querystring({person: {name:"John", age:110}}), "person[name]=John&person[age]=110");
2929
});
30-
30+
3131
test("nested objects & arrays", function() {
3232
equals(
3333
$.querystring({person: {name:"John", age:110, drinks: ['Beer', 'Whisky', 'Wine'], location: {city: "New York", state:"NY"}}}),
3434
"person[name]=John&person[age]=110&person[drinks][]=Beer&person[drinks][]=Whisky&person[drinks][]=Wine&person[location][city]=New%20York&person[location][state]=NY"
3535
);
3636
});
37-
38-
37+
38+
3939
module("Parse");
40-
40+
4141
test("simple properties", function() {
4242
deepEqual($.querystring("?name=John"), {name: "John"}, "With leading '?'");
4343
deepEqual($.querystring("name=John"), {name: "John"}, "Without leading '?'");
4444
deepEqual($.querystring("http://google.com/?name=John"), {name: "John"}, "With domains prefix.");
4545
});
46-
46+
4747
test("coercion to native types", function() {
4848
deepEqual($.querystring('?boring=false'), {boring:false}, 'Should parse true/false to native boolean types.');
4949
deepEqual($.querystring('?awesome=true'), {awesome:true}, 'Should parse true/false to native boolean types.');
@@ -55,34 +55,57 @@ $(function() {
5555
deepEqual($.querystring("?name=John%20Doe"), {name: "John Doe"});
5656
deepEqual($.querystring("?name=John%20Doe&garble=%20%2F%23%20%23%2F%20"), {name: "John Doe", garble: " /# #/ "});
5757
});
58-
58+
5959
test('empty values', function() {
6060
deepEqual($.querystring('?awesome'), {awesome:""});
6161
deepEqual($.querystring('?awesome='), {awesome:""});
6262
});
63-
63+
6464
test('arrays', function() {
6565
deepEqual(
6666
$.querystring("?drinks[]=Beer&drinks[]=Whisky&drinks[]=Wine"),
6767
{drinks: ['Beer', 'Whisky', 'Wine']}
6868
);
6969
});
70-
70+
7171
test('simple objects', function() {
7272
deepEqual($.querystring("?person[name]=John"), {person: {name: "John"}});
7373
});
74-
74+
7575
test('nested objects & arrays', function() {
7676
deepEqual(
7777
$.querystring("?person[location][city]=NYC&&person[drinks][]=Beer&person[drinks][]=Whisky&person[drinks][]=Wine"),
7878
{person: {location: {city:'NYC'}}, drinks: ['Beer', 'Whisky', 'Wine']}
79-
);
79+
);
80+
});
81+
82+
test('missing querystring', function() {
83+
deepEqual($.querystring('/foo?'), {}, 'Should give empty object with ? only')
84+
deepEqual($.querystring('/foo'), {}, 'Should give empty object with no ?')
85+
deepEqual($.querystring('http://google.com/foo?'), {}, 'Should give empty object with host/path and ?')
86+
deepEqual($.querystring('http://google.com/foo'), {}, 'Should give empty object with host/path and no ?')
8087
});
81-
88+
8289
module("Element methods");
83-
84-
test("get querystring from link", function() {});
85-
test("set link querystring", function() {});
90+
91+
test("get querystring from link", function() {
92+
deepEqual($('<a href="/foo?">link</a>').querystring(), {}, "With no querystring");
93+
deepEqual($('<a href="/foo?name=John">link</a>').querystring(), {name: "John"}, "With querystring");
94+
deepEqual($('<a href="http://google.com/?name=John">link</a>').querystring(), {name: "John"}, "With domains prefix.");
95+
// deepEqual($('<a href="/foo">link</a>').querystring(), {}, "With no ?");
96+
});
97+
test("set link querystring existing", function() {
98+
equals(
99+
$('<a href="/foo?name=John">link</a>').querystring({awesome:'value'}).attr('href'),
100+
'/foo?name=John&awesome=value'
101+
)
102+
});
103+
test("set link querystring non-existent", function() {
104+
equals(
105+
$('<a href="/foo">link</a>').querystring({awesome:'value'}).attr('href'),
106+
'/foo?awesome=value'
107+
)
108+
});
86109
// TODO: Tests for clearing, merging & using `form` elements.
87-
88-
});
110+
111+
});

0 commit comments

Comments
 (0)