SFRA Server-side Javascript - Source: modules/server/queryString.js menu

SFRA / Server-side JS / Source: modules/server/queryString.js

  1. 'use strict';
  2. /**
  3. * Zips the pref[n|v] http query params
  4. *
  5. * The Platform allows the use of multiple preference names and values to filter search results,
  6. * eg.: http://<sandbox>.com/../Search-Show?prefn1=refinementColor&prefv1=Blue&prefn2=size&prefv2=16
  7. *
  8. * @param {Object} preferences - HTTP query parameters map specific to selected refinement values
  9. * @return {Object} Map of provided preference name/value pairs
  10. */
  11. function parsePreferences(preferences) {
  12. var params = {};
  13. var count = Math.floor(Object.keys(preferences).length / 2);
  14. var key = '';
  15. var value = '';
  16. for (var i = 1; i < count + 1; i++) {
  17. key = preferences['prefn' + i];
  18. if (preferences['prefmin' + i]) {
  19. value = {
  20. min: preferences['prefmin' + i],
  21. max: preferences['prefmax' + i]
  22. };
  23. } else {
  24. value = preferences['prefv' + i];
  25. }
  26. params[key] = value;
  27. }
  28. return params;
  29. }
  30. /**
  31. * Detect duplicate parameters and be sure to set object[key] as an array of those parameter values
  32. *
  33. * @param {Object} object The object to check for existing values.
  34. * @param {string} key The key to set on object for the new value.
  35. * @param {string} value The new value to be added to object[key].
  36. * @return {Object} Value or array of values if object[key] has already exists.
  37. */
  38. function parameterToArray(object, key, value) {
  39. var result = value;
  40. if (object[key]) {
  41. result = object[key];
  42. if (!(result instanceof Array)) {
  43. result = [object[key]];
  44. }
  45. result.push(value);
  46. }
  47. return result;
  48. }
  49. var querystring = function (raw) {
  50. var pair;
  51. var left;
  52. var preferences = {};
  53. if (raw && raw.length > 0) {
  54. var qs = raw.substring(raw.indexOf('?') + 1).replace(/\+/g, '%20').split('&');
  55. for (var i = qs.length - 1; i >= 0; i--) {
  56. pair = qs[i].split('=');
  57. left = decodeURIComponent(pair[0]);
  58. if (left.indexOf('dwvar_') === 0) {
  59. left = left.replace(/__/g, '++');
  60. var variableParts = left.split('_');
  61. if (variableParts.length >= 3) {
  62. if (!this.variables) {
  63. this.variables = {};
  64. }
  65. this.variables[variableParts.slice(2).join('_')] = {
  66. id: variableParts[1].replace(/\+\+/g, '_'),
  67. value: decodeURIComponent(pair[1])
  68. };
  69. continue; // eslint-disable-line no-continue
  70. }
  71. } else if (left.indexOf('dwopt_') === 0) {
  72. left = left.replace(/__/g, '++');
  73. var optionParts = left.split('_');
  74. var productId = optionParts[1].replace(/\+\+/g, '_');
  75. var optionId = optionParts.slice(2).join('_');
  76. var selectedOptionValueId = decodeURIComponent(pair[1]);
  77. if (optionParts.length >= 3) {
  78. if (!this.options) {
  79. this.options = [];
  80. }
  81. this.options.push({
  82. optionId: optionId,
  83. selectedValueId: selectedOptionValueId,
  84. productId: productId
  85. });
  86. continue; // eslint-disable-line no-continue
  87. }
  88. } else if (left.indexOf('pref') === 0) {
  89. preferences[left] = decodeURIComponent(pair[1]);
  90. continue; // eslint-disable-line no-continue
  91. }
  92. this[left] = parameterToArray(this, left, decodeURIComponent(pair[1]));
  93. }
  94. }
  95. if (Object.keys(preferences).length) {
  96. this.preferences = parsePreferences(preferences);
  97. }
  98. };
  99. querystring.prototype.toString = function () {
  100. var result = [];
  101. var prefKeyIdx = 1;
  102. var preferences = {};
  103. Object.keys(this).forEach(function (key) {
  104. if (key === 'variables' && this.variables instanceof Object) {
  105. Object.keys(this.variables).forEach(function (variable) {
  106. result.push('dwvar_' +
  107. this.variables[variable].id.replace(/_/g, '__') + '_' +
  108. variable + '=' + encodeURIComponent(this.variables[variable].value));
  109. }, this);
  110. } else if (key === 'options' && this.options instanceof Array) {
  111. this.options.forEach(function (option) {
  112. result.push('dwopt_' +
  113. option.productId.replace(/_/g, '__') + '_' +
  114. option.optionId + '=' + encodeURIComponent(option.selectedValueId));
  115. });
  116. } else if (key === 'preferences' && this.preferences instanceof Object) {
  117. preferences = this.preferences;
  118. Object.keys(preferences).forEach(function (prefKey) {
  119. // Due to the nature of what is passed to this function this may be the literal string "undefined"
  120. if (prefKey !== 'undefined' && preferences[prefKey]) {
  121. result.push('prefn' + prefKeyIdx + '=' + encodeURIComponent(prefKey));
  122. if (preferences[prefKey].min) {
  123. result.push('prefmin' + prefKeyIdx + '=' + encodeURIComponent(preferences[prefKey].min));
  124. result.push('prefmax' + prefKeyIdx + '=' + encodeURIComponent(preferences[prefKey].max));
  125. } else {
  126. result.push('prefv' + prefKeyIdx + '=' + encodeURIComponent(preferences[prefKey]));
  127. }
  128. } else {
  129. var Logger = require('dw/system/Logger');
  130. Logger.warn('We were passed a key "undefined in the preferences object in queryString.js');
  131. }
  132. prefKeyIdx++;
  133. });
  134. } else {
  135. result.push(encodeURIComponent(key) + '=' + encodeURIComponent(this[key]));
  136. }
  137. }, this);
  138. return result.sort().join('&');
  139. };
  140. module.exports = querystring;