Browse Source

fix: multi valued query variables did not work correctly, fixes #10539

Torkel Ödegaard 8 years ago
parent
commit
66edb29f53

+ 52 - 0
public/app/core/utils/url.ts

@@ -0,0 +1,52 @@
+/**
+ * @preserve jquery-param (c) 2015 KNOWLEDGECODE | MIT
+ */
+
+export function toUrlParams(a) {
+  let s = [];
+  let rbracket = /\[\]$/;
+
+  let isArray = function(obj) {
+    return Object.prototype.toString.call(obj) === '[object Array]';
+  };
+
+  let add = function(k, v) {
+    v = typeof v === 'function' ? v() : v === null ? '' : v === undefined ? '' : v;
+    s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
+  };
+
+  let buildParams = function(prefix, obj) {
+    var i, len, key;
+
+    if (prefix) {
+      if (isArray(obj)) {
+        for (i = 0, len = obj.length; i < len; i++) {
+          if (rbracket.test(prefix)) {
+            add(prefix, obj[i]);
+          } else {
+            buildParams(prefix, obj[i]);
+          }
+        }
+      } else if (obj && String(obj) === '[object Object]') {
+        for (key in obj) {
+          buildParams(prefix + '[' + key + ']', obj[key]);
+        }
+      } else {
+        add(prefix, obj);
+      }
+    } else if (isArray(obj)) {
+      for (i = 0, len = obj.length; i < len; i++) {
+        add(obj[i].name, obj[i].value);
+      }
+    } else {
+      for (key in obj) {
+        buildParams(key, obj[key]);
+      }
+    }
+    return s;
+  };
+
+  return buildParams('', a)
+    .join('&')
+    .replace(/%20/g, '+');
+}

+ 26 - 0
public/app/stores/ViewStore/ViewStore.jest.ts

@@ -0,0 +1,26 @@
+import { ViewStore } from './ViewStore';
+import { toJS } from 'mobx';
+
+describe('ViewStore', () => {
+  let store;
+
+  beforeAll(() => {
+    store = ViewStore.create({
+      path: '',
+      query: {},
+    });
+  });
+
+  it('Can update path and query', () => {
+    store.updatePathAndQuery('/hello', { key: 1, otherParam: 'asd' });
+    expect(store.path).toBe('/hello');
+    expect(store.query.get('key')).toBe(1);
+    expect(store.currentUrl).toBe('/hello?key=1&otherParam=asd');
+  });
+
+  it('Query can contain arrays', () => {
+    store.updatePathAndQuery('/hello', { values: ['A', 'B'] });
+    expect(store.query.get('values').toJS()).toMatchObject(['A', 'B']);
+    expect(store.currentUrl).toBe('/hello?values=A&values=B');
+  });
+});

+ 5 - 11
public/app/stores/ViewStore/ViewStore.ts

@@ -1,15 +1,9 @@
 import { types } from 'mobx-state-tree';
+import { toJS } from 'mobx';
+import { toUrlParams } from 'app/core/utils/url';
 
-const QueryValueType = types.union(types.string, types.boolean, types.number);
-const urlParameterize = queryObj => {
-  const keys = Object.keys(queryObj);
-  const newQuery = keys.reduce((acc: string, key: string, idx: number) => {
-    const preChar = idx === 0 ? '?' : '&';
-    return acc + preChar + key + '=' + queryObj[key];
-  }, '');
-
-  return newQuery;
-};
+const QueryInnerValueType = types.union(types.string, types.boolean, types.number);
+const QueryValueType = types.union(QueryInnerValueType, types.array(QueryInnerValueType));
 
 export const ViewStore = types
   .model({
@@ -21,7 +15,7 @@ export const ViewStore = types
       let path = self.path;
 
       if (self.query.size) {
-        path += urlParameterize(self.query.toJS());
+        path += '?' + toUrlParams(toJS(self.query));
       }
       return path;
     },

+ 1 - 1
yarn.lock

@@ -7442,7 +7442,7 @@ performance-now@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
 
-phantomjs-prebuilt@^2.1.15, phantomjs-prebuilt@^2.1.7:
+phantomjs-prebuilt@^2.1.16, phantomjs-prebuilt@^2.1.7:
   version "2.1.16"
   resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz#efd212a4a3966d3647684ea8ba788549be2aefef"
   dependencies: