uri-js-rails 1.11.2 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +3 -0
- data/lib/uri-js-rails/version.rb +1 -1
- data/vendor/assets/javascripts/IPv6.js +188 -0
- data/vendor/assets/javascripts/SecondLevelDomains.js +241 -0
- data/vendor/assets/javascripts/URI.fragmentQuery.js +104 -0
- data/vendor/assets/javascripts/URI.fragmentURI.js +97 -0
- data/vendor/assets/javascripts/URI.js +1212 -1148
- data/vendor/assets/javascripts/URI.min.js +84 -0
- data/vendor/assets/javascripts/URITemplate.js +499 -0
- data/vendor/assets/javascripts/jquery.URI.js +132 -129
- data/vendor/assets/javascripts/jquery.URI.min.js +7 -0
- data/vendor/assets/javascripts/punycode.js +508 -0
- metadata +16 -6
@@ -0,0 +1,104 @@
|
|
1
|
+
/*
|
2
|
+
* Extending URI.js for fragment abuse
|
3
|
+
*/
|
4
|
+
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// EXAMPLE: storing application/x-www-form-urlencoded data in the fragment
|
7
|
+
// possibly helpful for Google's hashbangs
|
8
|
+
// see http://code.google.com/web/ajaxcrawling/
|
9
|
+
// --------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
// Note: make sure this is the last file loaded!
|
12
|
+
|
13
|
+
// USAGE:
|
14
|
+
// var uri = URI("http://example.org/#?foo=bar");
|
15
|
+
// uri.fragment(true) === {foo: "bar"};
|
16
|
+
// uri.fragment({bar: "foo"});
|
17
|
+
// uri.toString() === "http://example.org/#?bar=foo";
|
18
|
+
// uri.addFragment("name", "value");
|
19
|
+
// uri.toString() === "http://example.org/#?bar=foo&name=value";
|
20
|
+
// uri.removeFragment("name");
|
21
|
+
// uri.toString() === "http://example.org/#?bar=foo";
|
22
|
+
|
23
|
+
(function (root, factory) {
|
24
|
+
'use strict';
|
25
|
+
// https://github.com/umdjs/umd/blob/master/returnExports.js
|
26
|
+
if (typeof exports === 'object') {
|
27
|
+
// Node
|
28
|
+
module.exports = factory(require('./URI'));
|
29
|
+
} else if (typeof define === 'function' && define.amd) {
|
30
|
+
// AMD. Register as an anonymous module.
|
31
|
+
define(['./URI'], factory);
|
32
|
+
} else {
|
33
|
+
// Browser globals (root is window)
|
34
|
+
factory(root.URI);
|
35
|
+
}
|
36
|
+
}(this, function (URI) {
|
37
|
+
'use strict';
|
38
|
+
|
39
|
+
var p = URI.prototype;
|
40
|
+
// old fragment handler we need to wrap
|
41
|
+
var f = p.fragment;
|
42
|
+
|
43
|
+
// make fragmentPrefix configurable
|
44
|
+
URI.fragmentPrefix = '?';
|
45
|
+
var _parts = URI._parts;
|
46
|
+
URI._parts = function() {
|
47
|
+
var parts = _parts();
|
48
|
+
parts.fragmentPrefix = URI.fragmentPrefix;
|
49
|
+
return parts;
|
50
|
+
};
|
51
|
+
p.fragmentPrefix = function(v) {
|
52
|
+
this._parts.fragmentPrefix = v;
|
53
|
+
return this;
|
54
|
+
};
|
55
|
+
|
56
|
+
// add fragment(true) and fragment({key: value}) signatures
|
57
|
+
p.fragment = function(v, build) {
|
58
|
+
var prefix = this._parts.fragmentPrefix;
|
59
|
+
var fragment = this._parts.fragment || '';
|
60
|
+
|
61
|
+
if (v === true) {
|
62
|
+
if (fragment.substring(0, prefix.length) !== prefix) {
|
63
|
+
return {};
|
64
|
+
}
|
65
|
+
|
66
|
+
return URI.parseQuery(fragment.substring(prefix.length));
|
67
|
+
} else if (v !== undefined && typeof v !== 'string') {
|
68
|
+
this._parts.fragment = prefix + URI.buildQuery(v);
|
69
|
+
this.build(!build);
|
70
|
+
return this;
|
71
|
+
} else {
|
72
|
+
return f.call(this, v, build);
|
73
|
+
}
|
74
|
+
};
|
75
|
+
p.addFragment = function(name, value, build) {
|
76
|
+
var prefix = this._parts.fragmentPrefix;
|
77
|
+
var data = URI.parseQuery((this._parts.fragment || '').substring(prefix.length));
|
78
|
+
URI.addQuery(data, name, value);
|
79
|
+
this._parts.fragment = prefix + URI.buildQuery(data);
|
80
|
+
if (typeof name !== 'string') {
|
81
|
+
build = value;
|
82
|
+
}
|
83
|
+
|
84
|
+
this.build(!build);
|
85
|
+
return this;
|
86
|
+
};
|
87
|
+
p.removeFragment = function(name, value, build) {
|
88
|
+
var prefix = this._parts.fragmentPrefix;
|
89
|
+
var data = URI.parseQuery((this._parts.fragment || '').substring(prefix.length));
|
90
|
+
URI.removeQuery(data, name, value);
|
91
|
+
this._parts.fragment = prefix + URI.buildQuery(data);
|
92
|
+
if (typeof name !== 'string') {
|
93
|
+
build = value;
|
94
|
+
}
|
95
|
+
|
96
|
+
this.build(!build);
|
97
|
+
return this;
|
98
|
+
};
|
99
|
+
p.addHash = p.addFragment;
|
100
|
+
p.removeHash = p.removeFragment;
|
101
|
+
|
102
|
+
// extending existing object rather than defining something new
|
103
|
+
return URI;
|
104
|
+
}));
|
@@ -0,0 +1,97 @@
|
|
1
|
+
/*
|
2
|
+
* Extending URI.js for fragment abuse
|
3
|
+
*/
|
4
|
+
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// EXAMPLE: storing a relative URL in the fragment ("FragmentURI")
|
7
|
+
// possibly helpful when working with backbone.js or sammy.js
|
8
|
+
// inspired by https://github.com/medialize/URI.js/pull/2
|
9
|
+
// --------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
// Note: make sure this is the last file loaded!
|
12
|
+
|
13
|
+
// USAGE:
|
14
|
+
// var uri = URI("http://example.org/#!/foo/bar/baz.html");
|
15
|
+
// var furi = uri.fragment(true);
|
16
|
+
// furi.pathname() === '/foo/bar/baz.html';
|
17
|
+
// furi.pathname('/hello.html');
|
18
|
+
// uri.toString() === "http://example.org/#!/hello.html"
|
19
|
+
|
20
|
+
(function (root, factory) {
|
21
|
+
'use strict';
|
22
|
+
// https://github.com/umdjs/umd/blob/master/returnExports.js
|
23
|
+
if (typeof exports === 'object') {
|
24
|
+
// Node
|
25
|
+
module.exports = factory(require('./URI'));
|
26
|
+
} else if (typeof define === 'function' && define.amd) {
|
27
|
+
// AMD. Register as an anonymous module.
|
28
|
+
define(['./URI'], factory);
|
29
|
+
} else {
|
30
|
+
// Browser globals (root is window)
|
31
|
+
factory(root.URI);
|
32
|
+
}
|
33
|
+
}(this, function (URI) {
|
34
|
+
'use strict';
|
35
|
+
|
36
|
+
var p = URI.prototype;
|
37
|
+
// old handlers we need to wrap
|
38
|
+
var f = p.fragment;
|
39
|
+
var b = p.build;
|
40
|
+
|
41
|
+
// make fragmentPrefix configurable
|
42
|
+
URI.fragmentPrefix = '!';
|
43
|
+
var _parts = URI._parts;
|
44
|
+
URI._parts = function() {
|
45
|
+
var parts = _parts();
|
46
|
+
parts.fragmentPrefix = URI.fragmentPrefix;
|
47
|
+
return parts;
|
48
|
+
};
|
49
|
+
p.fragmentPrefix = function(v) {
|
50
|
+
this._parts.fragmentPrefix = v;
|
51
|
+
return this;
|
52
|
+
};
|
53
|
+
|
54
|
+
// add fragment(true) and fragment(URI) signatures
|
55
|
+
p.fragment = function(v, build) {
|
56
|
+
var prefix = this._parts.fragmentPrefix;
|
57
|
+
var fragment = this._parts.fragment || '';
|
58
|
+
var furi;
|
59
|
+
|
60
|
+
if (v === true) {
|
61
|
+
if (fragment.substring(0, prefix.length) !== prefix) {
|
62
|
+
furi = URI('');
|
63
|
+
} else {
|
64
|
+
furi = new URI(fragment.substring(prefix.length));
|
65
|
+
}
|
66
|
+
|
67
|
+
this._fragmentURI = furi;
|
68
|
+
furi._parentURI = this;
|
69
|
+
return furi;
|
70
|
+
} else if (v !== undefined && typeof v !== 'string') {
|
71
|
+
this._fragmentURI = v;
|
72
|
+
v._parentURI = v;
|
73
|
+
this._parts.fragment = prefix + v.toString();
|
74
|
+
this.build(!build);
|
75
|
+
return this;
|
76
|
+
} else if (typeof v === 'string') {
|
77
|
+
this._fragmentURI = undefined;
|
78
|
+
}
|
79
|
+
|
80
|
+
return f.call(this, v, build);
|
81
|
+
};
|
82
|
+
|
83
|
+
// make .build() of the actual URI aware of the FragmentURI
|
84
|
+
p.build = function(deferBuild) {
|
85
|
+
var t = b.call(this, deferBuild);
|
86
|
+
|
87
|
+
if (deferBuild !== false && this._parentURI) {
|
88
|
+
// update the parent
|
89
|
+
this._parentURI.fragment(this);
|
90
|
+
}
|
91
|
+
|
92
|
+
return t;
|
93
|
+
};
|
94
|
+
|
95
|
+
// extending existing object rather than defining something new
|
96
|
+
return URI;
|
97
|
+
}));
|
@@ -1,10 +1,10 @@
|
|
1
1
|
/*!
|
2
2
|
* URI.js - Mutating URLs
|
3
3
|
*
|
4
|
-
* Version: 1.
|
4
|
+
* Version: 1.14.1
|
5
5
|
*
|
6
6
|
* Author: Rodney Rehm
|
7
|
-
* Web: http://medialize.github.
|
7
|
+
* Web: http://medialize.github.io/URI.js/
|
8
8
|
*
|
9
9
|
* Licensed under
|
10
10
|
* MIT License http://www.opensource.org/licenses/mit-license
|
@@ -12,190 +12,207 @@
|
|
12
12
|
*
|
13
13
|
*/
|
14
14
|
(function (root, factory) {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
'use strict';
|
16
|
+
// https://github.com/umdjs/umd/blob/master/returnExports.js
|
17
|
+
if (typeof exports === 'object') {
|
18
|
+
// Node
|
19
|
+
module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains'));
|
20
|
+
} else if (typeof define === 'function' && define.amd) {
|
21
|
+
// AMD. Register as an anonymous module.
|
22
|
+
define(['./punycode', './IPv6', './SecondLevelDomains'], factory);
|
23
|
+
} else {
|
24
|
+
// Browser globals (root is window)
|
25
|
+
root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);
|
26
|
+
}
|
26
27
|
}(this, function (punycode, IPv6, SLD, root) {
|
27
|
-
|
28
|
+
'use strict';
|
29
|
+
/*global location, escape, unescape */
|
30
|
+
// FIXME: v2.0.0 renamce non-camelCase properties to uppercase
|
31
|
+
/*jshint camelcase: false */
|
28
32
|
|
29
|
-
// save current URI variable, if any
|
30
|
-
var _URI = root && root.URI;
|
33
|
+
// save current URI variable, if any
|
34
|
+
var _URI = root && root.URI;
|
31
35
|
|
32
|
-
function URI(url, base) {
|
36
|
+
function URI(url, base) {
|
33
37
|
// Allow instantiation without the 'new' keyword
|
34
38
|
if (!(this instanceof URI)) {
|
35
|
-
|
39
|
+
return new URI(url, base);
|
36
40
|
}
|
37
41
|
|
38
42
|
if (url === undefined) {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
if (typeof location !== 'undefined') {
|
44
|
+
url = location.href + '';
|
45
|
+
} else {
|
46
|
+
url = '';
|
47
|
+
}
|
44
48
|
}
|
45
49
|
|
46
50
|
this.href(url);
|
47
51
|
|
48
52
|
// resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor
|
49
53
|
if (base !== undefined) {
|
50
|
-
|
54
|
+
return this.absoluteTo(base);
|
51
55
|
}
|
52
56
|
|
53
57
|
return this;
|
54
|
-
}
|
58
|
+
}
|
59
|
+
|
60
|
+
URI.version = '1.14.1';
|
55
61
|
|
56
|
-
var p = URI.prototype;
|
57
|
-
var hasOwn = Object.prototype.hasOwnProperty;
|
62
|
+
var p = URI.prototype;
|
63
|
+
var hasOwn = Object.prototype.hasOwnProperty;
|
58
64
|
|
59
|
-
function escapeRegEx(string) {
|
65
|
+
function escapeRegEx(string) {
|
60
66
|
// https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
|
61
67
|
return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
|
62
|
-
}
|
68
|
+
}
|
63
69
|
|
64
|
-
function getType(value) {
|
70
|
+
function getType(value) {
|
65
71
|
// IE8 doesn't return [Object Undefined] but [Object Object] for undefined value
|
66
72
|
if (value === undefined) {
|
67
|
-
|
73
|
+
return 'Undefined';
|
68
74
|
}
|
69
75
|
|
70
76
|
return String(Object.prototype.toString.call(value)).slice(8, -1);
|
71
|
-
}
|
77
|
+
}
|
72
78
|
|
73
|
-
function isArray(obj) {
|
74
|
-
return getType(obj) ===
|
75
|
-
}
|
79
|
+
function isArray(obj) {
|
80
|
+
return getType(obj) === 'Array';
|
81
|
+
}
|
76
82
|
|
77
|
-
function filterArrayValues(data, value) {
|
83
|
+
function filterArrayValues(data, value) {
|
78
84
|
var lookup = {};
|
79
85
|
var i, length;
|
80
86
|
|
81
87
|
if (isArray(value)) {
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
for (i = 0, length = value.length; i < length; i++) {
|
89
|
+
lookup[value[i]] = true;
|
90
|
+
}
|
85
91
|
} else {
|
86
|
-
|
92
|
+
lookup[value] = true;
|
87
93
|
}
|
88
94
|
|
89
95
|
for (i = 0, length = data.length; i < length; i++) {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
if (lookup[data[i]] !== undefined) {
|
97
|
+
data.splice(i, 1);
|
98
|
+
length--;
|
99
|
+
i--;
|
100
|
+
}
|
95
101
|
}
|
96
102
|
|
97
103
|
return data;
|
98
|
-
}
|
104
|
+
}
|
99
105
|
|
100
|
-
function arrayContains(list, value) {
|
106
|
+
function arrayContains(list, value) {
|
101
107
|
var i, length;
|
102
|
-
|
108
|
+
|
103
109
|
// value may be string, number, array, regexp
|
104
110
|
if (isArray(value)) {
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
}
|
111
|
+
// Note: this can be optimized to O(n) (instead of current O(m * n))
|
112
|
+
for (i = 0, length = value.length; i < length; i++) {
|
113
|
+
if (!arrayContains(list, value[i])) {
|
114
|
+
return false;
|
110
115
|
}
|
111
|
-
|
112
|
-
|
116
|
+
}
|
117
|
+
|
118
|
+
return true;
|
113
119
|
}
|
114
|
-
|
120
|
+
|
115
121
|
var _type = getType(value);
|
116
122
|
for (i = 0, length = list.length; i < length; i++) {
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
}
|
121
|
-
} else if (list[i] === value) {
|
122
|
-
return true;
|
123
|
+
if (_type === 'RegExp') {
|
124
|
+
if (typeof list[i] === 'string' && list[i].match(value)) {
|
125
|
+
return true;
|
123
126
|
}
|
127
|
+
} else if (list[i] === value) {
|
128
|
+
return true;
|
129
|
+
}
|
124
130
|
}
|
125
131
|
|
126
132
|
return false;
|
127
|
-
}
|
133
|
+
}
|
128
134
|
|
129
|
-
function arraysEqual(one, two) {
|
135
|
+
function arraysEqual(one, two) {
|
130
136
|
if (!isArray(one) || !isArray(two)) {
|
131
|
-
|
137
|
+
return false;
|
132
138
|
}
|
133
|
-
|
139
|
+
|
134
140
|
// arrays can't be equal if they have different amount of content
|
135
141
|
if (one.length !== two.length) {
|
136
|
-
|
142
|
+
return false;
|
137
143
|
}
|
138
144
|
|
139
145
|
one.sort();
|
140
146
|
two.sort();
|
141
147
|
|
142
148
|
for (var i = 0, l = one.length; i < l; i++) {
|
143
|
-
|
144
|
-
|
145
|
-
|
149
|
+
if (one[i] !== two[i]) {
|
150
|
+
return false;
|
151
|
+
}
|
146
152
|
}
|
147
|
-
|
153
|
+
|
148
154
|
return true;
|
149
|
-
}
|
155
|
+
}
|
150
156
|
|
151
|
-
URI._parts = function() {
|
157
|
+
URI._parts = function() {
|
152
158
|
return {
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
159
|
+
protocol: null,
|
160
|
+
username: null,
|
161
|
+
password: null,
|
162
|
+
hostname: null,
|
163
|
+
urn: null,
|
164
|
+
port: null,
|
165
|
+
path: null,
|
166
|
+
query: null,
|
167
|
+
fragment: null,
|
168
|
+
// state
|
169
|
+
duplicateQueryParameters: URI.duplicateQueryParameters,
|
170
|
+
escapeQuerySpace: URI.escapeQuerySpace
|
165
171
|
};
|
166
|
-
};
|
167
|
-
// state: allow duplicate query parameters (a=1&a=1)
|
168
|
-
URI.duplicateQueryParameters = false;
|
169
|
-
// state: replaces + with %20 (space in query strings)
|
170
|
-
URI.escapeQuerySpace = true;
|
171
|
-
// static properties
|
172
|
-
URI.protocol_expression = /^[a-z][a-z0-9
|
173
|
-
URI.idn_expression = /[^a-z0-9\.-]/i;
|
174
|
-
URI.punycode_expression = /(xn--)/i;
|
175
|
-
// well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?
|
176
|
-
URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
177
|
-
// credits to Rich Brown
|
178
|
-
// source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
|
179
|
-
// specification: http://www.ietf.org/rfc/rfc4291.txt
|
180
|
-
URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
|
181
|
-
// gruber revised
|
182
|
-
|
183
|
-
// http://
|
184
|
-
// http://
|
185
|
-
URI.
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
}
|
193
|
-
|
194
|
-
//
|
195
|
-
//
|
196
|
-
URI.
|
197
|
-
|
198
|
-
|
172
|
+
};
|
173
|
+
// state: allow duplicate query parameters (a=1&a=1)
|
174
|
+
URI.duplicateQueryParameters = false;
|
175
|
+
// state: replaces + with %20 (space in query strings)
|
176
|
+
URI.escapeQuerySpace = true;
|
177
|
+
// static properties
|
178
|
+
URI.protocol_expression = /^[a-z][a-z0-9.+-]*$/i;
|
179
|
+
URI.idn_expression = /[^a-z0-9\.-]/i;
|
180
|
+
URI.punycode_expression = /(xn--)/i;
|
181
|
+
// well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?
|
182
|
+
URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
183
|
+
// credits to Rich Brown
|
184
|
+
// source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
|
185
|
+
// specification: http://www.ietf.org/rfc/rfc4291.txt
|
186
|
+
URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
|
187
|
+
// expression used is "gruber revised" (@gruber v2) determined to be the
|
188
|
+
// best solution in a regex-golf we did a couple of ages ago at
|
189
|
+
// * http://mathiasbynens.be/demo/url-regex
|
190
|
+
// * http://rodneyrehm.de/t/url-regex.html
|
191
|
+
URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig;
|
192
|
+
URI.findUri = {
|
193
|
+
// valid "scheme://" or "www."
|
194
|
+
start: /\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi,
|
195
|
+
// everything up to the next whitespace
|
196
|
+
end: /[\s\r\n]|$/,
|
197
|
+
// trim trailing punctuation captured by end RegExp
|
198
|
+
trim: /[`!()\[\]{};:'".,<>?«»“”„‘’]+$/
|
199
|
+
};
|
200
|
+
// http://www.iana.org/assignments/uri-schemes.html
|
201
|
+
// http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports
|
202
|
+
URI.defaultPorts = {
|
203
|
+
http: '80',
|
204
|
+
https: '443',
|
205
|
+
ftp: '21',
|
206
|
+
gopher: '70',
|
207
|
+
ws: '80',
|
208
|
+
wss: '443'
|
209
|
+
};
|
210
|
+
// allowed hostname characters according to RFC 3986
|
211
|
+
// ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded
|
212
|
+
// I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . -
|
213
|
+
URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/;
|
214
|
+
// map DOM Elements to their URI attribute
|
215
|
+
URI.domAttributes = {
|
199
216
|
'a': 'href',
|
200
217
|
'blockquote': 'cite',
|
201
218
|
'link': 'href',
|
@@ -208,200 +225,215 @@ URI.domAttributes = {
|
|
208
225
|
'embed': 'src',
|
209
226
|
'source': 'src',
|
210
227
|
'track': 'src',
|
211
|
-
'input': 'src' // but only if type="image"
|
212
|
-
|
213
|
-
|
228
|
+
'input': 'src', // but only if type="image"
|
229
|
+
'audio': 'src',
|
230
|
+
'video': 'src'
|
231
|
+
};
|
232
|
+
URI.getDomAttribute = function(node) {
|
214
233
|
if (!node || !node.nodeName) {
|
215
|
-
|
234
|
+
return undefined;
|
216
235
|
}
|
217
|
-
|
236
|
+
|
218
237
|
var nodeName = node.nodeName.toLowerCase();
|
219
238
|
// <input> should only expose src for type="image"
|
220
239
|
if (nodeName === 'input' && node.type !== 'image') {
|
221
|
-
|
240
|
+
return undefined;
|
222
241
|
}
|
223
|
-
|
242
|
+
|
224
243
|
return URI.domAttributes[nodeName];
|
225
|
-
};
|
244
|
+
};
|
226
245
|
|
227
|
-
function escapeForDumbFirefox36(value) {
|
246
|
+
function escapeForDumbFirefox36(value) {
|
228
247
|
// https://github.com/medialize/URI.js/issues/91
|
229
248
|
return escape(value);
|
230
|
-
}
|
249
|
+
}
|
231
250
|
|
232
|
-
// encoding / decoding according to RFC3986
|
233
|
-
function strictEncodeURIComponent(string) {
|
251
|
+
// encoding / decoding according to RFC3986
|
252
|
+
function strictEncodeURIComponent(string) {
|
234
253
|
// see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent
|
235
254
|
return encodeURIComponent(string)
|
236
|
-
|
237
|
-
|
238
|
-
}
|
239
|
-
URI.encode = strictEncodeURIComponent;
|
240
|
-
URI.decode = decodeURIComponent;
|
241
|
-
URI.iso8859 = function() {
|
255
|
+
.replace(/[!'()*]/g, escapeForDumbFirefox36)
|
256
|
+
.replace(/\*/g, '%2A');
|
257
|
+
}
|
258
|
+
URI.encode = strictEncodeURIComponent;
|
259
|
+
URI.decode = decodeURIComponent;
|
260
|
+
URI.iso8859 = function() {
|
242
261
|
URI.encode = escape;
|
243
262
|
URI.decode = unescape;
|
244
|
-
};
|
245
|
-
URI.unicode = function() {
|
263
|
+
};
|
264
|
+
URI.unicode = function() {
|
246
265
|
URI.encode = strictEncodeURIComponent;
|
247
266
|
URI.decode = decodeURIComponent;
|
248
|
-
};
|
249
|
-
URI.characters = {
|
267
|
+
};
|
268
|
+
URI.characters = {
|
250
269
|
pathname: {
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
270
|
+
encode: {
|
271
|
+
// RFC3986 2.1: For consistency, URI producers and normalizers should
|
272
|
+
// use uppercase hexadecimal digits for all percent-encodings.
|
273
|
+
expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig,
|
274
|
+
map: {
|
275
|
+
// -._~!'()*
|
276
|
+
'%24': '$',
|
277
|
+
'%26': '&',
|
278
|
+
'%2B': '+',
|
279
|
+
'%2C': ',',
|
280
|
+
'%3B': ';',
|
281
|
+
'%3D': '=',
|
282
|
+
'%3A': ':',
|
283
|
+
'%40': '@'
|
284
|
+
}
|
285
|
+
},
|
286
|
+
decode: {
|
287
|
+
expression: /[\/\?#]/g,
|
288
|
+
map: {
|
289
|
+
'/': '%2F',
|
290
|
+
'?': '%3F',
|
291
|
+
'#': '%23'
|
292
|
+
}
|
293
|
+
}
|
275
294
|
},
|
276
295
|
reserved: {
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
296
|
+
encode: {
|
297
|
+
// RFC3986 2.1: For consistency, URI producers and normalizers should
|
298
|
+
// use uppercase hexadecimal digits for all percent-encodings.
|
299
|
+
expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,
|
300
|
+
map: {
|
301
|
+
// gen-delims
|
302
|
+
'%3A': ':',
|
303
|
+
'%2F': '/',
|
304
|
+
'%3F': '?',
|
305
|
+
'%23': '#',
|
306
|
+
'%5B': '[',
|
307
|
+
'%5D': ']',
|
308
|
+
'%40': '@',
|
309
|
+
// sub-delims
|
310
|
+
'%21': '!',
|
311
|
+
'%24': '$',
|
312
|
+
'%26': '&',
|
313
|
+
'%27': '\'',
|
314
|
+
'%28': '(',
|
315
|
+
'%29': ')',
|
316
|
+
'%2A': '*',
|
317
|
+
'%2B': '+',
|
318
|
+
'%2C': ',',
|
319
|
+
'%3B': ';',
|
320
|
+
'%3D': '='
|
321
|
+
}
|
322
|
+
}
|
323
|
+
}
|
324
|
+
};
|
325
|
+
URI.encodeQuery = function(string, escapeQuerySpace) {
|
326
|
+
var escaped = URI.encode(string + '');
|
327
|
+
if (escapeQuerySpace === undefined) {
|
328
|
+
escapeQuerySpace = URI.escapeQuerySpace;
|
304
329
|
}
|
305
|
-
|
306
|
-
URI.encodeQuery = function(string, escapeQuerySpace) {
|
307
|
-
var escaped = URI.encode(string + "");
|
330
|
+
|
308
331
|
return escapeQuerySpace ? escaped.replace(/%20/g, '+') : escaped;
|
309
|
-
};
|
310
|
-
URI.decodeQuery = function(string, escapeQuerySpace) {
|
311
|
-
string +=
|
332
|
+
};
|
333
|
+
URI.decodeQuery = function(string, escapeQuerySpace) {
|
334
|
+
string += '';
|
335
|
+
if (escapeQuerySpace === undefined) {
|
336
|
+
escapeQuerySpace = URI.escapeQuerySpace;
|
337
|
+
}
|
338
|
+
|
312
339
|
try {
|
313
|
-
|
340
|
+
return URI.decode(escapeQuerySpace ? string.replace(/\+/g, '%20') : string);
|
314
341
|
} catch(e) {
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
}
|
321
|
-
};
|
322
|
-
URI.recodePath = function(string) {
|
323
|
-
var segments = (string +
|
342
|
+
// we're not going to mess with weird encodings,
|
343
|
+
// give up and return the undecoded original string
|
344
|
+
// see https://github.com/medialize/URI.js/issues/87
|
345
|
+
// see https://github.com/medialize/URI.js/issues/92
|
346
|
+
return string;
|
347
|
+
}
|
348
|
+
};
|
349
|
+
URI.recodePath = function(string) {
|
350
|
+
var segments = (string + '').split('/');
|
324
351
|
for (var i = 0, length = segments.length; i < length; i++) {
|
325
|
-
|
352
|
+
segments[i] = URI.encodePathSegment(URI.decode(segments[i]));
|
326
353
|
}
|
327
354
|
|
328
355
|
return segments.join('/');
|
329
|
-
};
|
330
|
-
URI.decodePath = function(string) {
|
331
|
-
var segments = (string +
|
356
|
+
};
|
357
|
+
URI.decodePath = function(string) {
|
358
|
+
var segments = (string + '').split('/');
|
332
359
|
for (var i = 0, length = segments.length; i < length; i++) {
|
333
|
-
|
360
|
+
segments[i] = URI.decodePathSegment(segments[i]);
|
334
361
|
}
|
335
362
|
|
336
363
|
return segments.join('/');
|
337
|
-
};
|
338
|
-
// generate encode/decode path functions
|
339
|
-
var _parts = {'encode':'encode', 'decode':'decode'};
|
340
|
-
var _part;
|
341
|
-
var generateAccessor = function(_group, _part) {
|
364
|
+
};
|
365
|
+
// generate encode/decode path functions
|
366
|
+
var _parts = {'encode':'encode', 'decode':'decode'};
|
367
|
+
var _part;
|
368
|
+
var generateAccessor = function(_group, _part) {
|
342
369
|
return function(string) {
|
343
|
-
|
344
|
-
|
370
|
+
try {
|
371
|
+
return URI[_part](string + '').replace(URI.characters[_group][_part].expression, function(c) {
|
372
|
+
return URI.characters[_group][_part].map[c];
|
345
373
|
});
|
374
|
+
} catch (e) {
|
375
|
+
// we're not going to mess with weird encodings,
|
376
|
+
// give up and return the undecoded original string
|
377
|
+
// see https://github.com/medialize/URI.js/issues/87
|
378
|
+
// see https://github.com/medialize/URI.js/issues/92
|
379
|
+
return string;
|
380
|
+
}
|
346
381
|
};
|
347
|
-
};
|
382
|
+
};
|
348
383
|
|
349
|
-
for (_part in _parts) {
|
350
|
-
URI[_part +
|
351
|
-
}
|
384
|
+
for (_part in _parts) {
|
385
|
+
URI[_part + 'PathSegment'] = generateAccessor('pathname', _parts[_part]);
|
386
|
+
}
|
352
387
|
|
353
|
-
URI.encodeReserved = generateAccessor(
|
388
|
+
URI.encodeReserved = generateAccessor('reserved', 'encode');
|
354
389
|
|
355
|
-
URI.parse = function(string, parts) {
|
390
|
+
URI.parse = function(string, parts) {
|
356
391
|
var pos;
|
357
392
|
if (!parts) {
|
358
|
-
|
393
|
+
parts = {};
|
359
394
|
}
|
360
395
|
// [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment]
|
361
396
|
|
362
397
|
// extract fragment
|
363
398
|
pos = string.indexOf('#');
|
364
399
|
if (pos > -1) {
|
365
|
-
|
366
|
-
|
367
|
-
|
400
|
+
// escaping?
|
401
|
+
parts.fragment = string.substring(pos + 1) || null;
|
402
|
+
string = string.substring(0, pos);
|
368
403
|
}
|
369
404
|
|
370
405
|
// extract query
|
371
406
|
pos = string.indexOf('?');
|
372
407
|
if (pos > -1) {
|
373
|
-
|
374
|
-
|
375
|
-
|
408
|
+
// escaping?
|
409
|
+
parts.query = string.substring(pos + 1) || null;
|
410
|
+
string = string.substring(0, pos);
|
376
411
|
}
|
377
412
|
|
378
413
|
// extract protocol
|
379
414
|
if (string.substring(0, 2) === '//') {
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
415
|
+
// relative-scheme
|
416
|
+
parts.protocol = null;
|
417
|
+
string = string.substring(2);
|
418
|
+
// extract "user:pass@host:port"
|
419
|
+
string = URI.parseAuthority(string, parts);
|
385
420
|
} else {
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
} else {
|
401
|
-
string = string.substring(pos + 1);
|
402
|
-
parts.urn = true;
|
403
|
-
}
|
421
|
+
pos = string.indexOf(':');
|
422
|
+
if (pos > -1) {
|
423
|
+
parts.protocol = string.substring(0, pos) || null;
|
424
|
+
if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {
|
425
|
+
// : may be within the path
|
426
|
+
parts.protocol = undefined;
|
427
|
+
} else if (string.substring(pos + 1, pos + 3) === '//') {
|
428
|
+
string = string.substring(pos + 3);
|
429
|
+
|
430
|
+
// extract "user:pass@host:port"
|
431
|
+
string = URI.parseAuthority(string, parts);
|
432
|
+
} else {
|
433
|
+
string = string.substring(pos + 1);
|
434
|
+
parts.urn = true;
|
404
435
|
}
|
436
|
+
}
|
405
437
|
}
|
406
438
|
|
407
439
|
// what's left must be the path
|
@@ -409,78 +441,79 @@ URI.parse = function(string, parts) {
|
|
409
441
|
|
410
442
|
// and we're done
|
411
443
|
return parts;
|
412
|
-
};
|
413
|
-
URI.parseHost = function(string, parts) {
|
444
|
+
};
|
445
|
+
URI.parseHost = function(string, parts) {
|
414
446
|
// extract host:port
|
415
447
|
var pos = string.indexOf('/');
|
416
448
|
var bracketPos;
|
417
449
|
var t;
|
418
450
|
|
419
451
|
if (pos === -1) {
|
420
|
-
|
452
|
+
pos = string.length;
|
421
453
|
}
|
422
454
|
|
423
|
-
if (string.charAt(0) ===
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
// IPv6 host contains multiple colons - but no port
|
432
|
-
// this notation is actually not allowed by RFC 3986, but we're a liberal parser
|
433
|
-
parts.hostname = string.substring(0, pos) || null;
|
455
|
+
if (string.charAt(0) === '[') {
|
456
|
+
// IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6
|
457
|
+
// I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts
|
458
|
+
// IPv6+port in the format [2001:db8::1]:80 (for the time being)
|
459
|
+
bracketPos = string.indexOf(']');
|
460
|
+
parts.hostname = string.substring(1, bracketPos) || null;
|
461
|
+
parts.port = string.substring(bracketPos + 2, pos) || null;
|
462
|
+
if (parts.port === '/') {
|
434
463
|
parts.port = null;
|
464
|
+
}
|
465
|
+
} else if (string.indexOf(':') !== string.lastIndexOf(':')) {
|
466
|
+
// IPv6 host contains multiple colons - but no port
|
467
|
+
// this notation is actually not allowed by RFC 3986, but we're a liberal parser
|
468
|
+
parts.hostname = string.substring(0, pos) || null;
|
469
|
+
parts.port = null;
|
435
470
|
} else {
|
436
|
-
|
437
|
-
|
438
|
-
|
471
|
+
t = string.substring(0, pos).split(':');
|
472
|
+
parts.hostname = t[0] || null;
|
473
|
+
parts.port = t[1] || null;
|
439
474
|
}
|
440
475
|
|
441
476
|
if (parts.hostname && string.substring(pos).charAt(0) !== '/') {
|
442
|
-
|
443
|
-
|
477
|
+
pos++;
|
478
|
+
string = '/' + string;
|
444
479
|
}
|
445
480
|
|
446
481
|
return string.substring(pos) || '/';
|
447
|
-
};
|
448
|
-
URI.parseAuthority = function(string, parts) {
|
482
|
+
};
|
483
|
+
URI.parseAuthority = function(string, parts) {
|
449
484
|
string = URI.parseUserinfo(string, parts);
|
450
485
|
return URI.parseHost(string, parts);
|
451
|
-
};
|
452
|
-
URI.parseUserinfo = function(string, parts) {
|
486
|
+
};
|
487
|
+
URI.parseUserinfo = function(string, parts) {
|
453
488
|
// extract username:password
|
454
489
|
var firstSlash = string.indexOf('/');
|
455
|
-
var pos = firstSlash > -1
|
456
|
-
? string.lastIndexOf('@', firstSlash)
|
457
|
-
: string.indexOf('@');
|
490
|
+
var pos = string.lastIndexOf('@', firstSlash > -1 ? firstSlash : string.length - 1);
|
458
491
|
var t;
|
459
492
|
|
460
493
|
// authority@ must come before /path
|
461
494
|
if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
495
|
+
t = string.substring(0, pos).split(':');
|
496
|
+
parts.username = t[0] ? URI.decode(t[0]) : null;
|
497
|
+
t.shift();
|
498
|
+
parts.password = t[0] ? URI.decode(t.join(':')) : null;
|
499
|
+
string = string.substring(pos + 1);
|
467
500
|
} else {
|
468
|
-
|
469
|
-
|
501
|
+
parts.username = null;
|
502
|
+
parts.password = null;
|
470
503
|
}
|
471
504
|
|
472
505
|
return string;
|
473
|
-
};
|
474
|
-
URI.parseQuery = function(string, escapeQuerySpace) {
|
506
|
+
};
|
507
|
+
URI.parseQuery = function(string, escapeQuerySpace) {
|
475
508
|
if (!string) {
|
476
|
-
|
509
|
+
return {};
|
477
510
|
}
|
478
511
|
|
479
512
|
// throw out the funky business - "?"[name"="value"&"]+
|
480
513
|
string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, '');
|
481
514
|
|
482
515
|
if (!string) {
|
483
|
-
|
516
|
+
return {};
|
484
517
|
}
|
485
518
|
|
486
519
|
var items = {};
|
@@ -489,459 +522,477 @@ URI.parseQuery = function(string, escapeQuerySpace) {
|
|
489
522
|
var v, name, value;
|
490
523
|
|
491
524
|
for (var i = 0; i < length; i++) {
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
if (items[name]) {
|
498
|
-
if (typeof items[name] === "string") {
|
499
|
-
items[name] = [items[name]];
|
500
|
-
}
|
525
|
+
v = splits[i].split('=');
|
526
|
+
name = URI.decodeQuery(v.shift(), escapeQuerySpace);
|
527
|
+
// no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
|
528
|
+
value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;
|
501
529
|
|
502
|
-
|
503
|
-
|
504
|
-
|
530
|
+
if (hasOwn.call(items, name)) {
|
531
|
+
if (typeof items[name] === 'string') {
|
532
|
+
items[name] = [items[name]];
|
505
533
|
}
|
534
|
+
|
535
|
+
items[name].push(value);
|
536
|
+
} else {
|
537
|
+
items[name] = value;
|
538
|
+
}
|
506
539
|
}
|
507
540
|
|
508
541
|
return items;
|
509
|
-
};
|
542
|
+
};
|
510
543
|
|
511
|
-
URI.build = function(parts) {
|
512
|
-
var t =
|
544
|
+
URI.build = function(parts) {
|
545
|
+
var t = '';
|
513
546
|
|
514
547
|
if (parts.protocol) {
|
515
|
-
|
548
|
+
t += parts.protocol + ':';
|
516
549
|
}
|
517
550
|
|
518
551
|
if (!parts.urn && (t || parts.hostname)) {
|
519
|
-
|
552
|
+
t += '//';
|
520
553
|
}
|
521
554
|
|
522
555
|
t += (URI.buildAuthority(parts) || '');
|
523
556
|
|
524
|
-
if (typeof parts.path ===
|
525
|
-
|
526
|
-
|
527
|
-
|
557
|
+
if (typeof parts.path === 'string') {
|
558
|
+
if (parts.path.charAt(0) !== '/' && typeof parts.hostname === 'string') {
|
559
|
+
t += '/';
|
560
|
+
}
|
528
561
|
|
529
|
-
|
562
|
+
t += parts.path;
|
530
563
|
}
|
531
564
|
|
532
|
-
if (typeof parts.query ===
|
533
|
-
|
565
|
+
if (typeof parts.query === 'string' && parts.query) {
|
566
|
+
t += '?' + parts.query;
|
534
567
|
}
|
535
568
|
|
536
|
-
if (typeof parts.fragment ===
|
537
|
-
|
569
|
+
if (typeof parts.fragment === 'string' && parts.fragment) {
|
570
|
+
t += '#' + parts.fragment;
|
538
571
|
}
|
539
572
|
return t;
|
540
|
-
};
|
541
|
-
URI.buildHost = function(parts) {
|
542
|
-
var t =
|
573
|
+
};
|
574
|
+
URI.buildHost = function(parts) {
|
575
|
+
var t = '';
|
543
576
|
|
544
577
|
if (!parts.hostname) {
|
545
|
-
|
578
|
+
return '';
|
546
579
|
} else if (URI.ip6_expression.test(parts.hostname)) {
|
547
|
-
|
548
|
-
t += "[" + parts.hostname + "]:" + parts.port;
|
549
|
-
} else {
|
550
|
-
// don't know if we should always wrap IPv6 in []
|
551
|
-
// the RFC explicitly says SHOULD, not MUST.
|
552
|
-
t += parts.hostname;
|
553
|
-
}
|
580
|
+
t += '[' + parts.hostname + ']';
|
554
581
|
} else {
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
582
|
+
t += parts.hostname;
|
583
|
+
}
|
584
|
+
|
585
|
+
if (parts.port) {
|
586
|
+
t += ':' + parts.port;
|
559
587
|
}
|
560
588
|
|
561
589
|
return t;
|
562
|
-
};
|
563
|
-
URI.buildAuthority = function(parts) {
|
590
|
+
};
|
591
|
+
URI.buildAuthority = function(parts) {
|
564
592
|
return URI.buildUserinfo(parts) + URI.buildHost(parts);
|
565
|
-
};
|
566
|
-
URI.buildUserinfo = function(parts) {
|
567
|
-
var t =
|
593
|
+
};
|
594
|
+
URI.buildUserinfo = function(parts) {
|
595
|
+
var t = '';
|
568
596
|
|
569
597
|
if (parts.username) {
|
570
|
-
|
598
|
+
t += URI.encode(parts.username);
|
571
599
|
|
572
|
-
|
573
|
-
|
574
|
-
|
600
|
+
if (parts.password) {
|
601
|
+
t += ':' + URI.encode(parts.password);
|
602
|
+
}
|
575
603
|
|
576
|
-
|
604
|
+
t += '@';
|
577
605
|
}
|
578
606
|
|
579
607
|
return t;
|
580
|
-
};
|
581
|
-
URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {
|
608
|
+
};
|
609
|
+
URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {
|
582
610
|
// according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html
|
583
611
|
// being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed
|
584
612
|
// the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax!
|
585
613
|
// URI.js treats the query string as being application/x-www-form-urlencoded
|
586
614
|
// see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
|
587
615
|
|
588
|
-
var t =
|
616
|
+
var t = '';
|
589
617
|
var unique, key, i, length;
|
590
618
|
for (key in data) {
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
}
|
601
|
-
}
|
602
|
-
} else if (data[key] !== undefined) {
|
603
|
-
t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);
|
619
|
+
if (hasOwn.call(data, key) && key) {
|
620
|
+
if (isArray(data[key])) {
|
621
|
+
unique = {};
|
622
|
+
for (i = 0, length = data[key].length; i < length; i++) {
|
623
|
+
if (data[key][i] !== undefined && unique[data[key][i] + ''] === undefined) {
|
624
|
+
t += '&' + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace);
|
625
|
+
if (duplicateQueryParameters !== true) {
|
626
|
+
unique[data[key][i] + ''] = true;
|
627
|
+
}
|
604
628
|
}
|
629
|
+
}
|
630
|
+
} else if (data[key] !== undefined) {
|
631
|
+
t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);
|
605
632
|
}
|
633
|
+
}
|
606
634
|
}
|
607
635
|
|
608
636
|
return t.substring(1);
|
609
|
-
};
|
610
|
-
URI.buildQueryParameter = function(name, value, escapeQuerySpace) {
|
637
|
+
};
|
638
|
+
URI.buildQueryParameter = function(name, value, escapeQuerySpace) {
|
611
639
|
// http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded
|
612
640
|
// don't append "=" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization
|
613
|
-
return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ?
|
614
|
-
};
|
615
|
-
|
616
|
-
URI.addQuery = function(data, name, value) {
|
617
|
-
if (typeof name ===
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
} else if (typeof name ===
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
641
|
+
return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? '=' + URI.encodeQuery(value, escapeQuerySpace) : '');
|
642
|
+
};
|
643
|
+
|
644
|
+
URI.addQuery = function(data, name, value) {
|
645
|
+
if (typeof name === 'object') {
|
646
|
+
for (var key in name) {
|
647
|
+
if (hasOwn.call(name, key)) {
|
648
|
+
URI.addQuery(data, key, name[key]);
|
649
|
+
}
|
650
|
+
}
|
651
|
+
} else if (typeof name === 'string') {
|
652
|
+
if (data[name] === undefined) {
|
653
|
+
data[name] = value;
|
654
|
+
return;
|
655
|
+
} else if (typeof data[name] === 'string') {
|
656
|
+
data[name] = [data[name]];
|
657
|
+
}
|
658
|
+
|
659
|
+
if (!isArray(value)) {
|
660
|
+
value = [value];
|
661
|
+
}
|
662
|
+
|
663
|
+
data[name] = (data[name] || []).concat(value);
|
636
664
|
} else {
|
637
|
-
|
665
|
+
throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');
|
638
666
|
}
|
639
|
-
};
|
640
|
-
URI.removeQuery = function(data, name, value) {
|
667
|
+
};
|
668
|
+
URI.removeQuery = function(data, name, value) {
|
641
669
|
var i, length, key;
|
642
|
-
|
670
|
+
|
643
671
|
if (isArray(name)) {
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
} else if (typeof name ===
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
} else if (typeof name ===
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
672
|
+
for (i = 0, length = name.length; i < length; i++) {
|
673
|
+
data[name[i]] = undefined;
|
674
|
+
}
|
675
|
+
} else if (typeof name === 'object') {
|
676
|
+
for (key in name) {
|
677
|
+
if (hasOwn.call(name, key)) {
|
678
|
+
URI.removeQuery(data, key, name[key]);
|
679
|
+
}
|
680
|
+
}
|
681
|
+
} else if (typeof name === 'string') {
|
682
|
+
if (value !== undefined) {
|
683
|
+
if (data[name] === value) {
|
684
|
+
data[name] = undefined;
|
685
|
+
} else if (isArray(data[name])) {
|
686
|
+
data[name] = filterArrayValues(data[name], value);
|
687
|
+
}
|
688
|
+
} else {
|
689
|
+
data[name] = undefined;
|
690
|
+
}
|
663
691
|
} else {
|
664
|
-
|
665
|
-
}
|
666
|
-
};
|
667
|
-
URI.hasQuery = function(data, name, value, withinArray) {
|
668
|
-
if (typeof name ===
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
}
|
692
|
+
throw new TypeError('URI.addQuery() accepts an object, string as the first parameter');
|
693
|
+
}
|
694
|
+
};
|
695
|
+
URI.hasQuery = function(data, name, value, withinArray) {
|
696
|
+
if (typeof name === 'object') {
|
697
|
+
for (var key in name) {
|
698
|
+
if (hasOwn.call(name, key)) {
|
699
|
+
if (!URI.hasQuery(data, key, name[key])) {
|
700
|
+
return false;
|
701
|
+
}
|
675
702
|
}
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
703
|
+
}
|
704
|
+
|
705
|
+
return true;
|
706
|
+
} else if (typeof name !== 'string') {
|
707
|
+
throw new TypeError('URI.hasQuery() accepts an object, string as the name parameter');
|
680
708
|
}
|
681
709
|
|
682
710
|
switch (getType(value)) {
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
case 'Boolean':
|
688
|
-
// true if exists and non-empty
|
689
|
-
var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);
|
690
|
-
return value === _booly;
|
691
|
-
|
692
|
-
case 'Function':
|
693
|
-
// allow complex comparison
|
694
|
-
return !!value(data[name], name, data);
|
695
|
-
|
696
|
-
case 'Array':
|
697
|
-
if (!isArray(data[name])) {
|
698
|
-
return false;
|
699
|
-
}
|
711
|
+
case 'Undefined':
|
712
|
+
// true if exists (but may be empty)
|
713
|
+
return name in data; // data[name] !== undefined;
|
700
714
|
|
701
|
-
|
702
|
-
|
715
|
+
case 'Boolean':
|
716
|
+
// true if exists and non-empty
|
717
|
+
var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);
|
718
|
+
return value === _booly;
|
703
719
|
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
}
|
720
|
+
case 'Function':
|
721
|
+
// allow complex comparison
|
722
|
+
return !!value(data[name], name, data);
|
708
723
|
|
709
|
-
|
710
|
-
|
711
|
-
|
724
|
+
case 'Array':
|
725
|
+
if (!isArray(data[name])) {
|
726
|
+
return false;
|
727
|
+
}
|
712
728
|
|
713
|
-
|
729
|
+
var op = withinArray ? arrayContains : arraysEqual;
|
730
|
+
return op(data[name], value);
|
714
731
|
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
if (!isArray(data[name])) {
|
720
|
-
return data[name] === value;
|
721
|
-
}
|
732
|
+
case 'RegExp':
|
733
|
+
if (!isArray(data[name])) {
|
734
|
+
return Boolean(data[name] && data[name].match(value));
|
735
|
+
}
|
722
736
|
|
723
|
-
|
724
|
-
|
725
|
-
|
737
|
+
if (!withinArray) {
|
738
|
+
return false;
|
739
|
+
}
|
740
|
+
|
741
|
+
return arrayContains(data[name], value);
|
742
|
+
|
743
|
+
case 'Number':
|
744
|
+
value = String(value);
|
745
|
+
/* falls through */
|
746
|
+
case 'String':
|
747
|
+
if (!isArray(data[name])) {
|
748
|
+
return data[name] === value;
|
749
|
+
}
|
750
|
+
|
751
|
+
if (!withinArray) {
|
752
|
+
return false;
|
753
|
+
}
|
726
754
|
|
727
|
-
|
755
|
+
return arrayContains(data[name], value);
|
728
756
|
|
729
|
-
|
730
|
-
|
757
|
+
default:
|
758
|
+
throw new TypeError('URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter');
|
731
759
|
}
|
732
|
-
};
|
760
|
+
};
|
733
761
|
|
734
762
|
|
735
|
-
URI.commonPath = function(one, two) {
|
763
|
+
URI.commonPath = function(one, two) {
|
736
764
|
var length = Math.min(one.length, two.length);
|
737
765
|
var pos;
|
738
766
|
|
739
767
|
// find first non-matching character
|
740
768
|
for (pos = 0; pos < length; pos++) {
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
769
|
+
if (one.charAt(pos) !== two.charAt(pos)) {
|
770
|
+
pos--;
|
771
|
+
break;
|
772
|
+
}
|
745
773
|
}
|
746
774
|
|
747
775
|
if (pos < 1) {
|
748
|
-
|
776
|
+
return one.charAt(0) === two.charAt(0) && one.charAt(0) === '/' ? '/' : '';
|
749
777
|
}
|
750
|
-
|
778
|
+
|
751
779
|
// revert to last /
|
752
780
|
if (one.charAt(pos) !== '/' || two.charAt(pos) !== '/') {
|
753
|
-
|
781
|
+
pos = one.substring(0, pos).lastIndexOf('/');
|
754
782
|
}
|
755
783
|
|
756
784
|
return one.substring(0, pos + 1);
|
757
|
-
};
|
785
|
+
};
|
786
|
+
|
787
|
+
URI.withinString = function(string, callback, options) {
|
788
|
+
options || (options = {});
|
789
|
+
var _start = options.start || URI.findUri.start;
|
790
|
+
var _end = options.end || URI.findUri.end;
|
791
|
+
var _trim = options.trim || URI.findUri.trim;
|
792
|
+
var _attributeOpen = /[a-z0-9-]=["']?$/i;
|
793
|
+
|
794
|
+
_start.lastIndex = 0;
|
795
|
+
while (true) {
|
796
|
+
var match = _start.exec(string);
|
797
|
+
if (!match) {
|
798
|
+
break;
|
799
|
+
}
|
800
|
+
|
801
|
+
var start = match.index;
|
802
|
+
if (options.ignoreHtml) {
|
803
|
+
// attribut(e=["']?$)
|
804
|
+
var attributeOpen = string.slice(Math.max(start - 3, 0), start);
|
805
|
+
if (attributeOpen && _attributeOpen.test(attributeOpen)) {
|
806
|
+
continue;
|
807
|
+
}
|
808
|
+
}
|
758
809
|
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
810
|
+
var end = start + string.slice(start).search(_end);
|
811
|
+
var slice = string.slice(start, end).replace(_trim, '');
|
812
|
+
if (options.ignore && options.ignore.test(slice)) {
|
813
|
+
continue;
|
814
|
+
}
|
764
815
|
|
765
|
-
|
766
|
-
|
816
|
+
end = start + slice.length;
|
817
|
+
var result = callback(slice, start, end, string);
|
818
|
+
string = string.slice(0, start) + result + string.slice(end);
|
819
|
+
_start.lastIndex = start + result.length;
|
820
|
+
}
|
767
821
|
|
768
|
-
|
822
|
+
_start.lastIndex = 0;
|
823
|
+
return string;
|
824
|
+
};
|
825
|
+
|
826
|
+
URI.ensureValidHostname = function(v) {
|
769
827
|
// Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986)
|
770
828
|
// they are not part of DNS and therefore ignored by URI.js
|
771
829
|
|
772
830
|
if (v.match(URI.invalid_hostname_characters)) {
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
831
|
+
// test punycode
|
832
|
+
if (!punycode) {
|
833
|
+
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-] and Punycode.js is not available');
|
834
|
+
}
|
777
835
|
|
778
|
-
|
779
|
-
|
780
|
-
|
836
|
+
if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) {
|
837
|
+
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-]');
|
838
|
+
}
|
781
839
|
}
|
782
|
-
};
|
840
|
+
};
|
783
841
|
|
784
|
-
// noConflict
|
785
|
-
URI.noConflict = function(removeAll) {
|
842
|
+
// noConflict
|
843
|
+
URI.noConflict = function(removeAll) {
|
786
844
|
if (removeAll) {
|
787
|
-
|
788
|
-
|
789
|
-
|
845
|
+
var unconflicted = {
|
846
|
+
URI: this.noConflict()
|
847
|
+
};
|
790
848
|
|
791
|
-
|
792
|
-
|
793
|
-
|
849
|
+
if (root.URITemplate && typeof root.URITemplate.noConflict === 'function') {
|
850
|
+
unconflicted.URITemplate = root.URITemplate.noConflict();
|
851
|
+
}
|
794
852
|
|
795
|
-
|
796
|
-
|
797
|
-
|
853
|
+
if (root.IPv6 && typeof root.IPv6.noConflict === 'function') {
|
854
|
+
unconflicted.IPv6 = root.IPv6.noConflict();
|
855
|
+
}
|
798
856
|
|
799
|
-
|
800
|
-
|
801
|
-
|
857
|
+
if (root.SecondLevelDomains && typeof root.SecondLevelDomains.noConflict === 'function') {
|
858
|
+
unconflicted.SecondLevelDomains = root.SecondLevelDomains.noConflict();
|
859
|
+
}
|
802
860
|
|
803
|
-
|
861
|
+
return unconflicted;
|
804
862
|
} else if (root.URI === this) {
|
805
|
-
|
863
|
+
root.URI = _URI;
|
806
864
|
}
|
807
865
|
|
808
866
|
return this;
|
809
|
-
};
|
867
|
+
};
|
810
868
|
|
811
|
-
p.build = function(deferBuild) {
|
869
|
+
p.build = function(deferBuild) {
|
812
870
|
if (deferBuild === true) {
|
813
|
-
|
871
|
+
this._deferred_build = true;
|
814
872
|
} else if (deferBuild === undefined || this._deferred_build) {
|
815
|
-
|
816
|
-
|
873
|
+
this._string = URI.build(this._parts);
|
874
|
+
this._deferred_build = false;
|
817
875
|
}
|
818
876
|
|
819
877
|
return this;
|
820
|
-
};
|
878
|
+
};
|
821
879
|
|
822
|
-
p.clone = function() {
|
880
|
+
p.clone = function() {
|
823
881
|
return new URI(this);
|
824
|
-
};
|
882
|
+
};
|
825
883
|
|
826
|
-
p.valueOf = p.toString = function() {
|
884
|
+
p.valueOf = p.toString = function() {
|
827
885
|
return this.build(false)._string;
|
828
|
-
};
|
886
|
+
};
|
887
|
+
|
829
888
|
|
830
|
-
|
831
|
-
_parts = {protocol: 'protocol', username: 'username', password: 'password', hostname: 'hostname', port: 'port'};
|
832
|
-
generateAccessor = function(_part){
|
889
|
+
function generateSimpleAccessor(_part){
|
833
890
|
return function(v, build) {
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
891
|
+
if (v === undefined) {
|
892
|
+
return this._parts[_part] || '';
|
893
|
+
} else {
|
894
|
+
this._parts[_part] = v || null;
|
895
|
+
this.build(!build);
|
896
|
+
return this;
|
897
|
+
}
|
841
898
|
};
|
842
|
-
}
|
899
|
+
}
|
843
900
|
|
844
|
-
|
845
|
-
p[_part] = generateAccessor(_parts[_part]);
|
846
|
-
}
|
847
|
-
|
848
|
-
// generate accessors with optionally prefixed input
|
849
|
-
_parts = {query: '?', fragment: '#'};
|
850
|
-
generateAccessor = function(_part, _key){
|
901
|
+
function generatePrefixAccessor(_part, _key){
|
851
902
|
return function(v, build) {
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
}
|
861
|
-
|
862
|
-
this._parts[_part] = v;
|
863
|
-
this.build(!build);
|
864
|
-
return this;
|
903
|
+
if (v === undefined) {
|
904
|
+
return this._parts[_part] || '';
|
905
|
+
} else {
|
906
|
+
if (v !== null) {
|
907
|
+
v = v + '';
|
908
|
+
if (v.charAt(0) === _key) {
|
909
|
+
v = v.substring(1);
|
910
|
+
}
|
865
911
|
}
|
866
|
-
};
|
867
|
-
};
|
868
912
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
// generate accessors with prefixed output
|
874
|
-
_parts = {search: ['?', 'query'], hash: ['#', 'fragment']};
|
875
|
-
generateAccessor = function(_part, _key){
|
876
|
-
return function(v, build) {
|
877
|
-
var t = this[_part](v, build);
|
878
|
-
return typeof t === "string" && t.length ? (_key + t) : t;
|
913
|
+
this._parts[_part] = v;
|
914
|
+
this.build(!build);
|
915
|
+
return this;
|
916
|
+
}
|
879
917
|
};
|
880
|
-
}
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
p.
|
918
|
+
}
|
919
|
+
|
920
|
+
p.protocol = generateSimpleAccessor('protocol');
|
921
|
+
p.username = generateSimpleAccessor('username');
|
922
|
+
p.password = generateSimpleAccessor('password');
|
923
|
+
p.hostname = generateSimpleAccessor('hostname');
|
924
|
+
p.port = generateSimpleAccessor('port');
|
925
|
+
p.query = generatePrefixAccessor('query', '?');
|
926
|
+
p.fragment = generatePrefixAccessor('fragment', '#');
|
927
|
+
|
928
|
+
p.search = function(v, build) {
|
929
|
+
var t = this.query(v, build);
|
930
|
+
return typeof t === 'string' && t.length ? ('?' + t) : t;
|
931
|
+
};
|
932
|
+
p.hash = function(v, build) {
|
933
|
+
var t = this.fragment(v, build);
|
934
|
+
return typeof t === 'string' && t.length ? ('#' + t) : t;
|
935
|
+
};
|
936
|
+
|
937
|
+
p.pathname = function(v, build) {
|
887
938
|
if (v === undefined || v === true) {
|
888
|
-
|
889
|
-
|
939
|
+
var res = this._parts.path || (this._parts.hostname ? '/' : '');
|
940
|
+
return v ? URI.decodePath(res) : res;
|
890
941
|
} else {
|
891
|
-
|
892
|
-
|
893
|
-
|
942
|
+
this._parts.path = v ? URI.recodePath(v) : '/';
|
943
|
+
this.build(!build);
|
944
|
+
return this;
|
894
945
|
}
|
895
|
-
};
|
896
|
-
p.path = p.pathname;
|
897
|
-
p.href = function(href, build) {
|
946
|
+
};
|
947
|
+
p.path = p.pathname;
|
948
|
+
p.href = function(href, build) {
|
898
949
|
var key;
|
899
|
-
|
950
|
+
|
900
951
|
if (href === undefined) {
|
901
|
-
|
952
|
+
return this.toString();
|
902
953
|
}
|
903
954
|
|
904
|
-
this._string =
|
955
|
+
this._string = '';
|
905
956
|
this._parts = URI._parts();
|
906
957
|
|
907
958
|
var _URI = href instanceof URI;
|
908
|
-
var _object = typeof href ===
|
959
|
+
var _object = typeof href === 'object' && (href.hostname || href.path || href.pathname);
|
909
960
|
if (href.nodeName) {
|
910
|
-
|
911
|
-
|
912
|
-
|
961
|
+
var attribute = URI.getDomAttribute(href);
|
962
|
+
href = href[attribute] || '';
|
963
|
+
_object = false;
|
913
964
|
}
|
914
|
-
|
965
|
+
|
915
966
|
// window.location is reported to be an object, but it's not the sort
|
916
|
-
// of object we're looking for:
|
967
|
+
// of object we're looking for:
|
917
968
|
// * location.protocol ends with a colon
|
918
969
|
// * location.query != object.search
|
919
970
|
// * location.hash != object.fragment
|
920
|
-
// simply serializing the unknown object should do the trick
|
971
|
+
// simply serializing the unknown object should do the trick
|
921
972
|
// (for location, not for everything...)
|
922
973
|
if (!_URI && _object && href.pathname !== undefined) {
|
923
|
-
|
974
|
+
href = href.toString();
|
924
975
|
}
|
925
976
|
|
926
|
-
if (typeof href ===
|
927
|
-
|
977
|
+
if (typeof href === 'string' || href instanceof String) {
|
978
|
+
this._parts = URI.parse(String(href), this._parts);
|
928
979
|
} else if (_URI || _object) {
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
}
|
980
|
+
var src = _URI ? href._parts : href;
|
981
|
+
for (key in src) {
|
982
|
+
if (hasOwn.call(this._parts, key)) {
|
983
|
+
this._parts[key] = src[key];
|
934
984
|
}
|
985
|
+
}
|
935
986
|
} else {
|
936
|
-
|
987
|
+
throw new TypeError('invalid input');
|
937
988
|
}
|
938
989
|
|
939
990
|
this.build(!build);
|
940
991
|
return this;
|
941
|
-
};
|
992
|
+
};
|
942
993
|
|
943
|
-
// identification accessors
|
944
|
-
p.is = function(what) {
|
994
|
+
// identification accessors
|
995
|
+
p.is = function(what) {
|
945
996
|
var ip = false;
|
946
997
|
var ip4 = false;
|
947
998
|
var ip6 = false;
|
@@ -952,740 +1003,751 @@ p.is = function(what) {
|
|
952
1003
|
var relative = !this._parts.urn;
|
953
1004
|
|
954
1005
|
if (this._parts.hostname) {
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
1006
|
+
relative = false;
|
1007
|
+
ip4 = URI.ip4_expression.test(this._parts.hostname);
|
1008
|
+
ip6 = URI.ip6_expression.test(this._parts.hostname);
|
1009
|
+
ip = ip4 || ip6;
|
1010
|
+
name = !ip;
|
1011
|
+
sld = name && SLD && SLD.has(this._parts.hostname);
|
1012
|
+
idn = name && URI.idn_expression.test(this._parts.hostname);
|
1013
|
+
punycode = name && URI.punycode_expression.test(this._parts.hostname);
|
963
1014
|
}
|
964
1015
|
|
965
1016
|
switch (what.toLowerCase()) {
|
966
|
-
|
967
|
-
|
1017
|
+
case 'relative':
|
1018
|
+
return relative;
|
968
1019
|
|
969
|
-
|
970
|
-
|
1020
|
+
case 'absolute':
|
1021
|
+
return !relative;
|
971
1022
|
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
1023
|
+
// hostname identification
|
1024
|
+
case 'domain':
|
1025
|
+
case 'name':
|
1026
|
+
return name;
|
976
1027
|
|
977
|
-
|
978
|
-
|
1028
|
+
case 'sld':
|
1029
|
+
return sld;
|
979
1030
|
|
980
|
-
|
981
|
-
|
1031
|
+
case 'ip':
|
1032
|
+
return ip;
|
982
1033
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
1034
|
+
case 'ip4':
|
1035
|
+
case 'ipv4':
|
1036
|
+
case 'inet4':
|
1037
|
+
return ip4;
|
987
1038
|
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
1039
|
+
case 'ip6':
|
1040
|
+
case 'ipv6':
|
1041
|
+
case 'inet6':
|
1042
|
+
return ip6;
|
992
1043
|
|
993
|
-
|
994
|
-
|
1044
|
+
case 'idn':
|
1045
|
+
return idn;
|
995
1046
|
|
996
|
-
|
997
|
-
|
1047
|
+
case 'url':
|
1048
|
+
return !this._parts.urn;
|
998
1049
|
|
999
|
-
|
1000
|
-
|
1050
|
+
case 'urn':
|
1051
|
+
return !!this._parts.urn;
|
1001
1052
|
|
1002
|
-
|
1003
|
-
|
1053
|
+
case 'punycode':
|
1054
|
+
return punycode;
|
1004
1055
|
}
|
1005
1056
|
|
1006
1057
|
return null;
|
1007
|
-
};
|
1058
|
+
};
|
1008
1059
|
|
1009
|
-
// component specific input validation
|
1010
|
-
var _protocol = p.protocol;
|
1011
|
-
var _port = p.port;
|
1012
|
-
var _hostname = p.hostname;
|
1060
|
+
// component specific input validation
|
1061
|
+
var _protocol = p.protocol;
|
1062
|
+
var _port = p.port;
|
1063
|
+
var _hostname = p.hostname;
|
1013
1064
|
|
1014
|
-
p.protocol = function(v, build) {
|
1065
|
+
p.protocol = function(v, build) {
|
1015
1066
|
if (v !== undefined) {
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1067
|
+
if (v) {
|
1068
|
+
// accept trailing ://
|
1069
|
+
v = v.replace(/:(\/\/)?$/, '');
|
1019
1070
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
}
|
1071
|
+
if (!v.match(URI.protocol_expression)) {
|
1072
|
+
throw new TypeError('Protocol "' + v + '" contains characters other than [A-Z0-9.+-] or doesn\'t start with [A-Z]');
|
1023
1073
|
}
|
1074
|
+
}
|
1024
1075
|
}
|
1025
1076
|
return _protocol.call(this, v, build);
|
1026
|
-
};
|
1027
|
-
p.scheme = p.protocol;
|
1028
|
-
p.port = function(v, build) {
|
1077
|
+
};
|
1078
|
+
p.scheme = p.protocol;
|
1079
|
+
p.port = function(v, build) {
|
1029
1080
|
if (this._parts.urn) {
|
1030
|
-
|
1081
|
+
return v === undefined ? '' : this;
|
1031
1082
|
}
|
1032
1083
|
|
1033
1084
|
if (v !== undefined) {
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1085
|
+
if (v === 0) {
|
1086
|
+
v = null;
|
1087
|
+
}
|
1037
1088
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1089
|
+
if (v) {
|
1090
|
+
v += '';
|
1091
|
+
if (v.charAt(0) === ':') {
|
1092
|
+
v = v.substring(1);
|
1093
|
+
}
|
1043
1094
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
}
|
1095
|
+
if (v.match(/[^0-9]/)) {
|
1096
|
+
throw new TypeError('Port "' + v + '" contains characters other than [0-9]');
|
1047
1097
|
}
|
1098
|
+
}
|
1048
1099
|
}
|
1049
1100
|
return _port.call(this, v, build);
|
1050
|
-
};
|
1051
|
-
p.hostname = function(v, build) {
|
1101
|
+
};
|
1102
|
+
p.hostname = function(v, build) {
|
1052
1103
|
if (this._parts.urn) {
|
1053
|
-
|
1104
|
+
return v === undefined ? '' : this;
|
1054
1105
|
}
|
1055
1106
|
|
1056
1107
|
if (v !== undefined) {
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1108
|
+
var x = {};
|
1109
|
+
URI.parseHost(v, x);
|
1110
|
+
v = x.hostname;
|
1060
1111
|
}
|
1061
1112
|
return _hostname.call(this, v, build);
|
1062
|
-
};
|
1113
|
+
};
|
1063
1114
|
|
1064
|
-
// compound accessors
|
1065
|
-
p.host = function(v, build) {
|
1115
|
+
// compound accessors
|
1116
|
+
p.host = function(v, build) {
|
1066
1117
|
if (this._parts.urn) {
|
1067
|
-
|
1118
|
+
return v === undefined ? '' : this;
|
1068
1119
|
}
|
1069
1120
|
|
1070
1121
|
if (v === undefined) {
|
1071
|
-
|
1122
|
+
return this._parts.hostname ? URI.buildHost(this._parts) : '';
|
1072
1123
|
} else {
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1124
|
+
URI.parseHost(v, this._parts);
|
1125
|
+
this.build(!build);
|
1126
|
+
return this;
|
1076
1127
|
}
|
1077
|
-
};
|
1078
|
-
p.authority = function(v, build) {
|
1128
|
+
};
|
1129
|
+
p.authority = function(v, build) {
|
1079
1130
|
if (this._parts.urn) {
|
1080
|
-
|
1131
|
+
return v === undefined ? '' : this;
|
1081
1132
|
}
|
1082
1133
|
|
1083
1134
|
if (v === undefined) {
|
1084
|
-
|
1135
|
+
return this._parts.hostname ? URI.buildAuthority(this._parts) : '';
|
1085
1136
|
} else {
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1137
|
+
URI.parseAuthority(v, this._parts);
|
1138
|
+
this.build(!build);
|
1139
|
+
return this;
|
1089
1140
|
}
|
1090
|
-
};
|
1091
|
-
p.userinfo = function(v, build) {
|
1141
|
+
};
|
1142
|
+
p.userinfo = function(v, build) {
|
1092
1143
|
if (this._parts.urn) {
|
1093
|
-
|
1144
|
+
return v === undefined ? '' : this;
|
1094
1145
|
}
|
1095
1146
|
|
1096
1147
|
if (v === undefined) {
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1148
|
+
if (!this._parts.username) {
|
1149
|
+
return '';
|
1150
|
+
}
|
1100
1151
|
|
1101
|
-
|
1102
|
-
|
1152
|
+
var t = URI.buildUserinfo(this._parts);
|
1153
|
+
return t.substring(0, t.length -1);
|
1103
1154
|
} else {
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1155
|
+
if (v[v.length-1] !== '@') {
|
1156
|
+
v += '@';
|
1157
|
+
}
|
1107
1158
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1159
|
+
URI.parseUserinfo(v, this._parts);
|
1160
|
+
this.build(!build);
|
1161
|
+
return this;
|
1111
1162
|
}
|
1112
|
-
};
|
1113
|
-
p.resource = function(v, build) {
|
1163
|
+
};
|
1164
|
+
p.resource = function(v, build) {
|
1114
1165
|
var parts;
|
1115
|
-
|
1166
|
+
|
1116
1167
|
if (v === undefined) {
|
1117
|
-
|
1168
|
+
return this.path() + this.search() + this.hash();
|
1118
1169
|
}
|
1119
|
-
|
1170
|
+
|
1120
1171
|
parts = URI.parse(v);
|
1121
1172
|
this._parts.path = parts.path;
|
1122
1173
|
this._parts.query = parts.query;
|
1123
1174
|
this._parts.fragment = parts.fragment;
|
1124
1175
|
this.build(!build);
|
1125
1176
|
return this;
|
1126
|
-
};
|
1177
|
+
};
|
1127
1178
|
|
1128
|
-
// fraction accessors
|
1129
|
-
p.subdomain = function(v, build) {
|
1179
|
+
// fraction accessors
|
1180
|
+
p.subdomain = function(v, build) {
|
1130
1181
|
if (this._parts.urn) {
|
1131
|
-
|
1182
|
+
return v === undefined ? '' : this;
|
1132
1183
|
}
|
1133
1184
|
|
1134
1185
|
// convenience, return "www" from "www.example.org"
|
1135
1186
|
if (v === undefined) {
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1187
|
+
if (!this._parts.hostname || this.is('IP')) {
|
1188
|
+
return '';
|
1189
|
+
}
|
1139
1190
|
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1191
|
+
// grab domain and add another segment
|
1192
|
+
var end = this._parts.hostname.length - this.domain().length - 1;
|
1193
|
+
return this._parts.hostname.substring(0, end) || '';
|
1143
1194
|
} else {
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1195
|
+
var e = this._parts.hostname.length - this.domain().length;
|
1196
|
+
var sub = this._parts.hostname.substring(0, e);
|
1197
|
+
var replace = new RegExp('^' + escapeRegEx(sub));
|
1147
1198
|
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1199
|
+
if (v && v.charAt(v.length - 1) !== '.') {
|
1200
|
+
v += '.';
|
1201
|
+
}
|
1151
1202
|
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1203
|
+
if (v) {
|
1204
|
+
URI.ensureValidHostname(v);
|
1205
|
+
}
|
1155
1206
|
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1207
|
+
this._parts.hostname = this._parts.hostname.replace(replace, v);
|
1208
|
+
this.build(!build);
|
1209
|
+
return this;
|
1159
1210
|
}
|
1160
|
-
};
|
1161
|
-
p.domain = function(v, build) {
|
1211
|
+
};
|
1212
|
+
p.domain = function(v, build) {
|
1162
1213
|
if (this._parts.urn) {
|
1163
|
-
|
1214
|
+
return v === undefined ? '' : this;
|
1164
1215
|
}
|
1165
1216
|
|
1166
1217
|
if (typeof v === 'boolean') {
|
1167
|
-
|
1168
|
-
|
1218
|
+
build = v;
|
1219
|
+
v = undefined;
|
1169
1220
|
}
|
1170
1221
|
|
1171
1222
|
// convenience, return "example.org" from "www.example.org"
|
1172
1223
|
if (v === undefined) {
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1224
|
+
if (!this._parts.hostname || this.is('IP')) {
|
1225
|
+
return '';
|
1226
|
+
}
|
1227
|
+
|
1228
|
+
// if hostname consists of 1 or 2 segments, it must be the domain
|
1229
|
+
var t = this._parts.hostname.match(/\./g);
|
1230
|
+
if (t && t.length < 2) {
|
1231
|
+
return this._parts.hostname;
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
// grab tld and add another segment
|
1235
|
+
var end = this._parts.hostname.length - this.tld(build).length - 1;
|
1236
|
+
end = this._parts.hostname.lastIndexOf('.', end -1) + 1;
|
1237
|
+
return this._parts.hostname.substring(end) || '';
|
1187
1238
|
} else {
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1239
|
+
if (!v) {
|
1240
|
+
throw new TypeError('cannot set domain empty');
|
1241
|
+
}
|
1191
1242
|
|
1192
|
-
|
1243
|
+
URI.ensureValidHostname(v);
|
1193
1244
|
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1245
|
+
if (!this._parts.hostname || this.is('IP')) {
|
1246
|
+
this._parts.hostname = v;
|
1247
|
+
} else {
|
1248
|
+
var replace = new RegExp(escapeRegEx(this.domain()) + '$');
|
1249
|
+
this._parts.hostname = this._parts.hostname.replace(replace, v);
|
1250
|
+
}
|
1200
1251
|
|
1201
|
-
|
1202
|
-
|
1252
|
+
this.build(!build);
|
1253
|
+
return this;
|
1203
1254
|
}
|
1204
|
-
};
|
1205
|
-
p.tld = function(v, build) {
|
1255
|
+
};
|
1256
|
+
p.tld = function(v, build) {
|
1206
1257
|
if (this._parts.urn) {
|
1207
|
-
|
1258
|
+
return v === undefined ? '' : this;
|
1208
1259
|
}
|
1209
1260
|
|
1210
1261
|
if (typeof v === 'boolean') {
|
1211
|
-
|
1212
|
-
|
1262
|
+
build = v;
|
1263
|
+
v = undefined;
|
1213
1264
|
}
|
1214
1265
|
|
1215
1266
|
// return "org" from "www.example.org"
|
1216
1267
|
if (v === undefined) {
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1268
|
+
if (!this._parts.hostname || this.is('IP')) {
|
1269
|
+
return '';
|
1270
|
+
}
|
1220
1271
|
|
1221
|
-
|
1222
|
-
|
1272
|
+
var pos = this._parts.hostname.lastIndexOf('.');
|
1273
|
+
var tld = this._parts.hostname.substring(pos + 1);
|
1223
1274
|
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1275
|
+
if (build !== true && SLD && SLD.list[tld.toLowerCase()]) {
|
1276
|
+
return SLD.get(this._parts.hostname) || tld;
|
1277
|
+
}
|
1227
1278
|
|
1228
|
-
|
1279
|
+
return tld;
|
1229
1280
|
} else {
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
} else {
|
1239
|
-
throw new TypeError("TLD '" + v + "' contains characters other than [A-Z0-9]");
|
1240
|
-
}
|
1241
|
-
} else if (!this._parts.hostname || this.is('IP')) {
|
1242
|
-
throw new ReferenceError("cannot set TLD on non-domain host");
|
1281
|
+
var replace;
|
1282
|
+
|
1283
|
+
if (!v) {
|
1284
|
+
throw new TypeError('cannot set TLD empty');
|
1285
|
+
} else if (v.match(/[^a-zA-Z0-9-]/)) {
|
1286
|
+
if (SLD && SLD.is(v)) {
|
1287
|
+
replace = new RegExp(escapeRegEx(this.tld()) + '$');
|
1288
|
+
this._parts.hostname = this._parts.hostname.replace(replace, v);
|
1243
1289
|
} else {
|
1244
|
-
|
1245
|
-
this._parts.hostname = this._parts.hostname.replace(replace, v);
|
1290
|
+
throw new TypeError('TLD "' + v + '" contains characters other than [A-Z0-9]');
|
1246
1291
|
}
|
1292
|
+
} else if (!this._parts.hostname || this.is('IP')) {
|
1293
|
+
throw new ReferenceError('cannot set TLD on non-domain host');
|
1294
|
+
} else {
|
1295
|
+
replace = new RegExp(escapeRegEx(this.tld()) + '$');
|
1296
|
+
this._parts.hostname = this._parts.hostname.replace(replace, v);
|
1297
|
+
}
|
1247
1298
|
|
1248
|
-
|
1249
|
-
|
1299
|
+
this.build(!build);
|
1300
|
+
return this;
|
1250
1301
|
}
|
1251
|
-
};
|
1252
|
-
p.directory = function(v, build) {
|
1302
|
+
};
|
1303
|
+
p.directory = function(v, build) {
|
1253
1304
|
if (this._parts.urn) {
|
1254
|
-
|
1305
|
+
return v === undefined ? '' : this;
|
1255
1306
|
}
|
1256
1307
|
|
1257
1308
|
if (v === undefined || v === true) {
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1309
|
+
if (!this._parts.path && !this._parts.hostname) {
|
1310
|
+
return '';
|
1311
|
+
}
|
1261
1312
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1313
|
+
if (this._parts.path === '/') {
|
1314
|
+
return '/';
|
1315
|
+
}
|
1265
1316
|
|
1266
|
-
|
1267
|
-
|
1317
|
+
var end = this._parts.path.length - this.filename().length - 1;
|
1318
|
+
var res = this._parts.path.substring(0, end) || (this._parts.hostname ? '/' : '');
|
1268
1319
|
|
1269
|
-
|
1320
|
+
return v ? URI.decodePath(res) : res;
|
1270
1321
|
|
1271
1322
|
} else {
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
// fully qualifier directories begin with a slash
|
1277
|
-
if (!this.is('relative')) {
|
1278
|
-
if (!v) {
|
1279
|
-
v = '/';
|
1280
|
-
}
|
1323
|
+
var e = this._parts.path.length - this.filename().length;
|
1324
|
+
var directory = this._parts.path.substring(0, e);
|
1325
|
+
var replace = new RegExp('^' + escapeRegEx(directory));
|
1281
1326
|
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1327
|
+
// fully qualifier directories begin with a slash
|
1328
|
+
if (!this.is('relative')) {
|
1329
|
+
if (!v) {
|
1330
|
+
v = '/';
|
1285
1331
|
}
|
1286
1332
|
|
1287
|
-
|
1288
|
-
|
1289
|
-
v += '/';
|
1333
|
+
if (v.charAt(0) !== '/') {
|
1334
|
+
v = '/' + v;
|
1290
1335
|
}
|
1336
|
+
}
|
1291
1337
|
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1338
|
+
// directories always end with a slash
|
1339
|
+
if (v && v.charAt(v.length - 1) !== '/') {
|
1340
|
+
v += '/';
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
v = URI.recodePath(v);
|
1344
|
+
this._parts.path = this._parts.path.replace(replace, v);
|
1345
|
+
this.build(!build);
|
1346
|
+
return this;
|
1296
1347
|
}
|
1297
|
-
};
|
1298
|
-
p.filename = function(v, build) {
|
1348
|
+
};
|
1349
|
+
p.filename = function(v, build) {
|
1299
1350
|
if (this._parts.urn) {
|
1300
|
-
|
1351
|
+
return v === undefined ? '' : this;
|
1301
1352
|
}
|
1302
1353
|
|
1303
1354
|
if (v === undefined || v === true) {
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1355
|
+
if (!this._parts.path || this._parts.path === '/') {
|
1356
|
+
return '';
|
1357
|
+
}
|
1307
1358
|
|
1308
|
-
|
1309
|
-
|
1359
|
+
var pos = this._parts.path.lastIndexOf('/');
|
1360
|
+
var res = this._parts.path.substring(pos+1);
|
1310
1361
|
|
1311
|
-
|
1362
|
+
return v ? URI.decodePathSegment(res) : res;
|
1312
1363
|
} else {
|
1313
|
-
|
1314
|
-
|
1315
|
-
if (v.charAt(0) === '/') {
|
1316
|
-
v = v.substring(1);
|
1317
|
-
}
|
1364
|
+
var mutatedDirectory = false;
|
1318
1365
|
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1366
|
+
if (v.charAt(0) === '/') {
|
1367
|
+
v = v.substring(1);
|
1368
|
+
}
|
1322
1369
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1370
|
+
if (v.match(/\.?\//)) {
|
1371
|
+
mutatedDirectory = true;
|
1372
|
+
}
|
1326
1373
|
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
this.build(!build);
|
1331
|
-
}
|
1374
|
+
var replace = new RegExp(escapeRegEx(this.filename()) + '$');
|
1375
|
+
v = URI.recodePath(v);
|
1376
|
+
this._parts.path = this._parts.path.replace(replace, v);
|
1332
1377
|
|
1333
|
-
|
1378
|
+
if (mutatedDirectory) {
|
1379
|
+
this.normalizePath(build);
|
1380
|
+
} else {
|
1381
|
+
this.build(!build);
|
1382
|
+
}
|
1383
|
+
|
1384
|
+
return this;
|
1334
1385
|
}
|
1335
|
-
};
|
1336
|
-
p.suffix = function(v, build) {
|
1386
|
+
};
|
1387
|
+
p.suffix = function(v, build) {
|
1337
1388
|
if (this._parts.urn) {
|
1338
|
-
|
1389
|
+
return v === undefined ? '' : this;
|
1339
1390
|
}
|
1340
1391
|
|
1341
1392
|
if (v === undefined || v === true) {
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1393
|
+
if (!this._parts.path || this._parts.path === '/') {
|
1394
|
+
return '';
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
var filename = this.filename();
|
1398
|
+
var pos = filename.lastIndexOf('.');
|
1399
|
+
var s, res;
|
1400
|
+
|
1401
|
+
if (pos === -1) {
|
1402
|
+
return '';
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
// suffix may only contain alnum characters (yup, I made this up.)
|
1406
|
+
s = filename.substring(pos+1);
|
1407
|
+
res = (/^[a-z0-9%]+$/i).test(s) ? s : '';
|
1408
|
+
return v ? URI.decodePathSegment(res) : res;
|
1358
1409
|
} else {
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
var suffix = this.suffix();
|
1364
|
-
var replace;
|
1410
|
+
if (v.charAt(0) === '.') {
|
1411
|
+
v = v.substring(1);
|
1412
|
+
}
|
1365
1413
|
|
1366
|
-
|
1367
|
-
|
1368
|
-
return this;
|
1369
|
-
}
|
1414
|
+
var suffix = this.suffix();
|
1415
|
+
var replace;
|
1370
1416
|
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
} else {
|
1375
|
-
replace = new RegExp(escapeRegEx(suffix) + "$");
|
1417
|
+
if (!suffix) {
|
1418
|
+
if (!v) {
|
1419
|
+
return this;
|
1376
1420
|
}
|
1377
1421
|
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1422
|
+
this._parts.path += '.' + URI.recodePath(v);
|
1423
|
+
} else if (!v) {
|
1424
|
+
replace = new RegExp(escapeRegEx('.' + suffix) + '$');
|
1425
|
+
} else {
|
1426
|
+
replace = new RegExp(escapeRegEx(suffix) + '$');
|
1427
|
+
}
|
1382
1428
|
|
1383
|
-
|
1384
|
-
|
1429
|
+
if (replace) {
|
1430
|
+
v = URI.recodePath(v);
|
1431
|
+
this._parts.path = this._parts.path.replace(replace, v);
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
this.build(!build);
|
1435
|
+
return this;
|
1385
1436
|
}
|
1386
|
-
};
|
1387
|
-
p.segment = function(segment, v, build) {
|
1437
|
+
};
|
1438
|
+
p.segment = function(segment, v, build) {
|
1388
1439
|
var separator = this._parts.urn ? ':' : '/';
|
1389
1440
|
var path = this.path();
|
1390
1441
|
var absolute = path.substring(0, 1) === '/';
|
1391
1442
|
var segments = path.split(separator);
|
1392
1443
|
|
1393
1444
|
if (segment !== undefined && typeof segment !== 'number') {
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1445
|
+
build = v;
|
1446
|
+
v = segment;
|
1447
|
+
segment = undefined;
|
1397
1448
|
}
|
1398
1449
|
|
1399
1450
|
if (segment !== undefined && typeof segment !== 'number') {
|
1400
|
-
|
1451
|
+
throw new Error('Bad segment "' + segment + '", must be 0-based integer');
|
1401
1452
|
}
|
1402
1453
|
|
1403
1454
|
if (absolute) {
|
1404
|
-
|
1455
|
+
segments.shift();
|
1405
1456
|
}
|
1406
1457
|
|
1407
1458
|
if (segment < 0) {
|
1408
|
-
|
1409
|
-
|
1459
|
+
// allow negative indexes to address from the end
|
1460
|
+
segment = Math.max(segments.length + segment, 0);
|
1410
1461
|
}
|
1411
1462
|
|
1412
1463
|
if (v === undefined) {
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1464
|
+
/*jshint laxbreak: true */
|
1465
|
+
return segment === undefined
|
1466
|
+
? segments
|
1467
|
+
: segments[segment];
|
1468
|
+
/*jshint laxbreak: false */
|
1416
1469
|
} else if (segment === null || segments[segment] === undefined) {
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
} else {
|
1437
|
-
segments.push(v);
|
1438
|
-
}
|
1439
|
-
}
|
1440
|
-
} else {
|
1441
|
-
if (v || (typeof v === "string" && v.length)) {
|
1442
|
-
segments[segment] = v;
|
1470
|
+
if (isArray(v)) {
|
1471
|
+
segments = [];
|
1472
|
+
// collapse empty elements within array
|
1473
|
+
for (var i=0, l=v.length; i < l; i++) {
|
1474
|
+
if (!v[i].length && (!segments.length || !segments[segments.length -1].length)) {
|
1475
|
+
continue;
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
if (segments.length && !segments[segments.length -1].length) {
|
1479
|
+
segments.pop();
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
segments.push(v[i]);
|
1483
|
+
}
|
1484
|
+
} else if (v || typeof v === 'string') {
|
1485
|
+
if (segments[segments.length -1] === '') {
|
1486
|
+
// empty trailing elements have to be overwritten
|
1487
|
+
// to prevent results such as /foo//bar
|
1488
|
+
segments[segments.length -1] = v;
|
1443
1489
|
} else {
|
1444
|
-
|
1490
|
+
segments.push(v);
|
1445
1491
|
}
|
1492
|
+
}
|
1493
|
+
} else {
|
1494
|
+
if (v) {
|
1495
|
+
segments[segment] = v;
|
1496
|
+
} else {
|
1497
|
+
segments.splice(segment, 1);
|
1498
|
+
}
|
1446
1499
|
}
|
1447
1500
|
|
1448
1501
|
if (absolute) {
|
1449
|
-
|
1502
|
+
segments.unshift('');
|
1450
1503
|
}
|
1451
1504
|
|
1452
1505
|
return this.path(segments.join(separator), build);
|
1453
|
-
};
|
1454
|
-
p.segmentCoded = function(segment, v, build) {
|
1506
|
+
};
|
1507
|
+
p.segmentCoded = function(segment, v, build) {
|
1455
1508
|
var segments, i, l;
|
1456
1509
|
|
1457
1510
|
if (typeof segment !== 'number') {
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1511
|
+
build = v;
|
1512
|
+
v = segment;
|
1513
|
+
segment = undefined;
|
1461
1514
|
}
|
1462
1515
|
|
1463
1516
|
if (v === undefined) {
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
}
|
1517
|
+
segments = this.segment(segment, v, build);
|
1518
|
+
if (!isArray(segments)) {
|
1519
|
+
segments = segments !== undefined ? URI.decode(segments) : undefined;
|
1520
|
+
} else {
|
1521
|
+
for (i = 0, l = segments.length; i < l; i++) {
|
1522
|
+
segments[i] = URI.decode(segments[i]);
|
1471
1523
|
}
|
1524
|
+
}
|
1472
1525
|
|
1473
|
-
|
1526
|
+
return segments;
|
1474
1527
|
}
|
1475
1528
|
|
1476
1529
|
if (!isArray(v)) {
|
1477
|
-
|
1530
|
+
v = (typeof v === 'string' || v instanceof String) ? URI.encode(v) : v;
|
1478
1531
|
} else {
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1532
|
+
for (i = 0, l = v.length; i < l; i++) {
|
1533
|
+
v[i] = URI.decode(v[i]);
|
1534
|
+
}
|
1482
1535
|
}
|
1483
1536
|
|
1484
1537
|
return this.segment(segment, v, build);
|
1485
|
-
};
|
1538
|
+
};
|
1486
1539
|
|
1487
|
-
// mutating query string
|
1488
|
-
var q = p.query;
|
1489
|
-
p.query = function(v, build) {
|
1540
|
+
// mutating query string
|
1541
|
+
var q = p.query;
|
1542
|
+
p.query = function(v, build) {
|
1490
1543
|
if (v === true) {
|
1491
|
-
|
1492
|
-
} else if (typeof v ===
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
} else if (v !== undefined && typeof v !==
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1544
|
+
return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1545
|
+
} else if (typeof v === 'function') {
|
1546
|
+
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1547
|
+
var result = v.call(this, data);
|
1548
|
+
this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
|
1549
|
+
this.build(!build);
|
1550
|
+
return this;
|
1551
|
+
} else if (v !== undefined && typeof v !== 'string') {
|
1552
|
+
this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
|
1553
|
+
this.build(!build);
|
1554
|
+
return this;
|
1502
1555
|
} else {
|
1503
|
-
|
1556
|
+
return q.call(this, v, build);
|
1504
1557
|
}
|
1505
|
-
};
|
1506
|
-
p.setQuery = function(name, value, build) {
|
1558
|
+
};
|
1559
|
+
p.setQuery = function(name, value, build) {
|
1507
1560
|
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1508
|
-
|
1509
|
-
if (typeof name ===
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1561
|
+
|
1562
|
+
if (typeof name === 'string' || name instanceof String) {
|
1563
|
+
data[name] = value !== undefined ? value : null;
|
1564
|
+
} else if (typeof name === 'object') {
|
1565
|
+
for (var key in name) {
|
1566
|
+
if (hasOwn.call(name, key)) {
|
1567
|
+
data[key] = name[key];
|
1514
1568
|
}
|
1515
|
-
|
1516
|
-
data[name] = value !== undefined ? value : null;
|
1569
|
+
}
|
1517
1570
|
} else {
|
1518
|
-
|
1571
|
+
throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');
|
1519
1572
|
}
|
1520
|
-
|
1573
|
+
|
1521
1574
|
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
|
1522
|
-
if (typeof name !==
|
1523
|
-
|
1575
|
+
if (typeof name !== 'string') {
|
1576
|
+
build = value;
|
1524
1577
|
}
|
1525
1578
|
|
1526
1579
|
this.build(!build);
|
1527
1580
|
return this;
|
1528
|
-
};
|
1529
|
-
p.addQuery = function(name, value, build) {
|
1581
|
+
};
|
1582
|
+
p.addQuery = function(name, value, build) {
|
1530
1583
|
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1531
1584
|
URI.addQuery(data, name, value === undefined ? null : value);
|
1532
1585
|
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
|
1533
|
-
if (typeof name !==
|
1534
|
-
|
1586
|
+
if (typeof name !== 'string') {
|
1587
|
+
build = value;
|
1535
1588
|
}
|
1536
1589
|
|
1537
1590
|
this.build(!build);
|
1538
1591
|
return this;
|
1539
|
-
};
|
1540
|
-
p.removeQuery = function(name, value, build) {
|
1592
|
+
};
|
1593
|
+
p.removeQuery = function(name, value, build) {
|
1541
1594
|
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1542
1595
|
URI.removeQuery(data, name, value);
|
1543
1596
|
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
|
1544
|
-
if (typeof name !==
|
1545
|
-
|
1597
|
+
if (typeof name !== 'string') {
|
1598
|
+
build = value;
|
1546
1599
|
}
|
1547
1600
|
|
1548
1601
|
this.build(!build);
|
1549
1602
|
return this;
|
1550
|
-
};
|
1551
|
-
p.hasQuery = function(name, value, withinArray) {
|
1603
|
+
};
|
1604
|
+
p.hasQuery = function(name, value, withinArray) {
|
1552
1605
|
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
|
1553
1606
|
return URI.hasQuery(data, name, value, withinArray);
|
1554
|
-
};
|
1555
|
-
p.setSearch = p.setQuery;
|
1556
|
-
p.addSearch = p.addQuery;
|
1557
|
-
p.removeSearch = p.removeQuery;
|
1558
|
-
p.hasSearch = p.hasQuery;
|
1559
|
-
|
1560
|
-
// sanitizing URLs
|
1561
|
-
p.normalize = function() {
|
1607
|
+
};
|
1608
|
+
p.setSearch = p.setQuery;
|
1609
|
+
p.addSearch = p.addQuery;
|
1610
|
+
p.removeSearch = p.removeQuery;
|
1611
|
+
p.hasSearch = p.hasQuery;
|
1612
|
+
|
1613
|
+
// sanitizing URLs
|
1614
|
+
p.normalize = function() {
|
1562
1615
|
if (this._parts.urn) {
|
1563
|
-
|
1564
|
-
.normalizeProtocol(false)
|
1565
|
-
.normalizeQuery(false)
|
1566
|
-
.normalizeFragment(false)
|
1567
|
-
.build();
|
1568
|
-
}
|
1569
|
-
|
1570
|
-
return this
|
1616
|
+
return this
|
1571
1617
|
.normalizeProtocol(false)
|
1572
|
-
.normalizeHostname(false)
|
1573
|
-
.normalizePort(false)
|
1574
|
-
.normalizePath(false)
|
1575
1618
|
.normalizeQuery(false)
|
1576
1619
|
.normalizeFragment(false)
|
1577
1620
|
.build();
|
1578
|
-
}
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1621
|
+
}
|
1622
|
+
|
1623
|
+
return this
|
1624
|
+
.normalizeProtocol(false)
|
1625
|
+
.normalizeHostname(false)
|
1626
|
+
.normalizePort(false)
|
1627
|
+
.normalizePath(false)
|
1628
|
+
.normalizeQuery(false)
|
1629
|
+
.normalizeFragment(false)
|
1630
|
+
.build();
|
1631
|
+
};
|
1632
|
+
p.normalizeProtocol = function(build) {
|
1633
|
+
if (typeof this._parts.protocol === 'string') {
|
1634
|
+
this._parts.protocol = this._parts.protocol.toLowerCase();
|
1635
|
+
this.build(!build);
|
1583
1636
|
}
|
1584
1637
|
|
1585
1638
|
return this;
|
1586
|
-
};
|
1587
|
-
p.normalizeHostname = function(build) {
|
1639
|
+
};
|
1640
|
+
p.normalizeHostname = function(build) {
|
1588
1641
|
if (this._parts.hostname) {
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1642
|
+
if (this.is('IDN') && punycode) {
|
1643
|
+
this._parts.hostname = punycode.toASCII(this._parts.hostname);
|
1644
|
+
} else if (this.is('IPv6') && IPv6) {
|
1645
|
+
this._parts.hostname = IPv6.best(this._parts.hostname);
|
1646
|
+
}
|
1594
1647
|
|
1595
|
-
|
1596
|
-
|
1648
|
+
this._parts.hostname = this._parts.hostname.toLowerCase();
|
1649
|
+
this.build(!build);
|
1597
1650
|
}
|
1598
1651
|
|
1599
1652
|
return this;
|
1600
|
-
};
|
1601
|
-
p.normalizePort = function(build) {
|
1653
|
+
};
|
1654
|
+
p.normalizePort = function(build) {
|
1602
1655
|
// remove port of it's the protocol's default
|
1603
|
-
if (typeof this._parts.protocol ===
|
1604
|
-
|
1605
|
-
|
1656
|
+
if (typeof this._parts.protocol === 'string' && this._parts.port === URI.defaultPorts[this._parts.protocol]) {
|
1657
|
+
this._parts.port = null;
|
1658
|
+
this.build(!build);
|
1606
1659
|
}
|
1607
1660
|
|
1608
1661
|
return this;
|
1609
|
-
};
|
1610
|
-
p.normalizePath = function(build) {
|
1662
|
+
};
|
1663
|
+
p.normalizePath = function(build) {
|
1611
1664
|
if (this._parts.urn) {
|
1612
|
-
|
1665
|
+
return this;
|
1613
1666
|
}
|
1614
1667
|
|
1615
1668
|
if (!this._parts.path || this._parts.path === '/') {
|
1616
|
-
|
1669
|
+
return this;
|
1617
1670
|
}
|
1618
1671
|
|
1619
1672
|
var _was_relative;
|
1620
1673
|
var _path = this._parts.path;
|
1674
|
+
var _leadingParents = '';
|
1621
1675
|
var _parent, _pos;
|
1622
1676
|
|
1623
1677
|
// handle relative paths
|
1624
1678
|
if (_path.charAt(0) !== '/') {
|
1625
|
-
|
1626
|
-
|
1679
|
+
_was_relative = true;
|
1680
|
+
_path = '/' + _path;
|
1627
1681
|
}
|
1628
1682
|
|
1629
1683
|
// resolve simples
|
1630
1684
|
_path = _path
|
1631
|
-
|
1632
|
-
|
1685
|
+
.replace(/(\/(\.\/)+)|(\/\.$)/g, '/')
|
1686
|
+
.replace(/\/{2,}/g, '/');
|
1687
|
+
|
1688
|
+
// remember leading parents
|
1689
|
+
if (_was_relative) {
|
1690
|
+
_leadingParents = _path.substring(1).match(/^(\.\.\/)+/) || '';
|
1691
|
+
if (_leadingParents) {
|
1692
|
+
_leadingParents = _leadingParents[0];
|
1693
|
+
}
|
1694
|
+
}
|
1633
1695
|
|
1634
1696
|
// resolve parents
|
1635
1697
|
while (true) {
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1698
|
+
_parent = _path.indexOf('/..');
|
1699
|
+
if (_parent === -1) {
|
1700
|
+
// no more ../ to resolve
|
1701
|
+
break;
|
1702
|
+
} else if (_parent === 0) {
|
1703
|
+
// top level cannot be relative, skip it
|
1704
|
+
_path = _path.substring(3);
|
1705
|
+
continue;
|
1706
|
+
}
|
1707
|
+
|
1708
|
+
_pos = _path.substring(0, _parent).lastIndexOf('/');
|
1709
|
+
if (_pos === -1) {
|
1710
|
+
_pos = _parent;
|
1711
|
+
}
|
1712
|
+
_path = _path.substring(0, _pos) + _path.substring(_parent + 3);
|
1651
1713
|
}
|
1652
1714
|
|
1653
1715
|
// revert to relative
|
1654
1716
|
if (_was_relative && this.is('relative')) {
|
1655
|
-
|
1717
|
+
_path = _leadingParents + _path.substring(1);
|
1656
1718
|
}
|
1657
1719
|
|
1658
1720
|
_path = URI.recodePath(_path);
|
1659
1721
|
this._parts.path = _path;
|
1660
1722
|
this.build(!build);
|
1661
1723
|
return this;
|
1662
|
-
};
|
1663
|
-
p.normalizePathname = p.normalizePath;
|
1664
|
-
p.normalizeQuery = function(build) {
|
1665
|
-
if (typeof this._parts.query ===
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1724
|
+
};
|
1725
|
+
p.normalizePathname = p.normalizePath;
|
1726
|
+
p.normalizeQuery = function(build) {
|
1727
|
+
if (typeof this._parts.query === 'string') {
|
1728
|
+
if (!this._parts.query.length) {
|
1729
|
+
this._parts.query = null;
|
1730
|
+
} else {
|
1731
|
+
this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace));
|
1732
|
+
}
|
1671
1733
|
|
1672
|
-
|
1734
|
+
this.build(!build);
|
1673
1735
|
}
|
1674
1736
|
|
1675
1737
|
return this;
|
1676
|
-
};
|
1677
|
-
p.normalizeFragment = function(build) {
|
1738
|
+
};
|
1739
|
+
p.normalizeFragment = function(build) {
|
1678
1740
|
if (!this._parts.fragment) {
|
1679
|
-
|
1680
|
-
|
1741
|
+
this._parts.fragment = null;
|
1742
|
+
this.build(!build);
|
1681
1743
|
}
|
1682
1744
|
|
1683
1745
|
return this;
|
1684
|
-
};
|
1685
|
-
p.normalizeSearch = p.normalizeQuery;
|
1686
|
-
p.normalizeHash = p.normalizeFragment;
|
1746
|
+
};
|
1747
|
+
p.normalizeSearch = p.normalizeQuery;
|
1748
|
+
p.normalizeHash = p.normalizeFragment;
|
1687
1749
|
|
1688
|
-
p.iso8859 = function() {
|
1750
|
+
p.iso8859 = function() {
|
1689
1751
|
// expect unicode input, iso8859 output
|
1690
1752
|
var e = URI.encode;
|
1691
1753
|
var d = URI.decode;
|
@@ -1696,9 +1758,9 @@ p.iso8859 = function() {
|
|
1696
1758
|
URI.encode = e;
|
1697
1759
|
URI.decode = d;
|
1698
1760
|
return this;
|
1699
|
-
};
|
1761
|
+
};
|
1700
1762
|
|
1701
|
-
p.unicode = function() {
|
1763
|
+
p.unicode = function() {
|
1702
1764
|
// expect iso8859 input, unicode output
|
1703
1765
|
var e = URI.encode;
|
1704
1766
|
var d = URI.decode;
|
@@ -1709,100 +1771,102 @@ p.unicode = function() {
|
|
1709
1771
|
URI.encode = e;
|
1710
1772
|
URI.decode = d;
|
1711
1773
|
return this;
|
1712
|
-
};
|
1774
|
+
};
|
1713
1775
|
|
1714
|
-
p.readable = function() {
|
1776
|
+
p.readable = function() {
|
1715
1777
|
var uri = this.clone();
|
1716
1778
|
// removing username, password, because they shouldn't be displayed according to RFC 3986
|
1717
|
-
uri.username(
|
1779
|
+
uri.username('').password('').normalize();
|
1718
1780
|
var t = '';
|
1719
1781
|
if (uri._parts.protocol) {
|
1720
|
-
|
1782
|
+
t += uri._parts.protocol + '://';
|
1721
1783
|
}
|
1722
1784
|
|
1723
1785
|
if (uri._parts.hostname) {
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
}
|
1729
|
-
} else {
|
1730
|
-
t += uri.host();
|
1786
|
+
if (uri.is('punycode') && punycode) {
|
1787
|
+
t += punycode.toUnicode(uri._parts.hostname);
|
1788
|
+
if (uri._parts.port) {
|
1789
|
+
t += ':' + uri._parts.port;
|
1731
1790
|
}
|
1791
|
+
} else {
|
1792
|
+
t += uri.host();
|
1793
|
+
}
|
1732
1794
|
}
|
1733
1795
|
|
1734
1796
|
if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== '/') {
|
1735
|
-
|
1797
|
+
t += '/';
|
1736
1798
|
}
|
1737
1799
|
|
1738
1800
|
t += uri.path(true);
|
1739
1801
|
if (uri._parts.query) {
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
}
|
1802
|
+
var q = '';
|
1803
|
+
for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) {
|
1804
|
+
var kv = (qp[i] || '').split('=');
|
1805
|
+
q += '&' + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace)
|
1806
|
+
.replace(/&/g, '%26');
|
1807
|
+
|
1808
|
+
if (kv[1] !== undefined) {
|
1809
|
+
q += '=' + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace)
|
1810
|
+
.replace(/&/g, '%26');
|
1750
1811
|
}
|
1751
|
-
|
1812
|
+
}
|
1813
|
+
t += '?' + q.substring(1);
|
1752
1814
|
}
|
1753
1815
|
|
1754
1816
|
t += URI.decodeQuery(uri.hash(), true);
|
1755
1817
|
return t;
|
1756
|
-
};
|
1818
|
+
};
|
1757
1819
|
|
1758
|
-
// resolving relative and absolute URLs
|
1759
|
-
p.absoluteTo = function(base) {
|
1820
|
+
// resolving relative and absolute URLs
|
1821
|
+
p.absoluteTo = function(base) {
|
1760
1822
|
var resolved = this.clone();
|
1761
1823
|
var properties = ['protocol', 'username', 'password', 'hostname', 'port'];
|
1762
1824
|
var basedir, i, p;
|
1763
1825
|
|
1764
1826
|
if (this._parts.urn) {
|
1765
|
-
|
1827
|
+
throw new Error('URNs do not have any generally defined hierarchical components');
|
1766
1828
|
}
|
1767
1829
|
|
1768
1830
|
if (!(base instanceof URI)) {
|
1769
|
-
|
1831
|
+
base = new URI(base);
|
1770
1832
|
}
|
1771
|
-
|
1833
|
+
|
1772
1834
|
if (!resolved._parts.protocol) {
|
1773
|
-
|
1835
|
+
resolved._parts.protocol = base._parts.protocol;
|
1774
1836
|
}
|
1775
|
-
|
1837
|
+
|
1776
1838
|
if (this._parts.hostname) {
|
1777
|
-
|
1839
|
+
return resolved;
|
1778
1840
|
}
|
1779
1841
|
|
1780
|
-
for (i = 0; p = properties[i]; i++) {
|
1781
|
-
|
1842
|
+
for (i = 0; (p = properties[i]); i++) {
|
1843
|
+
resolved._parts[p] = base._parts[p];
|
1782
1844
|
}
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1845
|
+
|
1846
|
+
if (!resolved._parts.path) {
|
1847
|
+
resolved._parts.path = base._parts.path;
|
1848
|
+
if (!resolved._parts.query) {
|
1849
|
+
resolved._parts.query = base._parts.query;
|
1850
|
+
}
|
1851
|
+
} else if (resolved._parts.path.substring(-2) === '..') {
|
1852
|
+
resolved._parts.path += '/';
|
1789
1853
|
}
|
1790
1854
|
|
1791
1855
|
if (resolved.path().charAt(0) !== '/') {
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1856
|
+
basedir = base.directory();
|
1857
|
+
resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path;
|
1858
|
+
resolved.normalizePath();
|
1795
1859
|
}
|
1796
1860
|
|
1797
1861
|
resolved.build();
|
1798
1862
|
return resolved;
|
1799
|
-
};
|
1800
|
-
p.relativeTo = function(base) {
|
1863
|
+
};
|
1864
|
+
p.relativeTo = function(base) {
|
1801
1865
|
var relative = this.clone().normalize();
|
1802
1866
|
var relativeParts, baseParts, common, relativePath, basePath;
|
1803
1867
|
|
1804
1868
|
if (relative._parts.urn) {
|
1805
|
-
|
1869
|
+
throw new Error('URNs do not have any generally defined hierarchical components');
|
1806
1870
|
}
|
1807
1871
|
|
1808
1872
|
base = new URI(base).normalize();
|
@@ -1812,57 +1876,57 @@ p.relativeTo = function(base) {
|
|
1812
1876
|
basePath = base.path();
|
1813
1877
|
|
1814
1878
|
if (relativePath.charAt(0) !== '/') {
|
1815
|
-
|
1879
|
+
throw new Error('URI is already relative');
|
1816
1880
|
}
|
1817
1881
|
|
1818
1882
|
if (basePath.charAt(0) !== '/') {
|
1819
|
-
|
1883
|
+
throw new Error('Cannot calculate a URI relative to another relative URI');
|
1820
1884
|
}
|
1821
1885
|
|
1822
1886
|
if (relativeParts.protocol === baseParts.protocol) {
|
1823
|
-
|
1887
|
+
relativeParts.protocol = null;
|
1824
1888
|
}
|
1825
1889
|
|
1826
1890
|
if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) {
|
1827
|
-
|
1891
|
+
return relative.build();
|
1828
1892
|
}
|
1829
1893
|
|
1830
1894
|
if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) {
|
1831
|
-
|
1895
|
+
return relative.build();
|
1832
1896
|
}
|
1833
1897
|
|
1834
1898
|
if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) {
|
1835
|
-
|
1836
|
-
|
1899
|
+
relativeParts.hostname = null;
|
1900
|
+
relativeParts.port = null;
|
1837
1901
|
} else {
|
1838
|
-
|
1902
|
+
return relative.build();
|
1839
1903
|
}
|
1840
1904
|
|
1841
1905
|
if (relativePath === basePath) {
|
1842
|
-
|
1843
|
-
|
1906
|
+
relativeParts.path = '';
|
1907
|
+
return relative.build();
|
1844
1908
|
}
|
1845
|
-
|
1909
|
+
|
1846
1910
|
// determine common sub path
|
1847
1911
|
common = URI.commonPath(relative.path(), base.path());
|
1848
1912
|
|
1849
1913
|
// If the paths have nothing in common, return a relative URL with the absolute path.
|
1850
1914
|
if (!common) {
|
1851
|
-
|
1915
|
+
return relative.build();
|
1852
1916
|
}
|
1853
1917
|
|
1854
1918
|
var parents = baseParts.path
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1919
|
+
.substring(common.length)
|
1920
|
+
.replace(/[^\/]*$/, '')
|
1921
|
+
.replace(/.*?\//g, '../');
|
1858
1922
|
|
1859
1923
|
relativeParts.path = parents + relativeParts.path.substring(common.length);
|
1860
1924
|
|
1861
1925
|
return relative.build();
|
1862
|
-
};
|
1926
|
+
};
|
1863
1927
|
|
1864
|
-
// comparing URIs
|
1865
|
-
p.equals = function(uri) {
|
1928
|
+
// comparing URIs
|
1929
|
+
p.equals = function(uri) {
|
1866
1930
|
var one = this.clone();
|
1867
1931
|
var two = new URI(uri);
|
1868
1932
|
var one_map = {};
|
@@ -1875,64 +1939,64 @@ p.equals = function(uri) {
|
|
1875
1939
|
|
1876
1940
|
// exact match
|
1877
1941
|
if (one.toString() === two.toString()) {
|
1878
|
-
|
1942
|
+
return true;
|
1879
1943
|
}
|
1880
1944
|
|
1881
1945
|
// extract query string
|
1882
1946
|
one_query = one.query();
|
1883
1947
|
two_query = two.query();
|
1884
|
-
one.query(
|
1885
|
-
two.query(
|
1948
|
+
one.query('');
|
1949
|
+
two.query('');
|
1886
1950
|
|
1887
1951
|
// definitely not equal if not even non-query parts match
|
1888
1952
|
if (one.toString() !== two.toString()) {
|
1889
|
-
|
1953
|
+
return false;
|
1890
1954
|
}
|
1891
1955
|
|
1892
1956
|
// query parameters have the same length, even if they're permuted
|
1893
1957
|
if (one_query.length !== two_query.length) {
|
1894
|
-
|
1958
|
+
return false;
|
1895
1959
|
}
|
1896
1960
|
|
1897
1961
|
one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace);
|
1898
1962
|
two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace);
|
1899
1963
|
|
1900
1964
|
for (key in one_map) {
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
}
|
1909
|
-
|
1910
|
-
checked[key] = true;
|
1965
|
+
if (hasOwn.call(one_map, key)) {
|
1966
|
+
if (!isArray(one_map[key])) {
|
1967
|
+
if (one_map[key] !== two_map[key]) {
|
1968
|
+
return false;
|
1969
|
+
}
|
1970
|
+
} else if (!arraysEqual(one_map[key], two_map[key])) {
|
1971
|
+
return false;
|
1911
1972
|
}
|
1973
|
+
|
1974
|
+
checked[key] = true;
|
1975
|
+
}
|
1912
1976
|
}
|
1913
1977
|
|
1914
1978
|
for (key in two_map) {
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
}
|
1979
|
+
if (hasOwn.call(two_map, key)) {
|
1980
|
+
if (!checked[key]) {
|
1981
|
+
// two contains a parameter not present in one
|
1982
|
+
return false;
|
1920
1983
|
}
|
1984
|
+
}
|
1921
1985
|
}
|
1922
1986
|
|
1923
1987
|
return true;
|
1924
|
-
};
|
1988
|
+
};
|
1925
1989
|
|
1926
|
-
// state
|
1927
|
-
p.duplicateQueryParameters = function(v) {
|
1990
|
+
// state
|
1991
|
+
p.duplicateQueryParameters = function(v) {
|
1928
1992
|
this._parts.duplicateQueryParameters = !!v;
|
1929
1993
|
return this;
|
1930
|
-
};
|
1994
|
+
};
|
1931
1995
|
|
1932
|
-
p.escapeQuerySpace = function(v) {
|
1996
|
+
p.escapeQuerySpace = function(v) {
|
1933
1997
|
this._parts.escapeQuerySpace = !!v;
|
1934
1998
|
return this;
|
1935
|
-
};
|
1999
|
+
};
|
1936
2000
|
|
1937
|
-
return URI;
|
2001
|
+
return URI;
|
1938
2002
|
}));
|