0
|
1 define(
|
3
|
2 [ "./declare" ],
|
0
|
3 function(declare) {
|
|
4 function parseURI(uri) {
|
|
5 var schema, host, port, path, query, hash, i;
|
|
6 if (typeof (uri) == "string") {
|
|
7 if ((i = uri.indexOf(":")) >= 0 &&
|
|
8 uri.substr(0, i).match(/^\w+$/)) {
|
|
9 schema = uri.substr(0, i);
|
|
10 uri = uri.substr(i + 1);
|
|
11 }
|
|
12
|
|
13 if (uri.indexOf("//") === 0) {
|
|
14 uri = uri.substr(2);
|
|
15 if ((i = uri.indexOf("/")) >= 0) {
|
|
16 host = uri.substr(0, i);
|
|
17 uri = uri.substr(i);
|
|
18 } else {
|
|
19 host = uri;
|
|
20 uri = "";
|
|
21 }
|
|
22 }
|
|
23
|
|
24 if ((i = uri.indexOf("?")) >= 0) {
|
|
25 path = uri.substr(0, i);
|
|
26 uri = uri.substr(i + 1);
|
|
27
|
|
28 } else {
|
|
29 path = uri;
|
|
30 uri = "";
|
|
31
|
|
32 if ((i = path.indexOf("#")) >= 0) {
|
|
33 hash = path.substr(i + 1);
|
|
34 path = path.substr(0, i);
|
|
35 }
|
|
36 }
|
|
37
|
|
38 if ((i = uri.indexOf("#")) >= 0) {
|
|
39 query = uri.substr(0, i);
|
|
40 hash = uri.substr(i + 1);
|
|
41 } else {
|
|
42 query = uri;
|
|
43 }
|
|
44 }
|
|
45
|
|
46 if (host && (i = host.lastIndexOf(":")) >= 0) {
|
|
47 port = host.substr(i + 1);
|
|
48 host = host.substr(0, i);
|
|
49 }
|
|
50
|
|
51 return {
|
|
52 schema : schema,
|
|
53 host : host,
|
|
54 port : port,
|
|
55 path : path,
|
|
56 query : query,
|
|
57 hash : hash
|
|
58 };
|
|
59 }
|
|
60
|
|
61 function makeURI(options) {
|
|
62 var uri = [];
|
|
63
|
|
64 if (options.schema)
|
|
65 uri.push(options.schema, ":");
|
|
66 if (options.host)
|
|
67 uri.push("//", options.host);
|
|
68 if (options.host && options.port)
|
|
69 uri.push(":", options.port);
|
|
70
|
|
71 if (options.path) {
|
|
72 if (options.host && options.path[0] != "/")
|
|
73 uri.push("/");
|
|
74 uri.push(options.path);
|
|
75 } else if (options.host) {
|
|
76 uri.push("/");
|
|
77 }
|
|
78
|
|
79 if (options.query)
|
|
80 uri.push("?", options.query);
|
|
81 if (options.hash)
|
|
82 uri.push("#", options.hash);
|
|
83
|
|
84 return uri.join("");
|
|
85 }
|
|
86
|
|
87 function reducePath(parts) {
|
|
88 var balance = 0, result = [], isRoot;
|
|
89
|
|
90 for (var i = 0; i < parts.length; i++) {
|
|
91 var part = parts[i];
|
|
92 switch (part) {
|
|
93 case "..":
|
|
94 if (balance > 0) {
|
|
95 result.pop();
|
|
96 } else {
|
|
97 if (isRoot)
|
|
98 throw new Error("Unbalanced path: " + parts);
|
|
99
|
|
100 result.push(part);
|
|
101 }
|
|
102 balance--;
|
|
103 break;
|
|
104 case ".":
|
|
105 break;
|
|
106 case "":
|
|
107 if (i === 0) {
|
|
108 isRoot = true;
|
|
109 result.push(part);
|
|
110 }
|
|
111 break;
|
|
112 default:
|
|
113 result.push(part);
|
|
114 balance++;
|
|
115 break;
|
|
116 }
|
|
117 }
|
|
118
|
|
119 return result.join("/");
|
|
120 }
|
|
121
|
|
122 var meta = {
|
|
123 schema : null,
|
|
124 host : null,
|
|
125 port : null,
|
|
126 path : null,
|
|
127 query : null,
|
|
128 hash : null
|
|
129 };
|
|
130
|
|
131 var URI = declare(null, {
|
|
132 constructor : function(opts) {
|
|
133 if (typeof (opts) == "string")
|
|
134 opts = parseURI(opts);
|
|
135 for ( var p in meta)
|
|
136 if (p in opts)
|
|
137 this[p] = opts[p];
|
|
138 },
|
|
139
|
|
140 clone : function() {
|
|
141 return new URI(this);
|
|
142 },
|
|
143
|
|
144 combine : function(rel) {
|
|
145 var me = this;
|
|
146
|
|
147 if (typeof (rel) === "string")
|
|
148 rel = new URI(rel);
|
|
149 else
|
|
150 rel = rel.clone();
|
|
151
|
|
152 // //some.host:123/path?q=a#123
|
|
153 if (rel.host)
|
|
154 return rel;
|
|
155
|
|
156 // /abs/path?q=a#123
|
|
157 if (rel.path && rel.path[0] == "/") {
|
|
158 if (me.host) {
|
|
159 rel.schema = me.schema;
|
|
160 rel.host = me.host;
|
|
161 rel.port = me.port;
|
|
162 }
|
|
163 return rel;
|
|
164 }
|
|
165
|
|
166 var base = me.clone();
|
|
167
|
|
168 // rel/path?a=b#cd
|
|
169 if (rel.path) {
|
|
170 var segments = base.getSegments();
|
|
171 segments.pop();
|
|
172 segments.push.apply(segments, rel.getSegments());
|
|
173
|
|
174 base.path = reducePath(segments);
|
|
175 }
|
|
176
|
|
177 // ?q=a#123
|
|
178 if (rel.query)
|
|
179 base.query = rel.query;
|
|
180 if (rel.hash)
|
|
181 base.hase = rel.hash;
|
|
182
|
|
183 return base;
|
|
184 },
|
|
185
|
|
186 optimize : function() {
|
|
187 this.path = reducePath(this.getSegments());
|
|
188 },
|
|
189
|
|
190 getSegments : function() {
|
|
191 if (typeof (this.path) === "string")
|
|
192 return this.path.split("/");
|
|
193 else
|
|
194 return [];
|
|
195 },
|
|
196
|
|
197 toString : function() {
|
|
198 var uri = [], me = this;
|
|
199
|
|
200 if (me.schema)
|
|
201 uri.push(me.schema, ":");
|
|
202 if (me.host)
|
|
203 uri.push("//", me.host);
|
|
204 if (me.host && me.port)
|
|
205 uri.push(":", me.port);
|
|
206
|
|
207 if (me.path) {
|
|
208 if (me.host && me.path[0] != "/")
|
|
209 uri.push("/");
|
|
210 uri.push(me.path);
|
|
211 } else if (me.host) {
|
|
212 uri.push("/");
|
|
213 }
|
|
214
|
|
215 if (me.query)
|
|
216 uri.push("?", me.query);
|
|
217 if (me.hash)
|
|
218 uri.push("#", me.hash);
|
|
219
|
|
220 return uri.join("");
|
|
221 }
|
|
222
|
|
223 });
|
|
224
|
|
225 URI.combine = function(base, rel) {
|
|
226 if (typeof (base) === "string")
|
|
227 base = new URI(base);
|
|
228 return base.combine(rel).toString();
|
|
229 };
|
|
230
|
|
231 return URI;
|
|
232 }); |