| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- * Utilities: A classic collection of JavaScript utilities
- * Copyright 2112 Matthew Eernisse ([email protected])
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- var uri
- , string = require('./string')
- , mixin = require('./core').mixin;
- /**
- @name uri
- @namespace uri
- */
- uri = new (function () {
- var _isArray = function (obj) {
- return obj &&
- typeof obj === 'object' &&
- typeof obj.length === 'number' &&
- typeof obj.splice === 'function' &&
- !(obj.propertyIsEnumerable('length'));
- };
- /**
- @name uri#getFileExtension
- @public
- @function
- @return {String} Returns the file extension for a given path
- @description Gets the file extension for a path and returns it
- @param {String} path The path to get the extension for
- */
- this.getFileExtension = function (path) {
- var match;
- if (path) {
- match = /.+\.(\w{2,4}$)/.exec(path);
- }
- return (match && match[1]) || '';
- };
- /**
- @name uri#paramify
- @public
- @function
- @return {String} Returns a querystring contains the given values
- @description Convert a JS Object to a querystring (key=val&key=val). Values in arrays
- will be added as multiple parameters
- @param {Object} obj An Object containing only scalars and arrays
- @param {Object} o The options to use for formatting
- @param {Boolean} [o.consolidate=false] take values from elements that can return
- multiple values (multi-select, checkbox groups) and collapse into a single,
- comman-delimited value.
- @param {Boolean} [o.includeEmpty=false] include keys in the string for all elements, even
- they have no value set (e.g., even if elemB has no value: elemA=foo&elemB=&elemC=bar).
- Note that some false-y values are always valid even without this option, [0, ''].
- This option extends coverage to [null, undefined, NaN]
- @param {Boolean} [o.snakeize=false] change param names from camelCase to snake_case.
- @param {Boolean} [o.escapeVals=false] escape the values for XML entities.
- @param {Boolean} [o.index=false] use numeric indices for arrays
- */
- this.paramify = function (obj, o) {
- var opts = o || {},
- _opts,
- str = '',
- key,
- val,
- isValid,
- itemArray,
- arr = [],
- arrVal,
- prefix = opts.prefix || '',
- self = this;
- function getParamName(key)
- {
- if (opts.prefix) {
- return prefix + '[' + key + ']';
- }
- else {
- return key;
- }
- }
- for (var p in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, p)) {
- val = obj[p];
- // This keeps valid falsy values like false and 0
- // It's duplicated in the array block below. Could
- // put it in a function but don't want the overhead
- isValid = !( val === null || val === undefined ||
- (typeof val === 'number' && isNaN(val)) );
- key = opts.snakeize ? string.snakeize(p) : p;
- if (isValid) {
- // Multiple vals -- array
- if (_isArray(val) && val.length) {
- itemArray = [];
- for (var i = 0, ii = val.length; i < ii; i++) {
- arrVal = val[i];
- // This keeps valid falsy values like false and 0
- isValid = !( arrVal === null || arrVal === undefined ||
- (typeof arrVal === 'number' && isNaN(arrVal)) );
- // for index mode, which works recursive
- // objects and array must not be encoded
- if (opts.index && typeof arrVal === 'object') {
- itemArray[i] = arrVal;
- }
- else {
- itemArray[i] = isValid ? encodeURIComponent(arrVal) : '';
- if (opts.escapeVals) {
- itemArray[i] = string.escapeXML(itemArray[i]);
- }
- }
- }
- // Consolidation mode -- single value joined on comma
- if (opts.consolidate) {
- arr.push(getParamName(key) + '=' + itemArray.join(','));
- }
- // Indexed mode -- multiple, same-named params with numeric indices
- else if (opts.index) {
- // {foo: [1, 2, 3]} => 'foo[0]=1&foo[1]=2&foo[2]=3'
- itemArray.forEach(function(item, i) {
- // recursion of arrays
- if (_isArray(item) && item.length) {
- _opts = mixin(opts, {});
- item.forEach(function(_item, ii) {
- if (typeof _item === 'object') {
- _opts.prefix = getParamName(key) + '[' + i + '][' + ii + ']';
- arr.push(self.paramify(_item, _opts));
- }
- else {
- arr.push(getParamName(key) + '[' + i + '][' + ii + ']=' + _item);
- }
- });
- }
- // recursion of object in array
- else if (typeof item === 'object') {
- _opts = mixin(opts, {});
- _opts.prefix = getParamName(key) + '[' + i + ']';
- arr.push(self.paramify(item, _opts));
- }
- // primitive
- else {
- arr.push(getParamName(key) + '[' + i + ']=' + item);
- }
- });
- }
- // Normal mode -- multiple, same-named params with each val
- else {
- // {foo: [1, 2, 3]} => 'foo=1&foo=2&foo=3'
- // Add into results array, as this just ends up getting
- // joined on ampersand at the end anyhow
- arr.push(getParamName(key) + '=' + itemArray.join('&' + getParamName(key) + '='));
- }
- }
- // Object -- recursion
- else if (typeof val === 'object') {
- _opts = mixin(opts, {});
- _opts.prefix = getParamName(key);
- arr.push(this.paramify(val, _opts));
- }
- // Single val -- string
- else {
- if (opts.escapeVals) {
- val = string.escapeXML(val);
- }
- arr.push(getParamName(key) + '=' + encodeURIComponent(val));
- }
- str += '&';
- }
- else {
- if (opts.includeEmpty) { arr.push(getParamName(key) + '='); }
- }
- }
- }
- return arr.join('&');
- };
- /**
- @name uri#objectify
- @public
- @function
- @return {Object} JavaScript key/val object with the values from the querystring
- @description Convert the values in a query string (key=val&key=val) to an Object
- @param {String} str The querystring to convert to an object
- @param {Object} o The options to use for formatting
- @param {Boolean} [o.consolidate=true] Convert multiple instances of the same
- key into an array of values instead of overwriting
- */
- this.objectify = function (str, o) {
- var opts = o || {};
- var d = {};
- var consolidate = typeof opts.consolidate == 'undefined' ?
- true : opts.consolidate;
- if (str) {
- var arr = str.split('&');
- for (var i = 0; i < arr.length; i++) {
- var pair = arr[i].split('=');
- var name = pair[0];
- var val = decodeURIComponent(pair[1] || '');
- // "We've already got one!" -- arrayize if the flag
- // is set
- if (typeof d[name] != 'undefined' && consolidate) {
- if (typeof d[name] == 'string') {
- d[name] = [d[name]];
- }
- d[name].push(val);
- }
- // Otherwise just set the value
- else {
- d[name] = val;
- }
- }
- }
- return d;
- };
- })();
- module.exports = uri;
|