@angular-wave/angular.ts 0.0.66 → 0.0.68
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.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/animations/animate-js.js +4 -4
- package/src/animations/animate-swap.js +3 -0
- package/src/core/compile/compile.js +3 -3
- package/src/core/controller/controller.js +0 -5
- package/src/core/di/injector.js +9 -12
- package/src/core/di/internal-injector.js +113 -60
- package/src/core/interval/interval-factory.js +8 -1
- package/src/core/interval/interval.js +30 -16
- package/src/core/location/location.js +473 -626
- package/src/core/location/location.md +114 -0
- package/src/core/location/location.spec.js +1 -76
- package/src/core/parser/parse.js +1 -12
- package/src/core/parser/parse.spec.js +96 -110
- package/src/core/q/q.js +63 -65
- package/src/core/sce/sce.js +1 -3
- package/src/core/scope/scope.js +2 -5
- package/src/core/timeout/timeout.js +110 -111
- package/src/core/url-utils/url-utils.js +5 -0
- package/src/directive/input/input.js +32 -726
- package/src/directive/input/input.md +706 -0
- package/src/directive/options/options.js +2 -156
- package/src/directive/options/options.md +179 -0
- package/src/directive/select/select.js +55 -126
- package/src/directive/select/select.md +74 -0
- package/src/directive/show-hide/show-hide.js +13 -224
- package/src/directive/show-hide/show-hide.md +257 -0
- package/src/exts/messages/messages.js +2 -0
- package/src/filters/limit-to.spec.js +1 -1
- package/src/filters/order-by.spec.js +1 -1
- package/src/index.js +6 -2
- package/src/loader.js +7 -3
- package/src/public.js +1 -7
- package/src/router/params/param.js +54 -54
- package/src/router/path/path-utils.js +1 -0
- package/src/router/state/state-builder.js +2 -4
- package/src/router/state/state-service.js +1 -1
- package/src/router/state-provider.js +1 -1
- package/src/router/template-factory.js +10 -10
- package/src/router/url/url-service.js +11 -4
- package/src/services/anchor-scroll.js +3 -5
- package/src/services/browser.js +2 -9
- package/src/services/cache-factory.js +0 -67
- package/src/services/cache-factory.md +75 -0
- package/src/services/cookie-reader.js +36 -55
- package/src/services/http/http.js +62 -587
- package/src/services/http/http.md +413 -0
- package/src/services/http-backend/http-backend.js +19 -44
- package/src/services/template-request.js +1 -9
- package/src/shared/jqlite/jqlite.js +5 -70
- package/src/types.js +2 -4
- package/types/animations/animate-swap.d.ts +4 -7
- package/types/core/compile/compile.d.ts +6 -6
- package/types/core/controller/controller.d.ts +0 -5
- package/types/core/di/internal-injector.d.ts +73 -18
- package/types/core/exception-handler.d.ts +1 -1
- package/types/core/interval/interval-factory.d.ts +1 -1
- package/types/core/interval/interval.d.ts +4 -0
- package/types/core/location/location.d.ts +235 -166
- package/types/core/parser/parse.d.ts +1 -1
- package/types/core/q/q.d.ts +61 -40
- package/types/core/scope/scope.d.ts +5 -8
- package/types/core/timeout/timeout.d.ts +16 -26
- package/types/core/url-utils/url-utils.d.ts +4 -0
- package/types/directive/input/input.d.ts +19 -124
- package/types/directive/select/select.d.ts +7 -74
- package/types/directive/show-hide/show-hide.d.ts +11 -224
- package/types/loader.d.ts +4 -4
- package/types/router/params/param.d.ts +11 -0
- package/types/router/state/state-builder.d.ts +1 -2
- package/types/router/state/state-service.d.ts +2 -2
- package/types/router/state-provider.d.ts +2 -2
- package/types/router/template-factory.d.ts +15 -15
- package/types/router/url/url-service.d.ts +12 -12
- package/types/services/anchor-scroll.d.ts +1 -1
- package/types/services/browser.d.ts +0 -10
- package/types/services/cache-factory.d.ts +0 -67
- package/types/services/cookie-reader.d.ts +2 -10
- package/types/services/http/http.d.ts +53 -61
- package/types/services/http-backend/http-backend.d.ts +8 -31
- package/types/services/template-request.d.ts +1 -9
- package/types/shared/jqlite/jqlite.d.ts +11 -11
- package/types/types.d.ts +1 -9
|
@@ -2,7 +2,6 @@ import { JQLite } from "../../shared/jqlite/jqlite";
|
|
|
2
2
|
import { urlResolve } from "../url-utils/url-utils";
|
|
3
3
|
import {
|
|
4
4
|
encodeUriSegment,
|
|
5
|
-
forEach,
|
|
6
5
|
isBoolean,
|
|
7
6
|
isDefined,
|
|
8
7
|
isNumber,
|
|
@@ -16,406 +15,107 @@ import {
|
|
|
16
15
|
} from "../../shared/utils";
|
|
17
16
|
import { ScopePhase } from "../scope/scope";
|
|
18
17
|
|
|
19
|
-
export const PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
|
|
20
|
-
const DEFAULT_PORTS = { http: 80, https: 443, ftp: 21 };
|
|
21
|
-
const $locationMinErr = minErr("$location");
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Encode path using encodeUriSegment, ignoring forward slashes
|
|
25
|
-
*
|
|
26
|
-
* @param {string} path Path to encode
|
|
27
|
-
* @returns {string}
|
|
28
|
-
*/
|
|
29
|
-
function encodePath(path) {
|
|
30
|
-
const segments = path.split("/");
|
|
31
|
-
let i = segments.length;
|
|
32
|
-
|
|
33
|
-
while (i--) {
|
|
34
|
-
// decode forward slashes to prevent them from being double encoded
|
|
35
|
-
segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, "/"));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return segments.join("/");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function decodePath(path, html5Mode) {
|
|
42
|
-
const segments = path.split("/");
|
|
43
|
-
let i = segments.length;
|
|
44
|
-
|
|
45
|
-
while (i--) {
|
|
46
|
-
segments[i] = decodeURIComponent(segments[i]);
|
|
47
|
-
if (html5Mode) {
|
|
48
|
-
// encode forward slashes to prevent them from being mistaken for path separators
|
|
49
|
-
segments[i] = segments[i].replace(/\//g, "%2F");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return segments.join("/");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function normalizePath(pathValue, searchValue, hashValue) {
|
|
57
|
-
const search = toKeyValue(searchValue);
|
|
58
|
-
const hash = hashValue ? `#${encodeUriSegment(hashValue)}` : "";
|
|
59
|
-
const path = encodePath(pathValue);
|
|
60
|
-
|
|
61
|
-
return path + (search ? `?${search}` : "") + hash;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function parseAbsoluteUrl(absoluteUrl, locationObj) {
|
|
65
|
-
const parsedUrl = urlResolve(absoluteUrl);
|
|
66
|
-
|
|
67
|
-
locationObj.$$protocol = parsedUrl.protocol;
|
|
68
|
-
locationObj.$$host = parsedUrl.hostname;
|
|
69
|
-
locationObj.$$port =
|
|
70
|
-
toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
|
|
74
|
-
function parseAppUrl(url, locationObj, html5Mode) {
|
|
75
|
-
if (DOUBLE_SLASH_REGEX.test(url)) {
|
|
76
|
-
throw $locationMinErr("badpath", 'Invalid url "{0}".', url);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const prefixed = url.charAt(0) !== "/";
|
|
80
|
-
if (prefixed) {
|
|
81
|
-
url = `/${url}`;
|
|
82
|
-
}
|
|
83
|
-
const match = urlResolve(url);
|
|
84
|
-
const path =
|
|
85
|
-
prefixed && match.pathname.charAt(0) === "/"
|
|
86
|
-
? match.pathname.substring(1)
|
|
87
|
-
: match.pathname;
|
|
88
|
-
locationObj.$$path = decodePath(path, html5Mode);
|
|
89
|
-
locationObj.$$search = parseKeyValue(match.search);
|
|
90
|
-
locationObj.$$hash = decodeURIComponent(match.hash);
|
|
91
|
-
|
|
92
|
-
// make sure path starts with '/';
|
|
93
|
-
if (locationObj.$$path && locationObj.$$path.charAt(0) !== "/") {
|
|
94
|
-
locationObj.$$path = `/${locationObj.$$path}`;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function startsWith(str, search) {
|
|
99
|
-
return str.slice(0, search.length) === search;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
18
|
/**
|
|
103
|
-
*
|
|
104
|
-
* @
|
|
105
|
-
* @
|
|
106
|
-
* @
|
|
107
|
-
* the expected string.
|
|
19
|
+
* @typedef {Object} DefaultPorts
|
|
20
|
+
* @property {number} http
|
|
21
|
+
* @property {number} https
|
|
22
|
+
* @property {number} ftp
|
|
108
23
|
*/
|
|
109
|
-
export function stripBaseUrl(base, url) {
|
|
110
|
-
if (startsWith(url, base)) {
|
|
111
|
-
return url.substr(base.length);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function stripHash(url) {
|
|
116
|
-
const index = url.indexOf("#");
|
|
117
|
-
return index === -1 ? url : url.substr(0, index);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function stripFile(url) {
|
|
121
|
-
return url.substr(0, stripHash(url).lastIndexOf("/") + 1);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/* return the server only (scheme://host:port) */
|
|
125
|
-
export function serverBase(url) {
|
|
126
|
-
return url.substring(0, url.indexOf("/", url.indexOf("//") + 2));
|
|
127
|
-
}
|
|
128
24
|
|
|
129
25
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* @
|
|
134
|
-
* @param {string} appBase application base URL
|
|
135
|
-
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
136
|
-
* @param {string} basePrefix URL path prefix
|
|
26
|
+
* @typedef {Object} Html5Mode
|
|
27
|
+
* @property {boolean} enabled
|
|
28
|
+
* @property {boolean} requireBase
|
|
29
|
+
* @property {boolean|string} rewriteLinks
|
|
137
30
|
*/
|
|
138
|
-
export function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
|
|
139
|
-
this.$$html5 = true;
|
|
140
|
-
basePrefix = basePrefix || "";
|
|
141
|
-
parseAbsoluteUrl(appBase, this);
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Parse given HTML5 (regular) URL string into properties
|
|
145
|
-
* @param {string} url HTML5 URL
|
|
146
|
-
* @private
|
|
147
|
-
*/
|
|
148
|
-
this.$$parse = function (url) {
|
|
149
|
-
const pathUrl = stripBaseUrl(appBaseNoFile, url);
|
|
150
|
-
if (!isString(pathUrl)) {
|
|
151
|
-
throw $locationMinErr(
|
|
152
|
-
"ipthprfx",
|
|
153
|
-
'Invalid url "{0}", missing path prefix "{1}".',
|
|
154
|
-
url,
|
|
155
|
-
appBaseNoFile,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
parseAppUrl(pathUrl, this, true);
|
|
160
|
-
|
|
161
|
-
if (!this.$$path) {
|
|
162
|
-
this.$$path = "/";
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
this.$$compose();
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
this.$$normalizeUrl = function (url) {
|
|
169
|
-
return appBaseNoFile + url.substr(1); // first char is always '/'
|
|
170
|
-
};
|
|
171
31
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.hash(relHref.slice(1));
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
let appUrl;
|
|
180
|
-
let prevAppUrl;
|
|
181
|
-
let rewrittenUrl;
|
|
182
|
-
|
|
183
|
-
if (isDefined((appUrl = stripBaseUrl(appBase, url)))) {
|
|
184
|
-
prevAppUrl = appUrl;
|
|
185
|
-
if (
|
|
186
|
-
basePrefix &&
|
|
187
|
-
isDefined((appUrl = stripBaseUrl(basePrefix, appUrl)))
|
|
188
|
-
) {
|
|
189
|
-
rewrittenUrl = appBaseNoFile + (stripBaseUrl("/", appUrl) || appUrl);
|
|
190
|
-
} else {
|
|
191
|
-
rewrittenUrl = appBase + prevAppUrl;
|
|
192
|
-
}
|
|
193
|
-
} else if (isDefined((appUrl = stripBaseUrl(appBaseNoFile, url)))) {
|
|
194
|
-
rewrittenUrl = appBaseNoFile + appUrl;
|
|
195
|
-
} else if (appBaseNoFile === `${url}/`) {
|
|
196
|
-
rewrittenUrl = appBaseNoFile;
|
|
197
|
-
}
|
|
198
|
-
if (rewrittenUrl) {
|
|
199
|
-
this.$$parse(rewrittenUrl);
|
|
200
|
-
}
|
|
201
|
-
return !!rewrittenUrl;
|
|
202
|
-
};
|
|
203
|
-
}
|
|
32
|
+
/** @type {DefaultPorts} */
|
|
33
|
+
const DEFAULT_PORTS = { http: 80, https: 443, ftp: 21 };
|
|
34
|
+
const PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
|
|
35
|
+
const $locationMinErr = minErr("$location");
|
|
204
36
|
|
|
205
37
|
/**
|
|
206
|
-
*
|
|
207
|
-
* This object is exposed as $location service when developer doesn't opt into html5 mode.
|
|
208
|
-
* It also serves as the base class for html5 mode fallback on legacy browsers.
|
|
209
|
-
*
|
|
210
|
-
* @constructor
|
|
211
|
-
* @param {string} appBase application base URL
|
|
212
|
-
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
213
|
-
* @param {string} hashPrefix hashbang prefix
|
|
38
|
+
* @abstract
|
|
214
39
|
*/
|
|
215
|
-
export
|
|
216
|
-
parseAbsoluteUrl(appBase, this);
|
|
217
|
-
|
|
40
|
+
export class Location {
|
|
218
41
|
/**
|
|
219
|
-
*
|
|
220
|
-
* @param {string}
|
|
221
|
-
* @private
|
|
42
|
+
* @param {string} appBase application base URL
|
|
43
|
+
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
222
44
|
*/
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
let withoutHashUrl;
|
|
227
|
-
|
|
228
|
-
if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === "#") {
|
|
229
|
-
// The rest of the URL starts with a hash so we have
|
|
230
|
-
// got either a hashbang path or a plain hash fragment
|
|
231
|
-
withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);
|
|
232
|
-
if (isUndefined(withoutHashUrl)) {
|
|
233
|
-
// There was no hashbang prefix so we just have a hash fragment
|
|
234
|
-
withoutHashUrl = withoutBaseUrl;
|
|
235
|
-
}
|
|
236
|
-
} else {
|
|
237
|
-
// There was no hashbang path nor hash fragment:
|
|
238
|
-
// If we are in HTML5 mode we use what is left as the path;
|
|
239
|
-
// Otherwise we ignore what is left
|
|
240
|
-
if (this.$$html5) {
|
|
241
|
-
withoutHashUrl = withoutBaseUrl;
|
|
242
|
-
} else {
|
|
243
|
-
withoutHashUrl = "";
|
|
244
|
-
if (isUndefined(withoutBaseUrl)) {
|
|
245
|
-
appBase = url;
|
|
246
|
-
/** @type {?} */ (this).replace();
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
45
|
+
constructor(appBase, appBaseNoFile) {
|
|
46
|
+
/** @type {string} */
|
|
47
|
+
this.appBase = appBase;
|
|
250
48
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
|
|
49
|
+
/** @type {string} */
|
|
50
|
+
this.appBaseNoFile = appBaseNoFile;
|
|
254
51
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
* In Windows, on an anchor node on documents loaded from
|
|
259
|
-
* the filesystem, the browser will return a pathname
|
|
260
|
-
* prefixed with the drive name ('/C:/path') when a
|
|
261
|
-
* pathname without a drive is set:
|
|
262
|
-
* * a.setAttribute('href', '/foo')
|
|
263
|
-
* * a.pathname === '/C:/foo' //true
|
|
264
|
-
*
|
|
265
|
-
* Inside of AngularJS, we're always using pathnames that
|
|
266
|
-
* do not include drive names for routing.
|
|
52
|
+
/**
|
|
53
|
+
* An absolute URL is the full URL, including protocol (http/https ), the optional subdomain (e.g. www ), domain (example.com), and path (which includes the directory and slug).
|
|
54
|
+
* @type {string}
|
|
267
55
|
*/
|
|
268
|
-
|
|
269
|
-
/*
|
|
270
|
-
Matches paths for file protocol on windows,
|
|
271
|
-
such as /C:/foo/bar, and captures only /foo/bar.
|
|
272
|
-
*/
|
|
273
|
-
const windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
|
|
56
|
+
this.$$absUrl = "";
|
|
274
57
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// The input URL intentionally contains a first path segment that ends with a colon.
|
|
283
|
-
if (windowsFilePathExp.exec(url)) {
|
|
284
|
-
return path;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
firstPathSegmentMatch = windowsFilePathExp.exec(path);
|
|
288
|
-
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
this.$$normalizeUrl = function (url) {
|
|
293
|
-
return appBase + (url ? hashPrefix + url : "");
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
this.$$parseLinkUrl = function (url) {
|
|
297
|
-
if (stripHash(appBase) === stripHash(url)) {
|
|
298
|
-
this.$$parse(url);
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
301
|
-
return false;
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* LocationHashbangUrl represents URL
|
|
307
|
-
* This object is exposed as $location service when html5 history api is enabled but the browser
|
|
308
|
-
* does not support it.
|
|
309
|
-
*
|
|
310
|
-
* @constructor
|
|
311
|
-
* @param {string} appBase application base URL
|
|
312
|
-
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
313
|
-
* @param {string} hashPrefix hashbang prefix
|
|
314
|
-
*/
|
|
315
|
-
export function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
|
|
316
|
-
this.$$html5 = true;
|
|
317
|
-
LocationHashbangUrl.apply(this, arguments);
|
|
318
|
-
|
|
319
|
-
this.$$parseLinkUrl = function (url, relHref) {
|
|
320
|
-
if (relHref && relHref[0] === "#") {
|
|
321
|
-
// special case for links to hash fragments:
|
|
322
|
-
// keep the old url and only replace the hash fragment
|
|
323
|
-
this.hash(relHref.slice(1));
|
|
324
|
-
return true;
|
|
325
|
-
}
|
|
58
|
+
/**
|
|
59
|
+
* If html5 mode is enabled
|
|
60
|
+
* @type {boolean}
|
|
61
|
+
*/
|
|
62
|
+
this.$$html5 = false;
|
|
326
63
|
|
|
327
|
-
|
|
328
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Has any change been replacing?
|
|
66
|
+
* @type {boolean}
|
|
67
|
+
*/
|
|
68
|
+
this.$$replace = false;
|
|
329
69
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
} else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {
|
|
333
|
-
rewrittenUrl = appBase + hashPrefix + appUrl;
|
|
334
|
-
} else if (appBaseNoFile === `${url}/`) {
|
|
335
|
-
rewrittenUrl = appBaseNoFile;
|
|
336
|
-
}
|
|
337
|
-
if (rewrittenUrl) {
|
|
338
|
-
this.$$parse(rewrittenUrl);
|
|
339
|
-
}
|
|
340
|
-
return !!rewrittenUrl;
|
|
341
|
-
};
|
|
70
|
+
/** @type {import('../url-utils/url-utils').HttpProtocol} */
|
|
71
|
+
this.$$protocol = undefined;
|
|
342
72
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return appBase + hashPrefix + url;
|
|
346
|
-
};
|
|
347
|
-
}
|
|
73
|
+
/** @type {string} */
|
|
74
|
+
this.$$host = undefined;
|
|
348
75
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
$$absUrl: "",
|
|
76
|
+
/**
|
|
77
|
+
* The port, without ":"
|
|
78
|
+
* @type {number}
|
|
79
|
+
*/
|
|
80
|
+
this.$$port = undefined;
|
|
355
81
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
82
|
+
/**
|
|
83
|
+
* The pathname, beginning with "/"
|
|
84
|
+
* @type {string}
|
|
85
|
+
*/
|
|
86
|
+
this.$$path = undefined;
|
|
361
87
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
88
|
+
/**
|
|
89
|
+
* The hash string, minus the hash symbol
|
|
90
|
+
* @type {string}
|
|
91
|
+
*/
|
|
92
|
+
this.$$hash = undefined;
|
|
367
93
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
this.$$absUrl = this.$$normalizeUrl(this.$$url);
|
|
375
|
-
this.$$urlUpdatedByLocation = true;
|
|
376
|
-
},
|
|
94
|
+
/**
|
|
95
|
+
* Helper property for scope watch changes
|
|
96
|
+
* @type {boolean}
|
|
97
|
+
*/
|
|
98
|
+
this.$$urlUpdatedByLocation = false;
|
|
99
|
+
}
|
|
377
100
|
|
|
378
101
|
/**
|
|
379
|
-
* @ngdoc method
|
|
380
|
-
* @name $location#absUrl
|
|
381
|
-
*
|
|
382
|
-
* @description
|
|
383
|
-
* This method is getter only.
|
|
384
|
-
*
|
|
385
102
|
* Return full URL representation with all segments encoded according to rules specified in
|
|
386
103
|
* [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
|
|
387
104
|
*
|
|
388
|
-
*
|
|
389
|
-
* ```js
|
|
390
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
|
|
391
|
-
* let absUrl = $location.absUrl();
|
|
392
|
-
* // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
|
|
393
|
-
* ```
|
|
394
|
-
*
|
|
395
105
|
* @return {string} full URL
|
|
396
106
|
*/
|
|
397
|
-
absUrl
|
|
107
|
+
absUrl() {
|
|
108
|
+
return this.$$absUrl;
|
|
109
|
+
}
|
|
398
110
|
|
|
399
111
|
/**
|
|
400
|
-
* @ngdoc method
|
|
401
|
-
* @name $location#url
|
|
402
|
-
*
|
|
403
|
-
* @description
|
|
404
112
|
* This method is getter / setter.
|
|
405
113
|
*
|
|
406
114
|
* Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
|
|
407
|
-
*
|
|
408
115
|
* Change path, search and hash, when called with parameter and return `$location`.
|
|
409
116
|
*
|
|
410
|
-
*
|
|
411
|
-
* ```js
|
|
412
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
|
|
413
|
-
* let url = $location.url();
|
|
414
|
-
* // => "/some/path?foo=bar&baz=xoxo"
|
|
415
|
-
* ```
|
|
416
|
-
*
|
|
417
117
|
* @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`)
|
|
418
|
-
* @return {string} url
|
|
118
|
+
* @return {Location|string} url
|
|
419
119
|
*/
|
|
420
120
|
url(url) {
|
|
421
121
|
if (isUndefined(url)) {
|
|
@@ -428,33 +128,18 @@ const locationPrototype = {
|
|
|
428
128
|
this.hash(match[5] || "");
|
|
429
129
|
|
|
430
130
|
return this;
|
|
431
|
-
}
|
|
131
|
+
}
|
|
432
132
|
|
|
433
133
|
/**
|
|
434
|
-
* @ngdoc method
|
|
435
|
-
* @name $location#protocol
|
|
436
|
-
*
|
|
437
|
-
* @description
|
|
438
|
-
* This method is getter only.
|
|
439
134
|
*
|
|
440
135
|
* Return protocol of current URL.
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
* ```js
|
|
444
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
|
|
445
|
-
* let protocol = $location.protocol();
|
|
446
|
-
* // => "http"
|
|
447
|
-
* ```
|
|
448
|
-
*
|
|
449
|
-
* @return {string} protocol of current URL
|
|
136
|
+
* @return {import("../url-utils/url-utils").HttpProtocol} protocol of current URL
|
|
450
137
|
*/
|
|
451
|
-
protocol
|
|
138
|
+
protocol() {
|
|
139
|
+
return this.$$protocol;
|
|
140
|
+
}
|
|
452
141
|
|
|
453
142
|
/**
|
|
454
|
-
* @ngdoc method
|
|
455
|
-
* @name $location#host
|
|
456
|
-
*
|
|
457
|
-
* @description
|
|
458
143
|
* This method is getter only.
|
|
459
144
|
*
|
|
460
145
|
* Return host of current URL.
|
|
@@ -462,27 +147,13 @@ const locationPrototype = {
|
|
|
462
147
|
* Note: compared to the non-AngularJS version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
|
|
463
148
|
*
|
|
464
149
|
*
|
|
465
|
-
* ```js
|
|
466
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
|
|
467
|
-
* let host = $location.host();
|
|
468
|
-
* // => "example.com"
|
|
469
|
-
*
|
|
470
|
-
* // given URL http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
|
|
471
|
-
* host = $location.host();
|
|
472
|
-
* // => "example.com"
|
|
473
|
-
* host = location.host;
|
|
474
|
-
* // => "example.com:8080"
|
|
475
|
-
* ```
|
|
476
|
-
*
|
|
477
150
|
* @return {string} host of current URL.
|
|
478
151
|
*/
|
|
479
|
-
host
|
|
152
|
+
host() {
|
|
153
|
+
return this.$$host;
|
|
154
|
+
}
|
|
480
155
|
|
|
481
156
|
/**
|
|
482
|
-
* @ngdoc method
|
|
483
|
-
* @name $location#port
|
|
484
|
-
*
|
|
485
|
-
* @description
|
|
486
157
|
* This method is getter only.
|
|
487
158
|
*
|
|
488
159
|
* Return port of current URL.
|
|
@@ -494,15 +165,13 @@ const locationPrototype = {
|
|
|
494
165
|
* // => 80
|
|
495
166
|
* ```
|
|
496
167
|
*
|
|
497
|
-
* @return {
|
|
168
|
+
* @return {number} port
|
|
498
169
|
*/
|
|
499
|
-
port
|
|
170
|
+
port() {
|
|
171
|
+
return this.$$port;
|
|
172
|
+
}
|
|
500
173
|
|
|
501
174
|
/**
|
|
502
|
-
* @ngdoc method
|
|
503
|
-
* @name $location#path
|
|
504
|
-
*
|
|
505
|
-
* @description
|
|
506
175
|
* This method is getter / setter.
|
|
507
176
|
*
|
|
508
177
|
* Return path of current URL when called without any parameter.
|
|
@@ -522,55 +191,58 @@ const locationPrototype = {
|
|
|
522
191
|
* @param {(string|number)=} path New path
|
|
523
192
|
* @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
|
|
524
193
|
*/
|
|
525
|
-
path
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
194
|
+
path(path) {
|
|
195
|
+
if (isUndefined(path)) {
|
|
196
|
+
return this.$$path;
|
|
197
|
+
}
|
|
198
|
+
let newPath = path !== null ? path.toString() : "";
|
|
199
|
+
this.$$path = newPath.charAt(0) === "/" ? newPath : `/${newPath}`;
|
|
200
|
+
this.$$compose();
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
529
203
|
|
|
530
204
|
/**
|
|
531
|
-
* @ngdoc method
|
|
532
|
-
* @name $location#search
|
|
533
|
-
*
|
|
534
|
-
* @description
|
|
535
205
|
* This method is getter / setter.
|
|
536
206
|
*
|
|
537
|
-
*
|
|
207
|
+
* Returns the hash fragment when called without any parameters.
|
|
538
208
|
*
|
|
539
|
-
*
|
|
209
|
+
* Changes the hash fragment when called with a parameter and returns `$location`.
|
|
540
210
|
*
|
|
541
211
|
*
|
|
542
212
|
* ```js
|
|
543
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
|
|
544
|
-
* let
|
|
545
|
-
* // =>
|
|
546
|
-
*
|
|
547
|
-
* // set foo to 'yipee'
|
|
548
|
-
* $location.search('foo', 'yipee');
|
|
549
|
-
* // $location.search() => {foo: 'yipee', baz: 'xoxo'}
|
|
213
|
+
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
|
|
214
|
+
* let hash = $location.hash();
|
|
215
|
+
* // => "hashValue"
|
|
550
216
|
* ```
|
|
551
217
|
*
|
|
552
|
-
* @param {string|
|
|
553
|
-
* hash
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
218
|
+
* @param {(string|number)=} hash New hash fragment
|
|
219
|
+
* @return {string|Location} hash
|
|
220
|
+
*/
|
|
221
|
+
hash(hash) {
|
|
222
|
+
if (isUndefined(hash)) {
|
|
223
|
+
return this.$$hash;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
this.$$hash = hash !== null ? hash.toString() : "";
|
|
227
|
+
this.$$compose();
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* If called, all changes to $location during the current `$digest` will replace the current history
|
|
233
|
+
* record, instead of adding a new one.
|
|
234
|
+
*/
|
|
235
|
+
replace() {
|
|
236
|
+
this.$$replace = true;
|
|
237
|
+
return this;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Returns or sets the search part (as object) of current URL when called without any parameter
|
|
571
242
|
*
|
|
572
|
-
* @
|
|
573
|
-
*
|
|
243
|
+
* @param {string|Object=} search New search params - string or hash object.
|
|
244
|
+
* @param {(string|number|Array<string>|boolean)=} paramValue If search is a string or number, then paramValue will override only a single search property.
|
|
245
|
+
* @returns {Object|Location} Search object or Location object
|
|
574
246
|
*/
|
|
575
247
|
search(search, paramValue) {
|
|
576
248
|
switch (arguments.length) {
|
|
@@ -603,149 +275,253 @@ const locationPrototype = {
|
|
|
603
275
|
}
|
|
604
276
|
}
|
|
605
277
|
|
|
606
|
-
this.$$compose();
|
|
607
|
-
return this;
|
|
608
|
-
}
|
|
278
|
+
this.$$compose();
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Compose url and update `url` and `absUrl` property
|
|
284
|
+
* @returns {void}
|
|
285
|
+
*/
|
|
286
|
+
$$compose() {
|
|
287
|
+
this.$$url = normalizePath(this.$$path, this.$$search, this.$$hash);
|
|
288
|
+
this.$$absUrl = this.$$normalizeUrl(this.$$url);
|
|
289
|
+
this.$$urlUpdatedByLocation = true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @param {string} _url
|
|
294
|
+
* @returns {string}
|
|
295
|
+
*/
|
|
296
|
+
$$normalizeUrl(_url) {
|
|
297
|
+
throw new Error(`Method not implemented ${_url}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* This method is getter / setter.
|
|
302
|
+
*
|
|
303
|
+
* Return the history state object when called without any parameter.
|
|
304
|
+
*
|
|
305
|
+
* Change the history state object when called with one parameter and return `$location`.
|
|
306
|
+
* The state object is later passed to `pushState` or `replaceState`.
|
|
307
|
+
* See {@link https://developer.mozilla.org/en-US/docs/Web/API/History/pushState#state|History.state}
|
|
308
|
+
*
|
|
309
|
+
* NOTE: This method is supported only in HTML5 mode and only in browsers supporting
|
|
310
|
+
* the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
|
|
311
|
+
* older browsers (like IE9 or Android < 4.0), don't use this method.
|
|
312
|
+
*
|
|
313
|
+
* @param {any} state State object for pushState or replaceState
|
|
314
|
+
* @return {any} state
|
|
315
|
+
*/
|
|
316
|
+
state(state) {
|
|
317
|
+
if (!arguments.length) {
|
|
318
|
+
return this.$$state;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!(this instanceof LocationHtml5Url) || !this.$$html5) {
|
|
322
|
+
throw $locationMinErr(
|
|
323
|
+
"nostate",
|
|
324
|
+
"History API state support is available only " +
|
|
325
|
+
"in HTML5 mode and only in browsers supporting HTML5 History API",
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
// The user might modify `stateObject` after invoking `$location.state(stateObject)`
|
|
329
|
+
// but we're changing the $$state reference to $browser.state() during the $digest
|
|
330
|
+
// so the modification window is narrow.
|
|
331
|
+
this.$$state = isUndefined(state) ? null : state;
|
|
332
|
+
this.$$urlUpdatedByLocation = true;
|
|
333
|
+
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* This object is exposed as $location service when HTML5 mode is enabled and supported
|
|
340
|
+
*/
|
|
341
|
+
export class LocationHtml5Url extends Location {
|
|
342
|
+
/**
|
|
343
|
+
* @param {string} appBase application base URL
|
|
344
|
+
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
345
|
+
* @param {string} basePrefix URL path prefix
|
|
346
|
+
*/
|
|
347
|
+
constructor(appBase, appBaseNoFile, basePrefix) {
|
|
348
|
+
super(appBase, appBaseNoFile);
|
|
349
|
+
this.$$html5 = true;
|
|
350
|
+
this.basePrefix = basePrefix || "";
|
|
351
|
+
parseAbsoluteUrl(appBase, this);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Parse given HTML5 (regular) URL string into properties
|
|
356
|
+
* @param {string} url HTML5 URL
|
|
357
|
+
*/
|
|
358
|
+
$$parse(url) {
|
|
359
|
+
const pathUrl = stripBaseUrl(this.appBaseNoFile, url);
|
|
360
|
+
if (!isString(pathUrl)) {
|
|
361
|
+
throw $locationMinErr(
|
|
362
|
+
"ipthprfx",
|
|
363
|
+
'Invalid url "{0}", missing path prefix "{1}".',
|
|
364
|
+
url,
|
|
365
|
+
this.appBaseNoFile,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
parseAppUrl(pathUrl, this, true);
|
|
370
|
+
|
|
371
|
+
if (!this.$$path) {
|
|
372
|
+
this.$$path = "/";
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this.$$compose();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
$$normalizeUrl(url) {
|
|
379
|
+
return this.appBaseNoFile + url.substr(1); // first char is always '/'
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
$$parseLinkUrl = function (url, relHref) {
|
|
383
|
+
if (relHref && relHref[0] === "#") {
|
|
384
|
+
// special case for links to hash fragments:
|
|
385
|
+
// keep the old url and only replace the hash fragment
|
|
386
|
+
this.hash(relHref.slice(1));
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
let appUrl;
|
|
390
|
+
let prevAppUrl;
|
|
391
|
+
let rewrittenUrl;
|
|
392
|
+
|
|
393
|
+
if (isDefined((appUrl = stripBaseUrl(this.appBase, url)))) {
|
|
394
|
+
prevAppUrl = appUrl;
|
|
395
|
+
if (
|
|
396
|
+
this.basePrefix &&
|
|
397
|
+
isDefined((appUrl = stripBaseUrl(this.basePrefix, appUrl)))
|
|
398
|
+
) {
|
|
399
|
+
rewrittenUrl =
|
|
400
|
+
this.appBaseNoFile + (stripBaseUrl("/", appUrl) || appUrl);
|
|
401
|
+
} else {
|
|
402
|
+
rewrittenUrl = this.appBase + prevAppUrl;
|
|
403
|
+
}
|
|
404
|
+
} else if (isDefined((appUrl = stripBaseUrl(this.appBaseNoFile, url)))) {
|
|
405
|
+
rewrittenUrl = this.appBaseNoFile + appUrl;
|
|
406
|
+
} else if (this.appBaseNoFile === `${url}/`) {
|
|
407
|
+
rewrittenUrl = this.appBaseNoFile;
|
|
408
|
+
}
|
|
409
|
+
if (rewrittenUrl) {
|
|
410
|
+
this.$$parse(rewrittenUrl);
|
|
411
|
+
}
|
|
412
|
+
return !!rewrittenUrl;
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* LocationHashbangUrl represents URL
|
|
418
|
+
* This object is exposed as $location service when developer doesn't opt into html5 mode.
|
|
419
|
+
* It also serves as the base class for html5 mode fallback on legacy browsers.
|
|
420
|
+
*
|
|
421
|
+
* @constructor
|
|
422
|
+
* @param {string} appBase application base URL
|
|
423
|
+
* @param {string} appBaseNoFile application base URL stripped of any filename
|
|
424
|
+
* @param {string} hashPrefix hashbang prefix
|
|
425
|
+
*/
|
|
426
|
+
export class LocationHashbangUrl extends Location {
|
|
427
|
+
constructor(appBase, appBaseNoFile, hashPrefix) {
|
|
428
|
+
super(appBase, appBaseNoFile);
|
|
429
|
+
this.appBase = appBase;
|
|
430
|
+
this.appBaseNoFile = appBaseNoFile;
|
|
431
|
+
this.hashPrefix = hashPrefix;
|
|
432
|
+
parseAbsoluteUrl(appBase, this);
|
|
433
|
+
}
|
|
609
434
|
|
|
610
435
|
/**
|
|
611
|
-
*
|
|
612
|
-
* @
|
|
613
|
-
*
|
|
614
|
-
* @description
|
|
615
|
-
* This method is getter / setter.
|
|
616
|
-
*
|
|
617
|
-
* Returns the hash fragment when called without any parameters.
|
|
618
|
-
*
|
|
619
|
-
* Changes the hash fragment when called with a parameter and returns `$location`.
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
* ```js
|
|
623
|
-
* // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
|
|
624
|
-
* let hash = $location.hash();
|
|
625
|
-
* // => "hashValue"
|
|
626
|
-
* ```
|
|
627
|
-
*
|
|
628
|
-
* @param {(string|number)=} hash New hash fragment
|
|
629
|
-
* @return {string} hash
|
|
436
|
+
* Parse given hashbang URL into properties
|
|
437
|
+
* @param {string} url Hashbang URL
|
|
630
438
|
*/
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
439
|
+
$$parse(url) {
|
|
440
|
+
const withoutBaseUrl =
|
|
441
|
+
stripBaseUrl(this.appBase, url) || stripBaseUrl(this.appBaseNoFile, url);
|
|
442
|
+
let withoutHashUrl;
|
|
634
443
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
444
|
+
if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === "#") {
|
|
445
|
+
// The rest of the URL starts with a hash so we have
|
|
446
|
+
// got either a hashbang path or a plain hash fragment
|
|
447
|
+
withoutHashUrl = stripBaseUrl(this.hashPrefix, withoutBaseUrl);
|
|
448
|
+
if (isUndefined(withoutHashUrl)) {
|
|
449
|
+
// There was no hashbang prefix so we just have a hash fragment
|
|
450
|
+
withoutHashUrl = withoutBaseUrl;
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
// There was no hashbang path nor hash fragment:
|
|
454
|
+
// If we are in HTML5 mode we use what is left as the path;
|
|
455
|
+
// Otherwise we ignore what is left
|
|
456
|
+
if (this.$$html5) {
|
|
457
|
+
withoutHashUrl = withoutBaseUrl;
|
|
458
|
+
} else {
|
|
459
|
+
withoutHashUrl = "";
|
|
460
|
+
if (isUndefined(withoutBaseUrl)) {
|
|
461
|
+
this.appBase = url;
|
|
462
|
+
/** @type {?} */ (this).replace();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
648
466
|
|
|
649
|
-
|
|
650
|
-
[LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url],
|
|
651
|
-
(Location) => {
|
|
652
|
-
Location.prototype = Object.create(locationPrototype);
|
|
467
|
+
parseAppUrl(withoutHashUrl, this, false);
|
|
653
468
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
469
|
+
this.$$path = removeWindowsDriveName(
|
|
470
|
+
this.$$path,
|
|
471
|
+
withoutHashUrl,
|
|
472
|
+
this.appBase,
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
this.$$compose();
|
|
476
|
+
|
|
477
|
+
/*
|
|
478
|
+
* In Windows, on an anchor node on documents loaded from
|
|
479
|
+
* the filesystem, the browser will return a pathname
|
|
480
|
+
* prefixed with the drive name ('/C:/path') when a
|
|
481
|
+
* pathname without a drive is set:
|
|
482
|
+
* * a.setAttribute('href', '/foo')
|
|
483
|
+
* * a.pathname === '/C:/foo' //true
|
|
669
484
|
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
485
|
+
* Inside of AngularJS, we're always using pathnames that
|
|
486
|
+
* do not include drive names for routing.
|
|
672
487
|
*/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
488
|
+
function removeWindowsDriveName(path, url, base) {
|
|
489
|
+
/*
|
|
490
|
+
Matches paths for file protocol on windows,
|
|
491
|
+
such as /C:/foo/bar, and captures only /foo/bar.
|
|
492
|
+
*/
|
|
493
|
+
const windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
|
|
677
494
|
|
|
678
|
-
|
|
679
|
-
throw $locationMinErr(
|
|
680
|
-
"nostate",
|
|
681
|
-
"History API state support is available only " +
|
|
682
|
-
"in HTML5 mode and only in browsers supporting HTML5 History API",
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
// The user might modify `stateObject` after invoking `$location.state(stateObject)`
|
|
686
|
-
// but we're changing the $$state reference to $browser.state() during the $digest
|
|
687
|
-
// so the modification window is narrow.
|
|
688
|
-
this.$$state = isUndefined(state) ? null : state;
|
|
689
|
-
this.$$urlUpdatedByLocation = true;
|
|
495
|
+
let firstPathSegmentMatch;
|
|
690
496
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
497
|
+
// Get the relative path from the input URL.
|
|
498
|
+
if (startsWith(url, base)) {
|
|
499
|
+
url = url.replace(base, "");
|
|
500
|
+
}
|
|
695
501
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}
|
|
502
|
+
// The input URL intentionally contains a first path segment that ends with a colon.
|
|
503
|
+
if (windowsFilePathExp.exec(url)) {
|
|
504
|
+
return path;
|
|
505
|
+
}
|
|
701
506
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
if (isUndefined(value)) {
|
|
705
|
-
return this[property];
|
|
507
|
+
firstPathSegmentMatch = windowsFilePathExp.exec(path);
|
|
508
|
+
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
|
|
706
509
|
}
|
|
510
|
+
}
|
|
707
511
|
|
|
708
|
-
|
|
709
|
-
this
|
|
512
|
+
$$normalizeUrl(url) {
|
|
513
|
+
return this.appBase + (url ? this.hashPrefix + url : "");
|
|
514
|
+
}
|
|
710
515
|
|
|
711
|
-
|
|
712
|
-
|
|
516
|
+
$$parseLinkUrl(url) {
|
|
517
|
+
if (stripHash(this.appBase) === stripHash(url)) {
|
|
518
|
+
this.$$parse(url);
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
713
523
|
}
|
|
714
524
|
|
|
715
|
-
/**
|
|
716
|
-
* @ngdoc service
|
|
717
|
-
* @name $location
|
|
718
|
-
*
|
|
719
|
-
* @requires $rootElement
|
|
720
|
-
*
|
|
721
|
-
* @description
|
|
722
|
-
* The $location service parses the URL in the browser address bar (based on the
|
|
723
|
-
* [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
|
|
724
|
-
* available to your application. Changes to the URL in the address bar are reflected into
|
|
725
|
-
* $location service and changes to $location are reflected into the browser address bar.
|
|
726
|
-
*
|
|
727
|
-
* **The $location service:**
|
|
728
|
-
*
|
|
729
|
-
* - Exposes the current URL in the browser address bar, so you can
|
|
730
|
-
* - Watch and observe the URL.
|
|
731
|
-
* - Change the URL.
|
|
732
|
-
* - Synchronizes the URL with the browser when the user
|
|
733
|
-
* - Changes the address bar.
|
|
734
|
-
* - Clicks the back or forward button (or clicks a History link).
|
|
735
|
-
* - Clicks on a link.
|
|
736
|
-
* - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
|
|
737
|
-
*
|
|
738
|
-
* For more information see {@link guide/$location Developer Guide: Using $location}
|
|
739
|
-
*/
|
|
740
|
-
|
|
741
|
-
/**
|
|
742
|
-
* @ngdoc provider
|
|
743
|
-
* @name $locationProvider
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
* @description
|
|
747
|
-
* Use the `$locationProvider` to configure how the application deep linking paths are stored.
|
|
748
|
-
*/
|
|
749
525
|
export function $LocationProvider() {
|
|
750
526
|
let hashPrefix = "!";
|
|
751
527
|
const html5Mode = {
|
|
@@ -755,9 +531,6 @@ export function $LocationProvider() {
|
|
|
755
531
|
};
|
|
756
532
|
|
|
757
533
|
/**
|
|
758
|
-
* @ngdoc method
|
|
759
|
-
* @name $locationProvider#hashPrefix
|
|
760
|
-
* @description
|
|
761
534
|
* The default value for the prefix is `'!'`.
|
|
762
535
|
* @param {string=} prefix Prefix for hash part (containing path and search)
|
|
763
536
|
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
|
@@ -771,9 +544,6 @@ export function $LocationProvider() {
|
|
|
771
544
|
};
|
|
772
545
|
|
|
773
546
|
/**
|
|
774
|
-
* @ngdoc method
|
|
775
|
-
* @name $locationProvider#html5Mode
|
|
776
|
-
* @description
|
|
777
547
|
* @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
|
|
778
548
|
* If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
|
|
779
549
|
* properties:
|
|
@@ -816,57 +586,19 @@ export function $LocationProvider() {
|
|
|
816
586
|
return html5Mode;
|
|
817
587
|
};
|
|
818
588
|
|
|
819
|
-
/**
|
|
820
|
-
* @ngdoc event
|
|
821
|
-
* @name $location#$locationChangeStart
|
|
822
|
-
* @eventType broadcast on root scope
|
|
823
|
-
* @description
|
|
824
|
-
* Broadcasted before a URL will change.
|
|
825
|
-
*
|
|
826
|
-
* This change can be prevented by calling
|
|
827
|
-
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
|
|
828
|
-
* details about event object. Upon successful change
|
|
829
|
-
* {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
|
|
830
|
-
*
|
|
831
|
-
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
|
|
832
|
-
* the browser supports the HTML5 History API.
|
|
833
|
-
*
|
|
834
|
-
* @param {Object} angularEvent Synthetic event object.
|
|
835
|
-
* @param {string} newUrl New URL
|
|
836
|
-
* @param {string=} oldUrl URL that was before it was changed.
|
|
837
|
-
* @param {string=} newState New history state object
|
|
838
|
-
* @param {string=} oldState History state object that was before it was changed.
|
|
839
|
-
*/
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* @ngdoc event
|
|
843
|
-
* @name $location#$locationChangeSuccess
|
|
844
|
-
* @eventType broadcast on root scope
|
|
845
|
-
* @description
|
|
846
|
-
* Broadcasted after a URL was changed.
|
|
847
|
-
*
|
|
848
|
-
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
|
|
849
|
-
* the browser supports the HTML5 History API.
|
|
850
|
-
*
|
|
851
|
-
* @param {Object} angularEvent Synthetic event object.
|
|
852
|
-
* @param {string} newUrl New URL
|
|
853
|
-
* @param {string=} oldUrl URL that was before it was changed.
|
|
854
|
-
* @param {string=} newState New history state object
|
|
855
|
-
* @param {string=} oldState History state object that was before it was changed.
|
|
856
|
-
*/
|
|
857
|
-
|
|
858
589
|
this.$get = [
|
|
859
590
|
"$rootScope",
|
|
860
591
|
"$browser",
|
|
861
592
|
"$rootElement",
|
|
862
593
|
/**
|
|
863
594
|
*
|
|
864
|
-
* @param {
|
|
865
|
-
* @param {
|
|
595
|
+
* @param {import('../scope/scope').Scope} $rootScope
|
|
596
|
+
* @param {import('../../services/browser').Browser} $browser
|
|
866
597
|
* @param {JQLite} $rootElement
|
|
867
598
|
* @returns
|
|
868
599
|
*/
|
|
869
600
|
function ($rootScope, $browser, $rootElement) {
|
|
601
|
+
/** @type {Location} */
|
|
870
602
|
let $location;
|
|
871
603
|
let LocationMode;
|
|
872
604
|
const baseHref = $browser.baseHref(); // if base[href] is undefined, it defaults to ''
|
|
@@ -895,13 +627,6 @@ export function $LocationProvider() {
|
|
|
895
627
|
|
|
896
628
|
const IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
|
|
897
629
|
|
|
898
|
-
// Determine if two URLs are equal despite potentially having different encoding/normalizing
|
|
899
|
-
// such as $location.absUrl() vs $browser.url()
|
|
900
|
-
// See https://github.com/angular/angular.js/issues/16592
|
|
901
|
-
function urlsEqual(a, b) {
|
|
902
|
-
return a === b || urlResolve(a).href === urlResolve(b).href;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
630
|
function setBrowserUrlWithFallback(url, replace, state) {
|
|
906
631
|
const oldUrl = $location.url();
|
|
907
632
|
const oldState = $location.$$state;
|
|
@@ -1029,7 +754,7 @@ export function $LocationProvider() {
|
|
|
1029
754
|
if (initializing || $location.$$urlUpdatedByLocation) {
|
|
1030
755
|
$location.$$urlUpdatedByLocation = false;
|
|
1031
756
|
|
|
1032
|
-
const oldUrl = $browser.url();
|
|
757
|
+
const oldUrl = /** @type {string} */ ($browser.url());
|
|
1033
758
|
const newUrl = $location.absUrl();
|
|
1034
759
|
const oldState = $browser.state();
|
|
1035
760
|
const currentReplace = $location.$$replace;
|
|
@@ -1091,3 +816,125 @@ export function $LocationProvider() {
|
|
|
1091
816
|
},
|
|
1092
817
|
];
|
|
1093
818
|
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* ///////////////////////////
|
|
822
|
+
* HELPERS
|
|
823
|
+
* ///////////////////////////
|
|
824
|
+
*/
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Encode path using encodeUriSegment, ignoring forward slashes
|
|
828
|
+
*
|
|
829
|
+
* @param {string} path Path to encode
|
|
830
|
+
* @returns {string}
|
|
831
|
+
*/
|
|
832
|
+
function encodePath(path) {
|
|
833
|
+
const segments = path.split("/");
|
|
834
|
+
let i = segments.length;
|
|
835
|
+
|
|
836
|
+
while (i--) {
|
|
837
|
+
// decode forward slashes to prevent them from being double encoded
|
|
838
|
+
segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, "/"));
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return segments.join("/");
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function decodePath(path, html5Mode) {
|
|
845
|
+
const segments = path.split("/");
|
|
846
|
+
let i = segments.length;
|
|
847
|
+
|
|
848
|
+
while (i--) {
|
|
849
|
+
segments[i] = decodeURIComponent(segments[i]);
|
|
850
|
+
if (html5Mode) {
|
|
851
|
+
// encode forward slashes to prevent them from being mistaken for path separators
|
|
852
|
+
segments[i] = segments[i].replace(/\//g, "%2F");
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return segments.join("/");
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function normalizePath(pathValue, searchValue, hashValue) {
|
|
860
|
+
const search = toKeyValue(searchValue);
|
|
861
|
+
const hash = hashValue ? `#${encodeUriSegment(hashValue)}` : "";
|
|
862
|
+
const path = encodePath(pathValue);
|
|
863
|
+
|
|
864
|
+
return path + (search ? `?${search}` : "") + hash;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* @param {string} absoluteUrl
|
|
869
|
+
* @param {Location} locationObj
|
|
870
|
+
*/
|
|
871
|
+
function parseAbsoluteUrl(absoluteUrl, locationObj) {
|
|
872
|
+
const parsedUrl = urlResolve(absoluteUrl);
|
|
873
|
+
|
|
874
|
+
locationObj.$$protocol = parsedUrl.protocol;
|
|
875
|
+
locationObj.$$host = parsedUrl.hostname;
|
|
876
|
+
locationObj.$$port =
|
|
877
|
+
toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
function parseAppUrl(url, locationObj, html5Mode) {
|
|
881
|
+
if (/^\s*[\\/]{2,}/.test(url)) {
|
|
882
|
+
throw $locationMinErr("badpath", 'Invalid url "{0}".', url);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const prefixed = url.charAt(0) !== "/";
|
|
886
|
+
if (prefixed) {
|
|
887
|
+
url = `/${url}`;
|
|
888
|
+
}
|
|
889
|
+
const match = urlResolve(url);
|
|
890
|
+
const path =
|
|
891
|
+
prefixed && match.pathname.charAt(0) === "/"
|
|
892
|
+
? match.pathname.substring(1)
|
|
893
|
+
: match.pathname;
|
|
894
|
+
locationObj.$$path = decodePath(path, html5Mode);
|
|
895
|
+
locationObj.$$search = parseKeyValue(match.search);
|
|
896
|
+
locationObj.$$hash = decodeURIComponent(match.hash);
|
|
897
|
+
|
|
898
|
+
// make sure path starts with '/';
|
|
899
|
+
if (locationObj.$$path && locationObj.$$path.charAt(0) !== "/") {
|
|
900
|
+
locationObj.$$path = `/${locationObj.$$path}`;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
function startsWith(str, search) {
|
|
905
|
+
return str.slice(0, search.length) === search;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
*
|
|
910
|
+
* @param {string} base
|
|
911
|
+
* @param {string} url
|
|
912
|
+
* @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
|
|
913
|
+
* the expected string.
|
|
914
|
+
*/
|
|
915
|
+
export function stripBaseUrl(base, url) {
|
|
916
|
+
if (startsWith(url, base)) {
|
|
917
|
+
return url.substr(base.length);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
export function stripHash(url) {
|
|
922
|
+
const index = url.indexOf("#");
|
|
923
|
+
return index === -1 ? url : url.substr(0, index);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
export function stripFile(url) {
|
|
927
|
+
return url.substr(0, stripHash(url).lastIndexOf("/") + 1);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* return the server only (scheme://host:port) */
|
|
931
|
+
export function serverBase(url) {
|
|
932
|
+
return url.substring(0, url.indexOf("/", url.indexOf("//") + 2));
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Determine if two URLs are equal despite potentially having different encoding/normalizing
|
|
936
|
+
// such as $location.absUrl() vs $browser.url()
|
|
937
|
+
// See https://github.com/angular/angular.js/issues/16592
|
|
938
|
+
function urlsEqual(a, b) {
|
|
939
|
+
return a === b || urlResolve(a).href === urlResolve(b).href;
|
|
940
|
+
}
|