├── README.md ├── jquery.query-object.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | jquery-plugin-query-object 2 | ========================== 3 | 4 | Query String Modification and Creation for jQuery 5 | 6 | This extension creates a singleton query string object for quick and readable query 7 | string modification and creation. This plugin provides a simple way of taking a page's 8 | query string and creating a modified version of this with little code. 9 | 10 | Disclaimer 11 | ------------------------- 12 | 13 | There are many URI manipulation libraries for JS and before use jquery-query-object you should look at least to https://github.com/medialize/URI.js because it much more feature rich, tested and better documented. I support jquery-query-object because i need it for one of my projects and i want to maintain reference to it on plugins.jquery.com - no other reasons to use it but not URI.js 14 | 15 | Example 16 | ------------------------- 17 | 18 | ``` 19 | var url = location.search; 20 | > "?action=view§ion=info&id=123&debug&testy[]=true&testy[]=false&testy[]" 21 | 22 | var section = $.query.get('section'); 23 | > "info" 24 | 25 | var id = $.query.get('id'); 26 | > 123 27 | 28 | var debug = $.query.get('debug'); 29 | > true 30 | 31 | var arr = $.query.get('testy'); 32 | > ["true", "false", true] 33 | 34 | var arrayElement = $.query.get('testy[1]'); 35 | > "false" 36 | 37 | var newUrl = $.query.set("section", 5).set("action", "do").toString(); 38 | > "?action=do§ion=5&id=123" 39 | 40 | var newQuery = "" + $.query.set('type', 'string'); 41 | > "?action=view§ion=info&id=123&type=string" 42 | 43 | var oldQuery = $.query.toString(); 44 | > "?action=view§ion=info&id=123" 45 | 46 | var oldQuery2 = $.query; 47 | > ?action=view§ion=info&id=123 48 | 49 | var newerQuery = $.query.SET('type', 'string'); 50 | > ?action=view§ion=info&id=123&type=string 51 | 52 | var notOldQuery = $.query.toString(); 53 | > "?action=view§ion=info&id=123&type=string" 54 | 55 | var oldQueryAgain = $.query.REMOVE("type"); 56 | > ?action=view§ion=info&id=123 57 | 58 | var removeElementByValue = $.query.REMOVE('section', 'info'); 59 | > ?action=view&id=123 60 | 61 | var newerQuery2 = $.query.set('testy[]', 'true').set('testy[]', 'false').set('testy[]', 'true'); 62 | > ?action=view&id=123&testy[0]=true&testy[1]=false&testy[2]=true 63 | 64 | var removeElementByValue1 = $.query.REMOVE('testy', 'false'); 65 | > ?action=view&id=123&testy[0]=true&testy[1]=true 66 | 67 | var emptyQuery = $.query.empty(); 68 | > "" 69 | 70 | var stillTheSame = $.query.copy(); 71 | > ?action=view§ion=info&id=123 72 | 73 | In case you dynamically change document.location via history API 74 | var parsedQuery = $.query.parseNew("?foo=bar", "bar=foo"); 75 | > ?foo=bar&bar=foo 76 | 77 | In case you are using History.js 78 | var parsedQuery = $.query.parseNew(location.search, location.hash.split("?").length > 1 ? location.hash.split("?")[1] : ""); 79 | ``` 80 | 81 | Features 82 | ------------------------- 83 | 84 | * **Chainability** 85 | Like much of jQuery, this object supports chaining set methods to add new key 86 | value pairs to the object. In addition, this chain does not modify the original 87 | object, but returns a copy which can be modified without changing the original object. 88 | You can use the method the 'loud' alternate methods to perform destructive 89 | modifications on the original object. 90 | 91 | * **Direct Object 'get' Accessor** 92 | The query string object returned contains the keys of the query string through a method named 'get' 93 | ``` 94 | $.query.get(keypath) 95 | ``` 96 | * **Easy String Creation** 97 | All modern browsers convert JavaScript objects to their string representation through 98 | their 'toString' method. So because this object creates a toString method for itself, 99 | when evaluated in a string context, this object returns a valid query string. If the 100 | query string object has no keys set, it returns an empty string. If it has keys set, 101 | it automatically prefixes the output with a question mark so you don't need to worry 102 | about appending one yourself. It's there if you need it and gone if you don't. 103 | It also supports arrays and associative arrays inside the query string. Both regular 104 | and associative arrays use "base[key1]=value1&base[key2]=value2" syntax in the query string. 105 | Originally arrays could forgo the square bracket and were simply printed out in their insertion 106 | order but with the new deep object support in version 2.0 this had to be removed for the sake of 107 | unambiguous keys. 108 | 109 | * **Custom url loading** 110 | You can create a new query object based on a provided url through the load method 111 | 112 | * **Query String Parsing** 113 | The original url parsing code was created by Jörn Zaefferer and modified by me. 114 | The new parsing features added are: 115 | 1. **Parsing Integers** 116 | The original code parsed floats out of strings but left integers as is. 117 | In my release, '123' will be converted to the number 123. 118 | 2. **Boolean Values** 119 | Query strings can often contain query parameters with no value set. This implies a simple boolean: 120 | ``` 121 | index.php?debug 122 | ``` 123 | implies a query string variable 'debug' set to true 124 | 3. **Improved number parsing** 125 | Parsing features introduced in version 1.2 include better support for number formats and differentiating between number-looking strings and numbers. 126 | 4. **Array syntax parsing** 127 | Array shaped query string keys will create an array in the internal jQuery.query structure and using square brackets without an index will generate an array dynamically. 128 | 5. **Ampersand or semi-colon delimiters** 129 | Because it has been requested of me, the parser now supports both semi-colons and ampersands as delimiting marks between key value pairs. 130 | 6. **Hash parameter parsing** 131 | Because it has been requested of me, the parser now supports both query string parsing and parsing of query string like strings in the url hash. 132 | 133 | 134 | Customization 135 | ------------------------- 136 | 137 | There are now some customizations which can be done, mostly dealing with parsing and with toString generation. The options are set by creating jQuery.query as an object of settings before including the jQuery.query source code on your page as seen below: 138 | 139 | ``` 140 | 143 | 144 | ``` 145 | 146 | When initializing, the query object will check the currently existing jQuery.query for any settings it can use. The settings are: 147 | 148 | 1. **separator** 149 | The default value for this setting is '&' as that is the standard for parameter division. However, when working in xml, some prefer to use a semi-colon to separate parameters to avoid overuse of &. The parser has been updated to read semi-colons as delimiters but to output generated query strings with a semi-colon you need to set this setting to ';' 150 | 151 | 2. **spaces** 152 | The default value for this is true as most people prefer plus signs in query strings to be converted to spaces. It's standard practice to use plus signs to represent spaces in query strings to avoid the dreaded %20 so the parser has been updated and, by default, converts plus signs to spaces. However, this feature can be disabled if you decide you need literal plus signs in your query strings. 153 | 154 | 3. **suffix** 155 | The default for this is true. If set to true, any arrays, when outputted to a query string will be suffixed with "[]" to show them as an array more clearly. Some may prefer to generate array strings without the square brackets and can set this value to false. I set this to true by default because I prefer one element arrays to be unambiguously arrays when generated in a query string. 156 | 157 | 4. **hash** 158 | The default for this is false. If set to true, the output of a query string will be prefixed by a hash '#' rather than a question mark. Given the interest in parsing hash parameters along with query string parameters, this seemed like a good setting to introduce. 159 | 160 | 5. **prefix** 161 | The default for this is true. If set to false, the output of a query string is not prefixed by a hash or question mark. 162 | 163 | 6. **numbers** 164 | The default for this is true. If set to false, numbers in query strings will NOT be parsed. This helps when left-hand zeros in a number are significant for some reason. 165 | 166 | Limitations 167 | ------------------------- 168 | 169 | * **Direct Object Access** 170 | Direct object access has been removed from this plugin as it wasn't symmetric (ie it was only usable for getting, not setting) and for safety reasons. 171 | 172 | * **Boolean false Values** 173 | Because true values are parsed and represented as attributes without distinct values, false is represented as a lack of attribute. Because of this, attempting to set an attribute to 'false' will result in its removal from the object. This is a design decision which may be made a customizable setting in the future. 174 | 175 | * **Key Complexity** 176 | Version 2.0 and above now supports deep objects just as well as PHP's built in $_GET object. 177 | -------------------------------------------------------------------------------- /jquery.query-object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.query - Query String Modification and Creation for jQuery 3 | * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com) 4 | * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/). 5 | * Date: 2009/8/13 6 | * 7 | * @author Blair Mitchelmore 8 | * @version 2.2.3 9 | * 10 | **/ 11 | new function(settings) { 12 | // Various Settings 13 | var $separator = settings.separator || '&'; 14 | var $spaces = settings.spaces === false ? false : true; 15 | var $suffix = settings.suffix === false ? '' : '[]'; 16 | var $prefix = settings.prefix === false ? false : true; 17 | var $hash = $prefix ? settings.hash === true ? "#" : "?" : ""; 18 | var $numbers = settings.numbers === false ? false : true; 19 | 20 | jQuery.query = new function() { 21 | var is = function(o, t) { 22 | return o != undefined && o !== null && (!!t ? o.constructor == t : true); 23 | }; 24 | var parse = function(path) { 25 | var m, rx = /\[([^[]*)\]/g, match = /^([^[]+)(\[.*\])?$/.exec(path), base = match[1], tokens = []; 26 | while (m = rx.exec(match[2])) tokens.push(m[1]); 27 | return [base, tokens]; 28 | }; 29 | var set = function(target, tokens, value) { 30 | var o, token = tokens.shift(); 31 | if (typeof target != 'object') target = null; 32 | if (token === "") { 33 | if (!target) target = []; 34 | if (is(target, Array)) { 35 | target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value)); 36 | } else if (is(target, Object)) { 37 | var i = 0; 38 | while (target[i++] != null); 39 | target[--i] = tokens.length == 0 ? value : set(target[i], tokens.slice(0), value); 40 | } else { 41 | target = []; 42 | target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value)); 43 | } 44 | } else if (token && token.match(/^\s*[0-9]+\s*$/)) { 45 | var index = parseInt(token, 10); 46 | if (!target) target = []; 47 | target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value); 48 | } else if (token) { 49 | var index = token.replace(/^\s*|\s*$/g, ""); 50 | if (!target) target = {}; 51 | if (is(target, Array)) { 52 | var temp = {}; 53 | for (var i = 0; i < target.length; ++i) { 54 | temp[i] = target[i]; 55 | } 56 | target = temp; 57 | } 58 | target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value); 59 | } else { 60 | return value; 61 | } 62 | return target; 63 | }; 64 | 65 | var queryObject = function(a) { 66 | var self = this; 67 | self.keys = {}; 68 | 69 | if (a.queryObject) { 70 | jQuery.each(a.get(), function(key, val) { 71 | self.SET(key, val); 72 | }); 73 | } else { 74 | self.parseNew.apply(self, arguments); 75 | } 76 | return self; 77 | }; 78 | 79 | queryObject.prototype = { 80 | queryObject: true, 81 | parseNew: function(){ 82 | var self = this; 83 | self.keys = {}; 84 | jQuery.each(arguments, function() { 85 | var q = "" + this; 86 | q = q.replace(/^[?#]/,''); // remove any leading ? || # 87 | q = q.replace(/[;&]$/,''); // remove any trailing & || ; 88 | if ($spaces) q = q.replace(/[+]/g,' '); // replace +'s with spaces 89 | 90 | jQuery.each(q.split(/[&;]/), function(){ 91 | var key = decodeURIComponent(this.split('=')[0] || ""); 92 | var val = decodeURIComponent(this.split('=')[1] || ""); 93 | 94 | if (!key) return; 95 | 96 | if ($numbers) { 97 | if (/^[+-]?[0-9]+\.[0-9]*$/.test(val)) // simple float regex 98 | val = parseFloat(val); 99 | else if (/^[+-]?[1-9][0-9]*$/.test(val)) // simple int regex 100 | val = parseInt(val, 10); 101 | } 102 | 103 | val = (!val && val !== 0) ? true : val; 104 | 105 | self.SET(key, val); 106 | }); 107 | }); 108 | return self; 109 | }, 110 | has: function(key, type) { 111 | var value = this.get(key); 112 | return is(value, type); 113 | }, 114 | GET: function(key) { 115 | if (!is(key)) return this.keys; 116 | var parsed = parse(key), base = parsed[0], tokens = parsed[1]; 117 | var target = this.keys[base]; 118 | while (target != null && tokens.length != 0) { 119 | target = target[tokens.shift()]; 120 | } 121 | return typeof target == 'number' ? target : target || ""; 122 | }, 123 | get: function(key) { 124 | var target = this.GET(key); 125 | if (is(target, Object)) 126 | return jQuery.extend(true, {}, target); 127 | else if (is(target, Array)) 128 | return target.slice(0); 129 | return target; 130 | }, 131 | SET: function(key, val) { 132 | if(!key.includes("__proto__")){ 133 | var value = !is(val) ? null : val; 134 | var parsed = parse(key), base = parsed[0], tokens = parsed[1]; 135 | var target = this.keys[base]; 136 | this.keys[base] = set(target, tokens.slice(0), value); 137 | } 138 | return this; 139 | }, 140 | set: function(key, val) { 141 | return this.copy().SET(key, val); 142 | }, 143 | REMOVE: function(key, val) { 144 | if (val) { 145 | var target = this.GET(key); 146 | if (is(target, Array)) { 147 | for (tval in target) { 148 | target[tval] = target[tval].toString(); 149 | } 150 | var index = $.inArray(val, target); 151 | if (index >= 0) { 152 | key = target.splice(index, 1); 153 | key = key[index]; 154 | } else { 155 | return; 156 | } 157 | } else if (val != target) { 158 | return; 159 | } 160 | } 161 | return this.SET(key, null).COMPACT(); 162 | }, 163 | remove: function(key, val) { 164 | return this.copy().REMOVE(key, val); 165 | }, 166 | EMPTY: function() { 167 | var self = this; 168 | jQuery.each(self.keys, function(key, value) { 169 | delete self.keys[key]; 170 | }); 171 | return self; 172 | }, 173 | load: function(url) { 174 | var hash = url.replace(/^.*?[#](.+?)(?:\?.+)?$/, "$1"); 175 | var search = url.replace(/^.*?[?](.+?)(?:#.+)?$/, "$1"); 176 | return new queryObject(url.length == search.length ? '' : search, url.length == hash.length ? '' : hash); 177 | }, 178 | empty: function() { 179 | return this.copy().EMPTY(); 180 | }, 181 | copy: function() { 182 | return new queryObject(this); 183 | }, 184 | COMPACT: function() { 185 | function build(orig) { 186 | var obj = typeof orig == "object" ? is(orig, Array) ? [] : {} : orig; 187 | if (typeof orig == 'object') { 188 | function add(o, key, value) { 189 | if (is(o, Array)) 190 | o.push(value); 191 | else 192 | o[key] = value; 193 | } 194 | jQuery.each(orig, function(key, value) { 195 | if (!is(value)) return true; 196 | add(obj, key, build(value)); 197 | }); 198 | } 199 | return obj; 200 | } 201 | this.keys = build(this.keys); 202 | return this; 203 | }, 204 | compact: function() { 205 | return this.copy().COMPACT(); 206 | }, 207 | toString: function() { 208 | var i = 0, queryString = [], chunks = [], self = this; 209 | var encode = function(str) { 210 | str = str + ""; 211 | str = encodeURIComponent(str); 212 | if ($spaces) str = str.replace(/%20/g, "+"); 213 | return str; 214 | }; 215 | var addFields = function(arr, key, value) { 216 | if (!is(value) || value === false) return; 217 | var o = [encode(key)]; 218 | if (value !== true) { 219 | o.push("="); 220 | o.push(encode(value)); 221 | } 222 | arr.push(o.join("")); 223 | }; 224 | var build = function(obj, base) { 225 | var newKey = function(key) { 226 | return !base || base == "" ? [key].join("") : [base, "[", key, "]"].join(""); 227 | }; 228 | jQuery.each(obj, function(key, value) { 229 | if (typeof value == 'object') 230 | build(value, newKey(key)); 231 | else 232 | addFields(chunks, newKey(key), value); 233 | }); 234 | }; 235 | 236 | build(this.keys); 237 | 238 | if (chunks.length > 0) queryString.push($hash); 239 | queryString.push(chunks.join($separator)); 240 | 241 | return queryString.join(""); 242 | } 243 | }; 244 | 245 | return new queryObject(location.search, location.hash); 246 | }; 247 | }(jQuery.query || {}); // Pass in jQuery.query as settings object 248 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-query-object", 3 | "title": "Query String Modification and Creation for jQuery", 4 | "description": "Query String Modification and Creation for jQuery", 5 | "keywords": [ 6 | "query", 7 | "parameter", 8 | "window.location.search", 9 | "querystring", 10 | "deserialize", 11 | "serialize" 12 | ], 13 | "version": "2.2.3", 14 | "author": "Blair Mitchelmore (https://github.com/blairmitchelmore)", 15 | "licenses": [ 16 | { 17 | "type": "WTFPL", 18 | "url": "http://sam.zoy.org/wtfpl/" 19 | } 20 | ], 21 | "bugs": { 22 | "url": "https://github.com/alrusdi/jquery-plugin-query-object/issues" 23 | }, 24 | "homepage": "https://github.com/alrusdi/jquery-plugin-query-object", 25 | "docs": "https://github.com/alrusdi/jquery-plugin-query-object", 26 | "download": "https://github.com/alrusdi/jquery-plugin-query-object/archive/master.zip", 27 | "dependencies": { 28 | "jquery": ">=1.4" 29 | }, 30 | "maintainers": [ 31 | "Alexander Alrusdi (https://github.com/alrusdi)" 32 | ], 33 | "main": "jquery.query-object.js", 34 | "scripts": { 35 | "test": "echo \"Error: no test specified\" && exit 1" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/alrusdi/jquery-plugin-query-object.git" 40 | }, 41 | "license": "ISC" 42 | } 43 | --------------------------------------------------------------------------------