diff --git a/core/js/js.js b/core/js/js.js
index e84f482d67230a9127791ad13982dc270981f9a4..976027dd06b971bcb996fd303e0603017613dbc7 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -364,6 +364,34 @@ var OC={
 		}
 		return result;
 	},
+
+	/**
+	 * Builds a URL query from a JS map.
+	 * @param params parameter map
+	 * @return string containing a URL query (without question) mark
+	 */
+	buildQueryString: function(params) {
+		var s = '';
+		var first = true;
+		if (!params) {
+			return s;
+		}
+		for (var key in params) {
+			var value = params[key];
+			if (first) {
+				first = false;
+			}
+			else {
+				s += '&';
+			}
+			s += encodeURIComponent(key);
+			if (value !== null && typeof(value) !== 'undefined') {
+				s += '=' + encodeURIComponent(value);
+			}
+		}
+		return s;
+	},
+
 	/**
 	 * Opens a popup with the setting for an app.
 	 * @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'.
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index 827669f270baa09519dd26429b1dd217ea7c6503..28c20a0642ee20edde16f36a1ec5b5c66761b202 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -67,4 +67,41 @@ describe('Core base tests', function() {
 			});
 		});
 	});
+	describe('Query string building', function() {
+		it('Returns empty string when empty params', function() {
+			expect(OC.buildQueryString()).toEqual('');
+			expect(OC.buildQueryString({})).toEqual('');
+		});
+		it('Encodes regular query strings', function() {
+			expect(OC.buildQueryString({
+				a: 'abc',
+				b: 'def'
+			})).toEqual('a=abc&b=def');
+		});
+		it('Encodes special characters', function() {
+			expect(OC.buildQueryString({
+				unicode: '汉字',
+			})).toEqual('unicode=%E6%B1%89%E5%AD%97');
+			expect(OC.buildQueryString({
+			   	b: 'spaace value',
+			   	'space key': 'normalvalue',
+			   	'slash/this': 'amp&ersand'
+			})).toEqual('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand');
+		});
+		it('Encodes data types and empty values', function() {
+			expect(OC.buildQueryString({
+				'keywithemptystring': '',
+			   	'keywithnull': null,
+			   	'keywithundefined': null,
+				something: 'else'
+			})).toEqual('keywithemptystring=&keywithnull&keywithundefined&something=else');
+			expect(OC.buildQueryString({
+			   	'booleanfalse': false,
+				'booleantrue': true
+			})).toEqual('booleanfalse=false&booleantrue=true');
+			expect(OC.buildQueryString({
+			   	'number': 123,
+			})).toEqual('number=123');
+		});
+	});
 });