1 | var nodeUrl = require('url');
|
2 | var querystring = require('querystring');
|
3 | var _ = require('underscore');
|
4 |
|
5 | var UrlGrey = function(url){
|
6 | this.url = url;
|
7 | this._parsed = null;
|
8 | };
|
9 |
|
10 | UrlGrey.prototype.parsed = function(){
|
11 | if (!this._parsed){
|
12 | this._parsed = nodeUrl.parse(this.url);
|
13 | var p = this._parsed;
|
14 | if (p.protocol){
|
15 | p.protocol = p.protocol.slice(0,-1);
|
16 | } else {
|
17 | p.protocol = 'http';
|
18 | }
|
19 | if (p.hash){
|
20 | p.hash = p.hash.substring(1);
|
21 | }
|
22 | p.username = '';
|
23 | p.password = '';
|
24 | if (!p.hostname){
|
25 | p.hostname = 'localhost';
|
26 | }
|
27 | if (!p.port){
|
28 | p.port = 80;
|
29 | } else {
|
30 | p.port = parseInt(p.port, 10);
|
31 | }
|
32 | if (p.auth){
|
33 | var auth = p.auth.split(':');
|
34 | p.username = auth[0];
|
35 | p.password = auth[1];
|
36 | }
|
37 | }
|
38 | return this._parsed;
|
39 | };
|
40 |
|
41 | UrlGrey.prototype.query = function(mergeObject){
|
42 | var path;
|
43 | if (mergeObject === false){
|
44 |
|
45 | return this.queryString('');
|
46 | }
|
47 |
|
48 | var url = this.url;
|
49 | if (!mergeObject){
|
50 | var parsed = nodeUrl.parse(url);
|
51 | if (!!parsed.search){
|
52 | var qstr = parsed.search.substring(1);
|
53 | return querystring.parse(qstr);
|
54 | }
|
55 | return {};
|
56 | } else {
|
57 |
|
58 | var oldQuery = querystring.parse(this.queryString());
|
59 | _.each(mergeObject, function(v, k){
|
60 | if (v === null){
|
61 | delete oldQuery[k];
|
62 | } else {
|
63 | oldQuery[k] = v;
|
64 | }
|
65 | });
|
66 | var newString = querystring.stringify(oldQuery, '&', '=');
|
67 | return this.queryString(newString);
|
68 | }
|
69 | };
|
70 |
|
71 |
|
72 | addPropertyGetterSetter('protocol');
|
73 | addPropertyGetterSetter('port');
|
74 | addPropertyGetterSetter('username');
|
75 | addPropertyGetterSetter('password');
|
76 | addPropertyGetterSetter('hostname');
|
77 | addPropertyGetterSetter('hash');
|
78 |
|
79 | addPropertyGetterSetter('query', 'queryString');
|
80 | addPropertyGetterSetter('pathname', 'path');
|
81 |
|
82 | UrlGrey.prototype.path = function(){
|
83 | var args = _.toArray(arguments);
|
84 | if (args.length !== 0){
|
85 | var obj = new UrlGrey(this.toString());
|
86 | var str = _.flatten(args).join('/');
|
87 | str = str.replace(/\/+/g, '/');
|
88 | str = str.replace(/\/$/, '');
|
89 | if (str[0] !== '/'){ str = '/' + str; }
|
90 | obj.parsed().pathname = str;
|
91 | return obj;
|
92 | }
|
93 | return this.parsed().pathname;
|
94 | };
|
95 |
|
96 |
|
97 | UrlGrey.prototype.encode = function(str){
|
98 | return querystring.escape(str);
|
99 | };
|
100 |
|
101 | UrlGrey.prototype.decode = function(str){
|
102 | return querystring.unescape(str);
|
103 | };
|
104 |
|
105 | UrlGrey.prototype.parent = function(){
|
106 |
|
107 | var pieces = this.path().split("/");
|
108 | var popped = pieces.pop();
|
109 | if (popped === ''){
|
110 | pieces.pop();
|
111 | }
|
112 | return this.path(pieces.join("/"));
|
113 | };
|
114 |
|
115 | UrlGrey.prototype.child = function(suffix){
|
116 | if (suffix){
|
117 | suffix = encodeURIComponent(suffix);
|
118 | return this.path(this.path(), suffix);
|
119 | } else {
|
120 |
|
121 | var pieces = this.path().split("/");
|
122 | var last = _.last(pieces);
|
123 | if ((pieces.length > 1) && (last === '')){
|
124 |
|
125 | pieces.pop();
|
126 | last = _.last(pieces);
|
127 | }
|
128 | return last;
|
129 | }
|
130 | };
|
131 |
|
132 | UrlGrey.prototype.toJSON = function(){
|
133 | return this.toString();
|
134 | };
|
135 |
|
136 | UrlGrey.prototype.toString = function(){
|
137 | var p = this.parsed();
|
138 | var userinfo = p.username + ':' + p.password;
|
139 | var retval = this.protocol() + '://';
|
140 | if (userinfo != ':'){
|
141 | retval += userinfo + '@';
|
142 | }
|
143 | retval += p.hostname;
|
144 | if (this.port() !== 80){
|
145 | retval += ':' + this.port();
|
146 | }
|
147 | retval += this.path() === '/' ? '' : this.path();
|
148 | var qs = this.queryString();
|
149 | if (qs){
|
150 | retval += '?' + qs;
|
151 | }
|
152 | if (p.hash){
|
153 | retval += '#' + p.hash;
|
154 | }
|
155 | return retval;
|
156 | };
|
157 |
|
158 | module.exports = function(url){ return new UrlGrey(url); };
|
159 |
|
160 | function addPropertyGetterSetter(propertyName, methodName){
|
161 | if (!methodName){
|
162 | methodName = propertyName;
|
163 | }
|
164 | UrlGrey.prototype[methodName] = function(str){
|
165 | if (!!str || str === ''){
|
166 | var obj = new UrlGrey(this.toString());
|
167 | obj.parsed()[propertyName] = str;
|
168 | return obj;
|
169 | }
|
170 | return this.parsed()[propertyName];
|
171 | };
|
172 | }
|