1/* 2 * Purl (A JavaScript URL parser) v2.3.1 3 * Developed and maintanined by Mark Perkins, [email protected] 4 * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser 5 * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details. 6 */ 7 8;(function(factory) { 9 if (typeof define === 'function' && define.amd) { 10 define(factory); 11 } else { 12 window.purl = factory(); 13 } 14})(function() { 15 16 var tag2attr = { 17 a : 'href', 18 img : 'src', 19 form : 'action', 20 base : 'href', 21 script : 'src', 22 iframe : 'src', 23 link : 'href', 24 embed : 'src', 25 object : 'data' 26 }, 27 28 key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query 29 30 aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability 31 32 parser = { 33 strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs 34 loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs 35 }, 36 37 isint = /^[0-9]+$/; 38 39 function parseUri( url, strictMode ) { 40 var str = decodeURI( url ), 41 res = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ), 42 uri = { attr : {}, param : {}, seg : {} }, 43 i = 14; 44 45 while ( i-- ) { 46 uri.attr[ key[i] ] = res[i] || ''; 47 } 48 49 // build query and fragment parameters 50 uri.param['query'] = parseString(uri.attr['query']); 51 uri.param['fragment'] = parseString(uri.attr['fragment']); 52 53 // split path and fragement into segments 54 uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/'); 55 uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/'); 56 57 // compile a 'base' domain attribute 58 uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ? uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : ''; 59 60 return uri; 61 } 62 63 function getAttrName( elm ) { 64 var tn = elm.tagName; 65 if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()]; 66 return tn; 67 } 68 69 function promote(parent, key) { 70 if (parent[key].length === 0) return parent[key] = {}; 71 var t = {}; 72 for (var i in parent[key]) t[i] = parent[key][i]; 73 parent[key] = t; 74 return t; 75 } 76 77 function parse(parts, parent, key, val) { 78 var part = parts.shift(); 79 if (!part) { 80 if (isArray(parent[key])) { 81 parent[key].push(val); 82 } else if ('object' == typeof parent[key]) { 83 parent[key] = val; 84 } else if ('undefined' == typeof parent[key]) { 85 parent[key] = val; 86 } else { 87 parent[key] = [parent[key], val]; 88 } 89 } else { 90 var obj = parent[key] = parent[key] || []; 91 if (']' == part) { 92 if (isArray(obj)) { 93 if ('' !== val) obj.push(val); 94 } else if ('object' == typeof obj) { 95 obj[keys(obj).length] = val; 96 } else { 97 obj = parent[key] = [parent[key], val]; 98 } 99 } else if (~part.indexOf(']')) { 100 part = part.substr(0, part.length - 1); 101 if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); 102 parse(parts, obj, part, val); 103 // key 104 } else { 105 if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); 106 parse(parts, obj, part, val); 107 } 108 } 109 } 110 111 function merge(parent, key, val) { 112 if (~key.indexOf(']')) { 113 var parts = key.split('['); 114 parse(parts, parent, 'base', val); 115 } else { 116 if (!isint.test(key) && isArray(parent.base)) { 117 var t = {}; 118 for (var k in parent.base) t[k] = parent.base[k]; 119 parent.base = t; 120 } 121 if (key !== '') { 122 set(parent.base, key, val); 123 } 124 } 125 return parent; 126 } 127 128 function parseString(str) { 129 return reduce(String(str).split(/&|;/), function(ret, pair) { 130 try { 131 pair = decodeURIComponent(pair.replace(/\+/g, ' ')); 132 } catch(e) { 133 // ignore 134 } 135 var eql = pair.indexOf('='), 136 brace = lastBraceInKey(pair), 137 key = pair.substr(0, brace || eql), 138 val = pair.substr(brace || eql, pair.length); 139 140 val = val.substr(val.indexOf('=') + 1, val.length); 141 142 if (key === '') { 143 key = pair; 144 val = ''; 145 } 146 147 return merge(ret, key, val); 148 }, { base: {} }).base; 149 } 150 151 function set(obj, key, val) { 152 var v = obj[key]; 153 if (typeof v === 'undefined') { 154 obj[key] = val; 155 } else if (isArray(v)) { 156 v.push(val); 157 } else { 158 obj[key] = [v, val]; 159 } 160 } 161 162 function lastBraceInKey(str) { 163 var len = str.length, 164 brace, 165 c; 166 for (var i = 0; i < len; ++i) { 167 c = str[i]; 168 if (']' == c) brace = false;
169 if ('[' == c) brace = true; 170 if ('=' == c && !brace) return i; 171 } 172 } 173 174 function reduce(obj, accumulator){ 175 var i = 0, 176 l = obj.length >> 0, 177 curr = arguments[2]; 178 while (i < l) { 179 if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj); 180 ++i; 181 } 182 return curr; 183 } 184 185 function isArray(vArg) { 186 return Object.prototype.toString.call(vArg) === "[object Array]"; 187 } 188 189 function keys(obj) { 190 var key_array = []; 191 for ( var prop in obj ) { 192 if ( obj.hasOwnProperty(prop) ) key_array.push(prop); 193 } 194 return key_array; 195 } 196 197 function purl( url, strictMode ) { 198 if ( arguments.length === 1 && url === true ) { 199 strictMode = true; 200 url = undefined; 201 } 202 strictMode = strictMode || false; 203 url = url || window.location.toString(); 204 205 return { 206 207 data : parseUri(url, strictMode), 208 209 // get various attributes from the URI 210 attr : function( attr ) { 211 attr = aliases[attr] || attr; 212 return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr; 213 }, 214 215 // return query string parameters 216 param : function( param ) { 217 return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query; 218 }, 219 220 // return fragment parameters 221 fparam : function( param ) { 222 return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment; 223 }, 224 225 // return path segments 226 segment : function( seg ) { 227 if ( typeof seg === 'undefined' ) { 228 return this.data.seg.path; 229 } else { 230 seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end 231 return this.data.seg.path[seg]; 232 } 233 }, 234 235 // return fragment segments 236 fsegment : function( seg ) { 237 if ( typeof seg === 'undefined' ) { 238 return this.data.seg.fragment; 239 } else { 240 seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end 241 return this.data.seg.fragment[seg]; 242 } 243 } 244 245 }; 246 247 } 248 249 purl.jQuery = function($){ 250 if ($ != null) { 251 $.fn.url = function( strictMode ) { 252 var url = ''; 253 if ( this.length ) { 254 url = $(this).attr( getAttrName(this[0]) ) || ''; 255 } 256 return purl( url, strictMode ); 257 }; 258 259 $.url = purl; 260 } 261 }; 262 263 purl.jQuery(window.jQuery); 264 265 return purl; 266 267});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.