@angular-wave/angular.ts 0.7.8 → 0.8.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.
Files changed (308) hide show
  1. package/@types/{loader.d.ts → angular.d.ts} +3 -3
  2. package/@types/core/di/ng-module.d.ts +61 -25
  3. package/@types/core/parse/parse.d.ts +6 -7
  4. package/@types/directive/bind/bind.d.ts +2 -1
  5. package/@types/index.d.ts +1 -1
  6. package/@types/interface.d.ts +4 -2
  7. package/@types/{public.d.ts → ng.d.ts} +2 -2
  8. package/@types/router/directives/state-directives.d.ts +2 -2
  9. package/@types/router/directives/view-directive.d.ts +1 -1
  10. package/@types/router/params/param-type.d.ts +0 -1
  11. package/@types/router/path/path-utils.d.ts +8 -11
  12. package/@types/router/{globals.d.ts → router.d.ts} +2 -2
  13. package/@types/router/state/interface.d.ts +1 -1
  14. package/@types/router/state/state-object.d.ts +1 -1
  15. package/@types/router/state/state-registry.d.ts +2 -2
  16. package/@types/router/state/state-service.d.ts +14 -16
  17. package/@types/router/state-filters.d.ts +24 -2
  18. package/@types/router/transition/transition-service.d.ts +3 -3
  19. package/@types/router/transition/transition.d.ts +16 -19
  20. package/@types/router/url/url-matcher.d.ts +3 -4
  21. package/@types/router/url/url-rule.d.ts +14 -4
  22. package/@types/router/url/url-rules.d.ts +26 -6
  23. package/@types/router/url/url-service.d.ts +28 -38
  24. package/@types/services/http/http.d.ts +48 -1
  25. package/@types/services/http-backend/http-backend.d.ts +48 -35
  26. package/@types/services/location/interface.d.ts +55 -0
  27. package/@types/services/location/location.d.ts +225 -252
  28. package/@types/shared/common.d.ts +0 -2
  29. package/@types/shared/hof.d.ts +0 -6
  30. package/@types/shared/interface.d.ts +0 -4
  31. package/@types/{router/common → shared}/queue.d.ts +2 -2
  32. package/@types/shared/url-utils/interface.d.ts +0 -1
  33. package/@types/shared/url-utils/url-utils.d.ts +0 -5
  34. package/@types/shared/utils.d.ts +29 -6
  35. package/CHANGELOG.md +0 -72
  36. package/CONTRIBUTING.md +0 -1
  37. package/DEVELOPERS.md +0 -1
  38. package/Makefile +6 -3
  39. package/TRIAGING.md +0 -1
  40. package/dist/angular-ts.esm.js +1048 -1150
  41. package/dist/angular-ts.umd.js +1048 -1150
  42. package/dist/angular-ts.umd.min.js +1 -1
  43. package/docs/assets/scss/index.scss +23 -0
  44. package/docs/content/_index.md +9 -8
  45. package/docs/content/docs/_index.md +1 -1
  46. package/docs/content/docs/directive/app.md +1 -1
  47. package/docs/content/docs/directive/bind.md +1 -1
  48. package/docs/content/docs/directive/blur.md +1 -1
  49. package/docs/content/docs/directive/channel.md +2 -2
  50. package/docs/content/docs/directive/class-even.md +1 -1
  51. package/docs/content/docs/directive/class-odd.md +1 -1
  52. package/docs/content/docs/directive/class.md +1 -1
  53. package/docs/content/docs/directive/click.md +1 -1
  54. package/docs/content/docs/directive/copy.md +1 -1
  55. package/docs/content/docs/directive/cut.md +1 -1
  56. package/docs/content/docs/directive/dblclick.md +1 -1
  57. package/docs/content/docs/directive/focus.md +1 -1
  58. package/docs/content/docs/directive/get.md +3 -3
  59. package/docs/content/docs/directive/keydown.md +1 -1
  60. package/docs/content/docs/directive/keyup.md +1 -1
  61. package/docs/content/docs/directive/load.md +1 -1
  62. package/docs/content/docs/directive/mousedown.md +1 -1
  63. package/docs/content/docs/directive/mouseenter.md +1 -1
  64. package/docs/content/docs/directive/mouseleave.md +1 -1
  65. package/docs/content/docs/directive/mousemove.md +1 -1
  66. package/docs/content/docs/directive/mouseout.md +1 -1
  67. package/docs/content/docs/directive/mouseover.md +1 -1
  68. package/docs/content/docs/directive/mouseup.md +1 -1
  69. package/docs/content/docs/directive/non-bindable.md +28 -0
  70. package/docs/content/docs/provider/locationProvider.md +26 -0
  71. package/docs/content/docs/provider/templateCacheProvider.md +2 -2
  72. package/docs/content/docs/service/location.md +57 -0
  73. package/docs/content/docs/service/url.md +5 -0
  74. package/docs/layouts/partials/hooks/head-end.html +1 -1
  75. package/docs/layouts/shortcodes/version.html +1 -0
  76. package/docs/static/examples/counter/counter-test.html +0 -4
  77. package/docs/static/examples/eventbus/eventbus-test.html +0 -4
  78. package/docs/static/examples/ng-non-bindable/ng-non-bindable-test.html +13 -0
  79. package/docs/static/examples/ng-non-bindable/ng-non-bindable.html +3 -0
  80. package/docs/static/examples/ng-non-bindable/ng-non-bindable.test.js +11 -0
  81. package/docs/static/typedoc/assets/hierarchy.js +1 -1
  82. package/docs/static/typedoc/assets/highlight.css +6 -6
  83. package/docs/static/typedoc/assets/navigation.js +1 -1
  84. package/docs/static/typedoc/assets/search.js +1 -1
  85. package/docs/static/typedoc/classes/Location.html +55 -0
  86. package/docs/static/typedoc/classes/LocationProvider.html +20 -0
  87. package/docs/static/typedoc/classes/NgModule.html +3 -3
  88. package/docs/static/typedoc/index.html +1 -1
  89. package/docs/static/typedoc/interfaces/DefaultPorts.html +5 -0
  90. package/docs/static/typedoc/interfaces/Html5Mode.html +23 -0
  91. package/docs/static/typedoc/interfaces/Provider.html +2 -1
  92. package/docs/static/typedoc/interfaces/UrlParts.html +9 -0
  93. package/docs/static/typedoc/types/AnnotatedFactory.html +1 -1
  94. package/docs/static/typedoc/types/Expression.html +1 -1
  95. package/docs/static/typedoc/types/Injectable.html +4 -1
  96. package/docs/static/typedoc/types/InjectableFactory.html +1 -4
  97. package/docs/static/typedoc/types/UrlChangeListener.html +5 -0
  98. package/docs/static/version.js +13 -0
  99. package/docs/test-results/.last-run.json +4 -0
  100. package/docs/test-results/static-examples-counter-counter-counter-example/error-context.md +50 -0
  101. package/package.json +2 -2
  102. package/src/{loader.js → angular.js} +11 -11
  103. package/src/angular.spec.js +189 -21
  104. package/src/animations/animate-css.js +17 -18
  105. package/src/animations/animate.spec.js +1 -1
  106. package/src/animations/shared.js +2 -3
  107. package/src/binding.spec.js +1 -1
  108. package/src/core/compile/compile.js +4 -7
  109. package/src/core/compile/compile.spec.js +1 -1
  110. package/src/core/controller/controller.spec.js +1 -1
  111. package/src/core/controller/controller.test.js +1 -0
  112. package/src/core/di/injector.js +7 -8
  113. package/src/core/di/injector.spec.js +2 -2
  114. package/src/core/di/injector.test.js +2 -2
  115. package/src/core/di/internal-injector.js +3 -6
  116. package/src/core/di/ng-module.js +26 -21
  117. package/src/core/filter/filter.js +1 -1
  118. package/src/core/filter/filter.spec.js +1 -1
  119. package/src/core/filter/filter.test.js +1 -0
  120. package/src/core/interpolate/interpolate.js +4 -6
  121. package/src/core/interpolate/interpolate.spec.js +1 -1
  122. package/src/core/interpolate/interpolate.test.js +1 -0
  123. package/src/core/parse/ast/ast.spec.js +1 -1
  124. package/src/core/parse/ast/ast.test.js +1 -1
  125. package/src/core/parse/lexer/lexer.spec.js +1 -1
  126. package/src/core/parse/parse.js +150 -146
  127. package/src/core/parse/parse.spec.js +46 -46
  128. package/src/core/prop.spec.js +1 -1
  129. package/src/core/root-element.spec.js +1 -1
  130. package/src/core/scope/scope.js +10 -11
  131. package/src/core/scope/scope.spec.js +3 -4
  132. package/src/directive/aria/aria.spec.js +1 -1
  133. package/src/directive/aria/aria.test.js +1 -0
  134. package/src/directive/attrs/attrs.spec.js +1 -1
  135. package/src/directive/attrs/attrs.test.js +1 -0
  136. package/src/directive/attrs/boolean.spec.js +1 -1
  137. package/src/directive/attrs/boolean.test.js +1 -0
  138. package/src/directive/attrs/element-style.spec.js +1 -1
  139. package/src/directive/attrs/element-style.test.js +1 -0
  140. package/src/directive/attrs/src.spec.js +1 -1
  141. package/src/directive/attrs/src.test.js +1 -0
  142. package/src/directive/bind/bind-html.spec.js +1 -1
  143. package/src/directive/bind/bind.js +1 -0
  144. package/src/directive/bind/bind.spec.js +1 -1
  145. package/src/directive/bind/bind.test.js +1 -0
  146. package/src/directive/channel/channel.spec.js +1 -1
  147. package/src/directive/channel/channel.test.js +1 -0
  148. package/src/directive/class/class.spec.js +1 -1
  149. package/src/directive/class/class.test.js +1 -0
  150. package/src/directive/cloak/cloak.spec.js +1 -1
  151. package/src/directive/cloak/cloak.test.js +1 -0
  152. package/src/directive/controller/controller.spec.js +1 -1
  153. package/src/directive/controller/controller.test.js +1 -0
  154. package/src/directive/events/click.spec.js +1 -1
  155. package/src/directive/events/event.spec.js +6 -6
  156. package/src/directive/events/events.test.js +1 -0
  157. package/src/directive/form/form.js +8 -5
  158. package/src/directive/form/form.spec.js +1 -1
  159. package/src/directive/form/form.test.js +1 -0
  160. package/src/directive/http/delete.spec.js +1 -1
  161. package/src/directive/http/form-test.html +18 -0
  162. package/src/directive/http/get.spec.js +1 -1
  163. package/src/directive/http/http.js +12 -3
  164. package/src/directive/http/post.spec.js +504 -9
  165. package/src/directive/http/put.spec.js +1 -1
  166. package/src/directive/if/if.spec.js +1 -1
  167. package/src/directive/include/include.spec.js +1 -1
  168. package/src/directive/init/init.spec.js +1 -1
  169. package/src/directive/init/init.test.js +1 -0
  170. package/src/directive/input/input.js +13 -15
  171. package/src/directive/input/input.spec.js +1 -2
  172. package/src/directive/input/input.test.js +1 -0
  173. package/src/directive/messages/messages.md +0 -4
  174. package/src/directive/messages/messages.spec.js +1 -1
  175. package/src/directive/messages/messages.test.js +1 -0
  176. package/src/directive/model/model.js +13 -13
  177. package/src/directive/model/model.spec.js +1 -1
  178. package/src/directive/model/model.test.js +1 -0
  179. package/src/directive/model-options/model-option.test.js +1 -0
  180. package/src/directive/model-options/model-options.js +1 -1
  181. package/src/directive/model-options/model-options.spec.js +1 -1
  182. package/src/directive/non-bindable/non-bindable.spec.js +1 -1
  183. package/src/directive/non-bindable/non-bindable.test.js +1 -0
  184. package/src/directive/observe/observe.spec.js +1 -1
  185. package/src/directive/observe/observe.test.js +1 -0
  186. package/src/directive/on/on.spec.js +1 -1
  187. package/src/directive/on/on.test.js +1 -0
  188. package/src/directive/options/options.spec.js +1 -1
  189. package/src/directive/options/options.test.js +1 -0
  190. package/src/directive/ref/href.spec.js +1 -1
  191. package/src/directive/ref/href.test.js +2 -0
  192. package/src/directive/ref/ref.spec.js +1 -1
  193. package/src/directive/repeat/repeat.js +1 -1
  194. package/src/directive/repeat/repeat.spec.js +2 -3
  195. package/src/directive/repeat/repeat.test.js +1 -0
  196. package/src/directive/script/script.spec.js +1 -1
  197. package/src/directive/script/script.test.js +1 -0
  198. package/src/directive/select/select.js +1 -1
  199. package/src/directive/select/select.spec.js +1 -1
  200. package/src/directive/select/select.test.js +1 -0
  201. package/src/directive/setter/setter.spec.js +1 -1
  202. package/src/directive/setter/setter.test.js +1 -0
  203. package/src/directive/show-hide/show-hide.spec.js +1 -1
  204. package/src/directive/show-hide/show-hide.test.js +1 -0
  205. package/src/directive/style/style.spec.js +1 -1
  206. package/src/directive/style/style.test.js +1 -0
  207. package/src/directive/switch/switch.spec.js +1 -1
  208. package/src/directive/switch/switch.test.js +1 -0
  209. package/src/directive/validators/validators.js +82 -84
  210. package/src/directive/validators/validators.spec.js +5 -4
  211. package/src/directive/validators/validators.test.js +1 -0
  212. package/src/filters/filter.spec.js +1 -1
  213. package/src/filters/filters.spec.js +1 -1
  214. package/src/filters/limit-to.js +2 -3
  215. package/src/filters/limit-to.spec.js +1 -1
  216. package/src/filters/order-by.spec.js +1 -1
  217. package/src/index.js +1 -1
  218. package/src/injection-tokens.js +7 -3
  219. package/src/interface.ts +4 -3
  220. package/src/loader.md +0 -155
  221. package/src/{public.js → ng.js} +11 -12
  222. package/src/{public.spec.js → ng.spec.js} +2 -2
  223. package/src/router/directives/state-directives.js +5 -5
  224. package/src/router/directives/state-directives.spec.js +8 -7
  225. package/src/router/directives/view-directive.js +7 -13
  226. package/src/router/directives/view-directive.spec.js +22 -23
  227. package/src/router/{common/common.html → glob/glob.html} +2 -3
  228. package/src/router/{common/common.test.js → glob/glob.test.js} +2 -1
  229. package/src/router/params/param-type.js +0 -1
  230. package/src/router/params/param.js +1 -1
  231. package/src/router/path/path-utils.js +5 -0
  232. package/src/router/router-test-hashbang.html +45 -0
  233. package/src/router/{globals.js → router.js} +2 -2
  234. package/src/router/services.spec.js +8 -9
  235. package/src/router/state/interface.ts +1 -1
  236. package/src/router/state/state-builder.js +3 -3
  237. package/src/router/state/state-builder.spec.js +1 -1
  238. package/src/router/state/state-object.js +1 -1
  239. package/src/router/state/state-registry.js +4 -4
  240. package/src/router/state/state-service.js +14 -14
  241. package/src/router/state/state.spec.js +23 -22
  242. package/src/router/state/state.test.js +1 -0
  243. package/src/router/state/views.js +1 -1
  244. package/src/router/state-filter.spec.js +1 -1
  245. package/src/router/state-filters.js +13 -9
  246. package/src/router/template-factory.js +5 -4
  247. package/src/router/template-factory.spec.js +7 -7
  248. package/src/router/transition/hook-registry.js +1 -1
  249. package/src/router/transition/transition-service.js +7 -6
  250. package/src/router/transition/transition.js +6 -6
  251. package/src/router/url/url-matcher.js +12 -14
  252. package/src/router/url/url-rule.js +8 -2
  253. package/src/router/url/url-rules.js +8 -5
  254. package/src/router/url/url-service.js +80 -76
  255. package/src/router/url/url-service.spec.js +61 -78
  256. package/src/router/url/url.test.js +1 -0
  257. package/src/router/view/view.js +4 -5
  258. package/src/router/view/view.spec.js +10 -12
  259. package/src/router/view/view.test.js +1 -0
  260. package/src/router/view-hook.spec.js +1 -1
  261. package/src/router/view-scroll.js +3 -1
  262. package/src/router/view-scroll.spec.js +12 -12
  263. package/src/services/anchor-scroll.html +2 -2
  264. package/src/services/anchor-scroll.js +5 -4
  265. package/src/services/http/http.js +9 -4
  266. package/src/services/http/http.spec.js +2 -7
  267. package/src/services/http/template-request.spec.js +1 -1
  268. package/src/services/http-backend/http-backend.js +51 -77
  269. package/src/services/http-backend/http-backend.spec.js +1 -2
  270. package/src/services/http-backend/http-backend.test.js +1 -0
  271. package/src/services/location/interface.ts +62 -0
  272. package/src/services/location/location.js +439 -519
  273. package/src/services/location/location.spec.js +915 -530
  274. package/src/services/location/location.test.js +2 -2
  275. package/src/services/log/log.spec.js +1 -1
  276. package/src/services/log/log.test.js +1 -0
  277. package/src/services/pubsub/pubsub.spec.js +1 -1
  278. package/src/services/sce/sce.js +5 -7
  279. package/src/services/sce/sce.md +2 -2
  280. package/src/services/sce/sce.spec.js +1 -1
  281. package/src/services/template-cache/template-cache.spec.js +1 -1
  282. package/src/services/template-cache/template-cache.test.js +1 -0
  283. package/src/shared/common.js +5 -10
  284. package/src/shared/common.spec.js +1 -1
  285. package/src/shared/hof.js +0 -14
  286. package/src/shared/interface.ts +0 -4
  287. package/src/{router/common → shared}/queue.js +7 -7
  288. package/src/shared/shared.html +1 -0
  289. package/src/shared/shared.test.js +1 -0
  290. package/src/shared/url-utils/interface.ts +0 -2
  291. package/src/shared/url-utils/url-utils.js +6 -30
  292. package/src/shared/url-utils/url-utils.spec.js +10 -9
  293. package/src/shared/utils.js +32 -9
  294. package/src/shared/utils.spec.js +35 -1
  295. package/src/src.html +1 -2
  296. package/typedoc.json +0 -1
  297. package/utils/express.js +27 -1
  298. package/utils/version.cjs +23 -0
  299. package/@types/router/state-provider.d.ts +0 -123
  300. package/src/directive/non-bindable/non-bindable.md +0 -17
  301. package/src/loader.spec.js +0 -169
  302. package/src/router/state-provider.js +0 -146
  303. package/src/services/location/location.md +0 -114
  304. package/src/shared/url-utils/url-utils.md +0 -46
  305. /package/@types/router/{common → glob}/glob.d.ts +0 -0
  306. /package/src/router/{common → glob}/glob.js +0 -0
  307. /package/src/router/{common → glob}/glob.spec.js +0 -0
  308. /package/src/{router/common → shared}/queue.spec.js +0 -0
@@ -1,7 +1,6 @@
1
1
  import { trimEmptyHash, urlResolve } from "../../shared/url-utils/url-utils.js";
2
2
  import {
3
3
  encodeUriSegment,
4
- isBoolean,
5
4
  isDefined,
6
5
  isNumber,
7
6
  isObject,
@@ -9,263 +8,168 @@ import {
9
8
  isUndefined,
10
9
  minErr,
11
10
  parseKeyValue,
12
- toInt,
13
11
  toKeyValue,
14
12
  equals,
13
+ startsWith,
15
14
  } from "../../shared/utils.js";
16
15
  import { getBaseHref } from "../../shared/dom.js";
16
+ import { $injectTokens as $t } from "../../injection-tokens.js";
17
+
18
+ const PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
19
+ const $locationMinErr = minErr("$location");
20
+
21
+ let urlUpdatedByLocation = false;
17
22
 
18
23
  /**
19
- * @typedef {Object} DefaultPorts
20
- * @property {number} http
21
- * @property {number} https
22
- * @property {number} ftp
24
+ * @ignore
25
+ * The pathname, beginning with "/"
26
+ * @type {string}
23
27
  */
28
+ let $$path;
24
29
 
25
30
  /**
26
- * Represents the configuration options for HTML5 mode.
27
- *
28
- * @typedef {Object} Html5Mode
29
- * @property {boolean} enabled - (default: false) If true, will rely on `history.pushState` to
30
- * change URLs where supported. Falls back to hash-prefixed paths in browsers that do not
31
- * support `pushState`.
32
- * @property {boolean} requireBase - (default: `true`) When html5Mode is enabled, specifies
33
- * whether or not a `<base>` tag is required to be present. If both `enabled` and `requireBase`
34
- * are true, and a `<base>` tag is not present, an error will be thrown when `$location` is injected.
35
- * See the {@link guide/$location $location guide} for more information.
36
- * @property {boolean|string} rewriteLinks - (default: `true`) When html5Mode is enabled, enables or
37
- * disables URL rewriting for relative links. If set to a string, URL rewriting will only apply to links
38
- * with an attribute that matches the given string. For example, if set to `'internal-link'`, URL rewriting
39
- * will only occur for `<a internal-link>` links. Note that [attribute name normalization](guide/directive#normalization)
40
- * does not apply here, so `'internalLink'` will **not** match `'internal-link'`.
31
+ * @type {Object.<string,boolean|Array>}
41
32
  */
42
-
43
- /** @type {DefaultPorts} */
44
- const DEFAULT_PORTS = { http: 80, https: 443, ftp: 21 };
45
- const PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
46
- const $locationMinErr = minErr("$location");
33
+ let $$search;
47
34
 
48
35
  /**
49
- * @abstract
36
+ * @ignore
37
+ * The hash string, minus the hash symbol
38
+ * @type {string}
50
39
  */
40
+ let $$hash;
41
+
51
42
  export class Location {
52
43
  /**
53
44
  * @param {string} appBase application base URL
54
45
  * @param {string} appBaseNoFile application base URL stripped of any filename
46
+ * @param {boolean} [html5] Defaults to true
47
+ * @param {string} [prefix] URL path prefix for html5 mode or hash prefix for hashbang mode
55
48
  */
56
- constructor(appBase, appBaseNoFile) {
57
- const parsedUrl = urlResolve(appBase);
58
-
49
+ constructor(appBase, appBaseNoFile, html5 = true, prefix) {
59
50
  /** @type {string} */
60
51
  this.appBase = appBase;
61
52
 
62
53
  /** @type {string} */
63
54
  this.appBaseNoFile = appBaseNoFile;
64
55
 
65
- /**
66
- * 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).
67
- * @type {string}
68
- */
69
- this.$$absUrl = "";
56
+ /** @type {boolean} */
57
+ this.html5 = html5;
70
58
 
71
- /**
72
- * If html5 mode is enabled
73
- * @type {boolean}
74
- */
75
- this.$$html5 = false;
59
+ /** @type {string | undefined} */
60
+ this.basePrefix = html5 ? prefix || "" : undefined;
76
61
 
77
- /**
78
- * Has any change been replacing?
79
- * @type {boolean}
80
- */
81
- this.$$replace = false;
82
-
83
- /** @type {string} */
84
- this.$$protocol = parsedUrl.protocol;
85
-
86
- /** @type {string} */
87
- this.$$host = parsedUrl.hostname;
88
-
89
- /**
90
- * The port, without ":"
91
- * @type {number}
92
- */
93
- this.$$port =
94
- toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
62
+ /** @type {string | undefined} */
63
+ this.hashPrefix = html5 ? undefined : prefix;
95
64
 
96
65
  /**
97
- * The pathname, beginning with "/"
66
+ * 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)
67
+ * with all segments encoded according to rules specified in [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
98
68
  * @type {string}
99
69
  */
100
- this.$$path = undefined;
70
+ this.absUrl = "";
101
71
 
102
72
  /**
103
- * The hash string, minus the hash symbol
73
+ * @ignore
74
+ * Current url
104
75
  * @type {string}
105
76
  */
106
- this.$$hash = undefined;
77
+ this.$$url = undefined;
107
78
 
108
79
  /**
109
- * Helper property for scope watch changes
110
- * @type {boolean}
80
+ * @ignore
81
+ * Callback to update browser url
82
+ * @type {Function}
111
83
  */
112
- this.$$urlUpdatedByLocation = false;
84
+ this.$$updateBrowser = undefined;
113
85
  }
114
86
 
115
87
  /**
116
- * Return full URL representation with all segments encoded according to rules specified in
117
- * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
118
- *
119
- * @return {string} full URL
120
- */
121
- absUrl() {
122
- return this.$$absUrl;
123
- }
124
-
125
- /**
126
- * This method is getter / setter.
127
- *
128
- * Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
129
88
  * Change path, search and hash, when called with parameter and return `$location`.
130
89
  *
131
- * @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`)
132
- * @return {Location|string} url
90
+ * @param {string} url New URL without base prefix (e.g. `/path?a=b#hash`)
91
+ * @return {Location} url
133
92
  */
134
- url(url) {
135
- if (isUndefined(url)) {
136
- return this.$$url;
93
+ setUrl(url) {
94
+ const match = PATH_MATCH.exec(url);
95
+
96
+ if (match[1] !== undefined || url === "") {
97
+ this.setPath(match[1] || "");
137
98
  }
138
99
 
139
- const match = PATH_MATCH.exec(url);
140
- if (match[1] || url === "") this.path(decodeURIComponent(match[1]));
141
- if (match[2] || match[1] || url === "") this.search(match[3] || "");
142
- this.hash(match[5] || "");
100
+ if (match[2] !== undefined || match[1] !== undefined || url === "") {
101
+ this.setSearch(match[3] || "");
102
+ }
103
+
104
+ this.setHash(match[5] || "");
143
105
 
144
106
  return this;
145
107
  }
146
108
 
147
109
  /**
110
+ * Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
148
111
  *
149
- * Return protocol of current URL.
150
- * @return {string} protocol of current URL
112
+ * @return {string} url
151
113
  */
152
- protocol() {
153
- return this.$$protocol;
114
+ getUrl() {
115
+ return this.$$url;
154
116
  }
155
117
 
156
118
  /**
157
- * This method is getter only.
158
- *
159
- * Return host of current URL.
119
+ * Change path parameter and return `$location`.
160
120
  *
161
- * Note: compared to the non-AngularTS version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
162
- *
163
- *
164
- * @return {string} host of current URL.
121
+ * @param {(string|number)} path New path
122
+ * @return {Location}
165
123
  */
166
- host() {
167
- return this.$$host;
168
- }
169
-
170
- /**
171
- * This method is getter only.
172
- *
173
- * Return port of current URL.
174
- *
175
- *
176
- * ```js
177
- * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
178
- * let port = $location.port();
179
- * // => 80
180
- * ```
181
- *
182
- * @return {number} port
183
- */
184
- port() {
185
- return this.$$port;
124
+ setPath(path) {
125
+ let newPath = path !== null ? path.toString() : "";
126
+ $$path = newPath.charAt(0) === "/" ? newPath : `/${newPath}`;
127
+ this.$$compose();
128
+ return this;
186
129
  }
187
130
 
188
131
  /**
189
- * This method is getter / setter.
190
- *
191
- * Return path of current URL when called without any parameter.
192
- *
193
- * Change path when called with parameter and return `$location`.
194
- *
195
- * Note: Path should always begin with forward slash (/), this method will add the forward slash
196
- * if it is missing.
197
132
  *
133
+ * Return path of current URL
198
134
  *
199
- * ```js
200
- * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
201
- * let path = $location.path();
202
- * // => "/some/path"
203
- * ```
204
- *
205
- * @param {(string|number)=} path New path
206
- * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
135
+ * @return {string}
207
136
  */
208
- path(path) {
209
- if (isUndefined(path)) {
210
- return this.$$path;
211
- }
212
- let newPath = path !== null ? path.toString() : "";
213
- this.$$path = newPath.charAt(0) === "/" ? newPath : `/${newPath}`;
214
- this.$$compose();
215
- return this;
137
+ getPath() {
138
+ return $$path;
216
139
  }
217
140
 
218
141
  /**
219
- * This method is getter / setter.
220
- *
221
- * Returns the hash fragment when called without any parameters.
222
- *
223
142
  * Changes the hash fragment when called with a parameter and returns `$location`.
224
- *
225
- *
226
- * ```js
227
- * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
228
- * let hash = $location.hash();
229
- * // => "hashValue"
230
- * ```
231
- *
232
- * @param {(string|number)=} hash New hash fragment
233
- * @return {string|Location} hash
143
+ * @param {(string|number)} hash New hash fragment
144
+ * @return {Location} hash
234
145
  */
235
- hash(hash) {
236
- if (isUndefined(hash)) {
237
- return this.$$hash;
238
- }
239
-
240
- this.$$hash = hash !== null ? hash.toString() : "";
146
+ setHash(hash) {
147
+ $$hash = hash !== null ? hash.toString() : "";
241
148
  this.$$compose();
242
149
  return this;
243
150
  }
244
151
 
245
152
  /**
246
- * If called, all changes to $location during the current `$digest` will replace the current history
247
- * record, instead of adding a new one.
153
+ * Returns the hash fragment when called without any parameters.
154
+ * @return {string} hash
248
155
  */
249
- replace() {
250
- this.$$replace = true;
251
- return this;
156
+ getHash() {
157
+ return $$hash;
252
158
  }
253
159
 
254
160
  /**
255
- * Returns or sets the search part (as object) of current URL when called without any parameter
161
+ * Sets the search part (as object) of current URL
256
162
  *
257
- * @param {string|Object=} search New search params - string or hash object.
163
+ * @param {string|Object} search New search params - string or hash object.
258
164
  * @param {(string|number|Array<string>|boolean)=} paramValue If search is a string or number, then paramValue will override only a single search property.
259
- * @returns {Object|Location} Search object or Location object
165
+ * @returns {Object} Search object or Location object
260
166
  */
261
- search(search, paramValue) {
167
+ setSearch(search, paramValue) {
262
168
  switch (arguments.length) {
263
- case 0:
264
- return this.$$search;
265
169
  case 1:
266
170
  if (isString(search) || isNumber(search)) {
267
171
  search = search.toString();
268
- this.$$search = parseKeyValue(search);
172
+ $$search = parseKeyValue(search);
269
173
  } else if (isObject(search)) {
270
174
  search = structuredClone(search, {});
271
175
  // remove object undefined or null properties
@@ -273,7 +177,7 @@ export class Location {
273
177
  if (value == null) delete search[key];
274
178
  });
275
179
 
276
- this.$$search = search;
180
+ $$search = search;
277
181
  } else {
278
182
  throw $locationMinErr(
279
183
  "isrcharg",
@@ -283,9 +187,10 @@ export class Location {
283
187
  break;
284
188
  default:
285
189
  if (isUndefined(paramValue) || paramValue === null) {
286
- delete this.$$search[search];
190
+ delete $$search[search];
287
191
  } else {
288
- this.$$search[search] = paramValue;
192
+ // @ts-ignore
193
+ $$search[search] = paramValue;
289
194
  }
290
195
  }
291
196
 
@@ -294,28 +199,28 @@ export class Location {
294
199
  }
295
200
 
296
201
  /**
297
- * Compose url and update `url` and `absUrl` property
298
- * @returns {void}
202
+ * Returns the search part (as object) of current URL
203
+ *
204
+ * @returns {Object} Search object or Location object
299
205
  */
300
- $$compose() {
301
- this.$$url = normalizePath(this.$$path, this.$$search, this.$$hash);
302
- this.$$absUrl = this.$$normalizeUrl(this.$$url);
303
- this.$$urlUpdatedByLocation = true;
206
+ getSearch() {
207
+ return $$search;
304
208
  }
305
209
 
306
210
  /**
307
- * @param {string} _url
308
- * @returns {string}
211
+ * @private
212
+ * Compose url and update `url` and `absUrl` property
309
213
  */
310
- $$normalizeUrl(_url) {
311
- throw new Error(`Method not implemented ${_url}`);
214
+ $$compose() {
215
+ this.$$url = normalizePath($$path, $$search, $$hash);
216
+ this.absUrl = this.html5
217
+ ? this.appBaseNoFile + this.$$url.substring(1)
218
+ : this.appBase + (this.$$url ? this.hashPrefix + this.$$url : "");
219
+ urlUpdatedByLocation = true;
220
+ setTimeout(() => this.$$updateBrowser && this.$$updateBrowser());
312
221
  }
313
222
 
314
223
  /**
315
- * This method is getter / setter.
316
- *
317
- * Return the history state object when called without any parameter.
318
- *
319
224
  * Change the history state object when called with one parameter and return `$location`.
320
225
  * The state object is later passed to `pushState` or `replaceState`.
321
226
  * See {@link https://developer.mozilla.org/en-US/docs/Web/API/History/pushState#state|History.state}
@@ -323,85 +228,30 @@ export class Location {
323
228
  * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
324
229
  * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
325
230
  * older browsers (like IE9 or Android < 4.0), don't use this method.
326
- *
327
- * @param {any} state State object for pushState or replaceState
328
- * @return {any} state
231
+ * @param {any} state
232
+ * @returns {Location}
329
233
  */
330
- state(state) {
331
- if (!arguments.length) {
332
- return this.$$state;
333
- }
334
-
335
- if (!(this instanceof LocationHtml5Url) || !this.$$html5) {
234
+ setState(state) {
235
+ if (!this.html5) {
336
236
  throw $locationMinErr(
337
237
  "nostate",
338
- "History API state support is available only " +
339
- "in HTML5 mode and only in browsers supporting HTML5 History API",
238
+ "History API state support is available only in HTML5 mode",
340
239
  );
341
240
  }
342
- // The user might modify `stateObject` after invoking `$location.state(stateObject)`
241
+ // The user might modify `stateObject` after invoking `$location.setState(stateObject)`
343
242
  // but we're changing the $$state reference to $browser.state() during the $digest
344
243
  // so the modification window is narrow.
345
244
  this.$$state = isUndefined(state) ? null : state;
346
- this.$$urlUpdatedByLocation = true;
245
+ urlUpdatedByLocation = true;
347
246
  return this;
348
247
  }
349
248
 
350
249
  /**
351
- * @param {string} _url
352
- * @param {string} _url2
353
- * @returns {boolean}
250
+ * Return the history state object
251
+ * @returns {any}
354
252
  */
355
- $$parseLinkUrl(_url, _url2) {
356
- throw new Error(`Method not implemented ${_url} ${_url2}`);
357
- }
358
-
359
- $$parse(_url) {
360
- throw new Error(`Method not implemented ${_url}`);
361
- }
362
- }
363
-
364
- /**
365
- * This object is exposed as $location service when HTML5 mode is enabled and supported
366
- */
367
- export class LocationHtml5Url extends Location {
368
- /**
369
- * @param {string} appBase application base URL
370
- * @param {string} appBaseNoFile application base URL stripped of any filename
371
- * @param {string} basePrefix URL path prefix
372
- */
373
- constructor(appBase, appBaseNoFile, basePrefix) {
374
- super(appBase, appBaseNoFile);
375
- this.$$html5 = true;
376
- this.basePrefix = basePrefix || "";
377
- }
378
-
379
- /**
380
- * Parse given HTML5 (regular) URL string into properties
381
- * @param {string} url HTML5 URL
382
- */
383
- $$parse(url) {
384
- const pathUrl = stripBaseUrl(this.appBaseNoFile, url);
385
- if (!isString(pathUrl)) {
386
- throw $locationMinErr(
387
- "ipthprfx",
388
- 'Invalid url "{0}", missing path prefix "{1}".',
389
- url,
390
- this.appBaseNoFile,
391
- );
392
- }
393
-
394
- parseAppUrl(pathUrl, this, true);
395
-
396
- if (!this.$$path) {
397
- this.$$path = "/";
398
- }
399
-
400
- this.$$compose();
401
- }
402
-
403
- $$normalizeUrl(url) {
404
- return this.appBaseNoFile + url.substring(1); // first char is always '/'
253
+ getState() {
254
+ return this.$$state;
405
255
  }
406
256
 
407
257
  /**
@@ -409,149 +259,139 @@ export class LocationHtml5Url extends Location {
409
259
  * @param {string} relHref
410
260
  * @returns {boolean}
411
261
  */
412
- $$parseLinkUrl(url, relHref) {
413
- if (relHref && relHref[0] === "#") {
414
- // special case for links to hash fragments:
415
- // keep the old url and only replace the hash fragment
416
- this.hash(relHref.slice(1));
417
- return true;
418
- }
419
- let appUrl;
420
- let prevAppUrl;
421
- let rewrittenUrl;
422
-
423
- if (isDefined((appUrl = stripBaseUrl(this.appBase, url)))) {
424
- prevAppUrl = appUrl;
425
- if (
426
- this.basePrefix &&
427
- isDefined((appUrl = stripBaseUrl(this.basePrefix, appUrl)))
428
- ) {
429
- rewrittenUrl =
430
- this.appBaseNoFile + (stripBaseUrl("/", appUrl) || appUrl);
431
- } else {
432
- rewrittenUrl = this.appBase + prevAppUrl;
262
+ parseLinkUrl(url, relHref) {
263
+ if (this.html5) {
264
+ if (relHref && relHref[0] === "#") {
265
+ // special case for links to hash fragments:
266
+ // keep the old url and only replace the hash fragment
267
+ this.setHash(relHref.slice(1));
268
+ return true;
433
269
  }
434
- } else if (isDefined((appUrl = stripBaseUrl(this.appBaseNoFile, url)))) {
435
- rewrittenUrl = this.appBaseNoFile + appUrl;
436
- } else if (this.appBaseNoFile === `${url}/`) {
437
- rewrittenUrl = this.appBaseNoFile;
438
- }
439
- if (rewrittenUrl) {
440
- this.$$parse(rewrittenUrl);
270
+ let appUrl;
271
+ let prevAppUrl;
272
+ let rewrittenUrl;
273
+
274
+ if (isDefined((appUrl = stripBaseUrl(this.appBase, url)))) {
275
+ prevAppUrl = appUrl;
276
+ if (
277
+ this.basePrefix &&
278
+ isDefined((appUrl = stripBaseUrl(this.basePrefix, appUrl)))
279
+ ) {
280
+ rewrittenUrl =
281
+ this.appBaseNoFile + (stripBaseUrl("/", appUrl) || appUrl);
282
+ } else {
283
+ rewrittenUrl = this.appBase + prevAppUrl;
284
+ }
285
+ } else if (isDefined((appUrl = stripBaseUrl(this.appBaseNoFile, url)))) {
286
+ rewrittenUrl = this.appBaseNoFile + appUrl;
287
+ } else if (this.appBaseNoFile === `${url}/`) {
288
+ rewrittenUrl = this.appBaseNoFile;
289
+ }
290
+ if (rewrittenUrl) {
291
+ this.parse(rewrittenUrl);
292
+ }
293
+ return !!rewrittenUrl;
294
+ } else {
295
+ if (stripHash(this.appBase) === stripHash(url)) {
296
+ this.parse(url);
297
+ return true;
298
+ }
299
+ return false;
441
300
  }
442
- return !!rewrittenUrl;
443
301
  }
444
- }
445
302
 
446
- /**
447
- * LocationHashbangUrl represents URL
448
- * This object is exposed as $location service when developer doesn't opt into html5 mode.
449
- * It also serves as the base class for html5 mode fallback on legacy browsers.
450
- *
451
- */
452
- export class LocationHashbangUrl extends Location {
453
303
  /**
454
- * @param {string} appBase application base URL
455
- * @param {string} appBaseNoFile application base URL stripped of any filename
456
- * @param {string} hashPrefix hashbang prefix
304
+ * Parse given HTML5 (regular) URL string into properties
305
+ * @param {string} url HTML5 URL
457
306
  */
458
- constructor(appBase, appBaseNoFile, hashPrefix) {
459
- super(appBase, appBaseNoFile);
460
- this.hashPrefix = hashPrefix;
461
- }
307
+ parse(url) {
308
+ if (this.html5) {
309
+ const pathUrl = stripBaseUrl(this.appBaseNoFile, url);
310
+ if (!isString(pathUrl)) {
311
+ throw $locationMinErr(
312
+ "ipthprfx",
313
+ 'Invalid url "{0}", missing path prefix "{1}".',
314
+ url,
315
+ this.appBaseNoFile,
316
+ );
317
+ }
462
318
 
463
- /**
464
- * Parse given hashbang URL into properties
465
- * @param {string} url Hashbang URL
466
- */
467
- $$parse(url) {
468
- const withoutBaseUrl =
469
- stripBaseUrl(this.appBase, url) || stripBaseUrl(this.appBaseNoFile, url);
470
- let withoutHashUrl;
471
-
472
- if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === "#") {
473
- // The rest of the URL starts with a hash so we have
474
- // got either a hashbang path or a plain hash fragment
475
- withoutHashUrl = stripBaseUrl(this.hashPrefix, withoutBaseUrl);
476
- if (isUndefined(withoutHashUrl)) {
477
- // There was no hashbang prefix so we just have a hash fragment
478
- withoutHashUrl = withoutBaseUrl;
319
+ parseAppUrl(pathUrl, true);
320
+
321
+ if (!$$path) {
322
+ $$path = "/";
479
323
  }
324
+
325
+ this.$$compose();
480
326
  } else {
481
- // There was no hashbang path nor hash fragment:
482
- // If we are in HTML5 mode we use what is left as the path;
483
- // Otherwise we ignore what is left
484
- if (this.$$html5) {
485
- withoutHashUrl = withoutBaseUrl;
327
+ const withoutBaseUrl =
328
+ stripBaseUrl(this.appBase, url) ||
329
+ stripBaseUrl(this.appBaseNoFile, url);
330
+ let withoutHashUrl;
331
+
332
+ if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === "#") {
333
+ // The rest of the URL starts with a hash so we have
334
+ // got either a hashbang path or a plain hash fragment
335
+ withoutHashUrl = stripBaseUrl(this.hashPrefix, withoutBaseUrl);
336
+ if (isUndefined(withoutHashUrl)) {
337
+ // There was no hashbang prefix so we just have a hash fragment
338
+ withoutHashUrl = withoutBaseUrl;
339
+ }
486
340
  } else {
487
- withoutHashUrl = "";
488
- if (isUndefined(withoutBaseUrl)) {
489
- this.appBase = url;
490
- /** @type {?} */ (this).replace();
341
+ // There was no hashbang path nor hash fragment:
342
+ // If we are in HTML5 mode we use what is left as the path;
343
+ // Otherwise we ignore what is left
344
+ if (this.html5) {
345
+ withoutHashUrl = withoutBaseUrl;
346
+ } else {
347
+ withoutHashUrl = "";
348
+ if (isUndefined(withoutBaseUrl)) {
349
+ this.appBase = url;
350
+ }
491
351
  }
492
352
  }
493
- }
494
353
 
495
- parseAppUrl(withoutHashUrl, this, false);
354
+ parseAppUrl(withoutHashUrl, false);
496
355
 
497
- this.$$path = removeWindowsDriveName(
498
- this.$$path,
499
- withoutHashUrl,
500
- this.appBase,
501
- );
356
+ $$path = removeWindowsDriveName($$path, withoutHashUrl, this.appBase);
502
357
 
503
- this.$$compose();
358
+ this.$$compose();
504
359
 
505
- /*
506
- * In Windows, on an anchor node on documents loaded from
507
- * the filesystem, the browser will return a pathname
508
- * prefixed with the drive name ('/C:/path') when a
509
- * pathname without a drive is set:
510
- * * a.setAttribute('href', '/foo')
511
- * * a.pathname === '/C:/foo' //true
512
- *
513
- * Inside of AngularTS, we're always using pathnames that
514
- * do not include drive names for routing.
515
- */
516
- function removeWindowsDriveName(path, url, base) {
517
360
  /*
518
- Matches paths for file protocol on windows,
519
- such as /C:/foo/bar, and captures only /foo/bar.
520
- */
521
- const windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
522
-
523
- let firstPathSegmentMatch;
361
+ * In Windows, on an anchor node on documents loaded from
362
+ * the filesystem, the browser will return a pathname
363
+ * prefixed with the drive name ('/C:/path') when a
364
+ * pathname without a drive is set:
365
+ * * a.setAttribute('href', '/foo')
366
+ * * a.pathname === '/C:/foo' //true
367
+ *
368
+ * Inside of AngularTS, we're always using pathnames that
369
+ * do not include drive names for routing.
370
+ */
371
+ function removeWindowsDriveName(path, url, base) {
372
+ /*
373
+ Matches paths for file protocol on windows,
374
+ such as /C:/foo/bar, and captures only /foo/bar.
375
+ */
376
+ const windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
377
+
378
+ let firstPathSegmentMatch;
379
+
380
+ // Get the relative path from the input URL.
381
+ if (startsWith(url, base)) {
382
+ url = url.replace(base, "");
383
+ }
524
384
 
525
- // Get the relative path from the input URL.
526
- if (startsWith(url, base)) {
527
- url = url.replace(base, "");
528
- }
385
+ // The input URL intentionally contains a first path segment that ends with a colon.
386
+ if (windowsFilePathExp.exec(url)) {
387
+ return path;
388
+ }
529
389
 
530
- // The input URL intentionally contains a first path segment that ends with a colon.
531
- if (windowsFilePathExp.exec(url)) {
532
- return path;
390
+ firstPathSegmentMatch = windowsFilePathExp.exec(path);
391
+ return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
533
392
  }
534
-
535
- firstPathSegmentMatch = windowsFilePathExp.exec(path);
536
- return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
537
393
  }
538
394
  }
539
-
540
- $$normalizeUrl(url) {
541
- return this.appBase + (url ? this.hashPrefix + url : "");
542
- }
543
-
544
- /**
545
- * @param {string} url
546
- * @returns {boolean}
547
- */
548
- $$parseLinkUrl(url) {
549
- if (stripHash(this.appBase) === stripHash(url)) {
550
- this.$$parse(url);
551
- return true;
552
- }
553
- return false;
554
- }
555
395
  }
556
396
 
557
397
  export class LocationProvider {
@@ -559,20 +399,20 @@ export class LocationProvider {
559
399
  /** @type {string} */
560
400
  this.hashPrefixConf = "!";
561
401
 
562
- /** @type {Html5Mode} */
402
+ /** @type {import("./interface.ts").Html5Mode} */
563
403
  this.html5ModeConf = {
564
- enabled: false,
565
- requireBase: true,
404
+ enabled: true,
405
+ requireBase: false,
566
406
  rewriteLinks: true,
567
407
  };
568
408
 
569
- /** @type {Array<import("./interface.js").UrlChangeListener>} */
409
+ /** @type {Array<import("./interface.ts").UrlChangeListener>} */
570
410
  this.urlChangeListeners = [];
571
411
  this.urlChangeInit = false;
572
412
 
573
413
  /** @type {History['state']} */
574
414
  this.cachedState = null;
575
- /** @typeof {History.state} */
415
+ /** @type {History['state']} */
576
416
  this.lastHistoryState = null;
577
417
  /** @type {string} */
578
418
  this.lastBrowserUrl = window.location.href;
@@ -583,14 +423,19 @@ export class LocationProvider {
583
423
  // URL API
584
424
  /// ///////////////////////////////////////////////////////////
585
425
 
426
+ /**
427
+ * Updates the browser's current URL and history state.
428
+ *
429
+ * @param {string|undefined} url - The target URL to navigate to.
430
+ * @param {*} [state=null] - Optional history state object to associate with the new URL.
431
+ * @returns {LocationProvider}
432
+ */
586
433
  setUrl(url, state) {
587
434
  if (state === undefined) {
588
435
  state = null;
589
436
  }
590
-
591
- // setter
592
437
  if (url) {
593
- url = urlResolve(url).href;
438
+ url = new URL(url).href;
594
439
 
595
440
  if (this.lastBrowserUrl === url && this.lastHistoryState === state) {
596
441
  return this;
@@ -607,7 +452,7 @@ export class LocationProvider {
607
452
  * Returns the current URL with any empty hash (`#`) removed.
608
453
  * @return {string}
609
454
  */
610
- getUrl() {
455
+ getBrowserUrl() {
611
456
  return trimEmptyHash(window.location.href);
612
457
  }
613
458
 
@@ -635,19 +480,17 @@ export class LocationProvider {
635
480
 
636
481
  /**
637
482
  * Fires the state or URL change event.
638
- *
639
- * @private
640
483
  */
641
- fireStateOrUrlChange() {
484
+ #fireStateOrUrlChange() {
642
485
  const prevLastHistoryState = this.lastHistoryState;
643
486
  this.cacheState();
644
487
  if (
645
- this.lastBrowserUrl === this.getUrl() &&
488
+ this.lastBrowserUrl === this.getBrowserUrl() &&
646
489
  prevLastHistoryState === this.cachedState
647
490
  ) {
648
491
  return;
649
492
  }
650
- this.lastBrowserUrl = this.getUrl();
493
+ this.lastBrowserUrl = this.getBrowserUrl();
651
494
  this.lastHistoryState = this.cachedState;
652
495
  this.urlChangeListeners.forEach((listener) => {
653
496
  listener(trimEmptyHash(window.location.href), this.cachedState);
@@ -660,131 +503,75 @@ export class LocationProvider {
660
503
  * @param {import("./interface.js").UrlChangeListener} callback - The callback function to register.
661
504
  * @returns void
662
505
  */
663
- onUrlChange(callback) {
506
+ #onUrlChange(callback) {
664
507
  if (!this.urlChangeInit) {
665
- window.addEventListener("popstate", this.fireStateOrUrlChange.bind(this));
508
+ window.addEventListener(
509
+ "popstate",
510
+ this.#fireStateOrUrlChange.bind(this),
511
+ );
666
512
  window.addEventListener(
667
513
  "hashchange",
668
- this.fireStateOrUrlChange.bind(this),
514
+ this.#fireStateOrUrlChange.bind(this),
669
515
  );
670
516
  this.urlChangeInit = true;
671
517
  }
672
518
  this.urlChangeListeners.push(callback);
673
519
  }
674
520
 
675
- /**
676
- * The default value for the prefix is `'!'`.
677
- * @param {string=} prefix Prefix for hash part (containing path and search)
678
- * @returns {void}
679
- */
680
- setHashPrefix(prefix) {
681
- this.hashPrefixConf = prefix;
682
- }
683
-
684
- /**
685
- * Current hash prefix
686
- * @returns {string}
687
- */
688
- getHashPrefix() {
689
- return this.hashPrefixConf;
690
- }
691
-
692
- /**
693
- * Configures html5 mode
694
- * @param {(boolean|Html5Mode)=} mode If boolean, sets `html5Mode.enabled` to value. Otherwise, accepts html5Mode object
695
- *
696
- * @returns {void}
697
- */
698
- setHtml5Mode(mode) {
699
- if (isBoolean(mode)) {
700
- this.html5ModeConf.enabled = /** @type {boolean} */ (mode);
701
- }
702
- if (isObject(mode)) {
703
- const html5Mode = /** @type {Html5Mode} */ (mode);
704
- if (isDefined(html5Mode.enabled) && isBoolean(html5Mode.enabled)) {
705
- this.html5ModeConf.enabled = html5Mode.enabled;
706
- }
707
-
708
- if (
709
- isDefined(html5Mode.requireBase) &&
710
- isBoolean(html5Mode.requireBase)
711
- ) {
712
- this.html5ModeConf.requireBase = html5Mode.requireBase;
713
- }
714
-
715
- if (
716
- isDefined(html5Mode.rewriteLinks) &&
717
- (isBoolean(html5Mode.rewriteLinks) || isString(html5Mode.rewriteLinks))
718
- ) {
719
- this.html5ModeConf.rewriteLinks = html5Mode.rewriteLinks;
720
- }
721
- }
722
- }
723
-
724
- /**
725
- * Returns html5 mode cofiguration
726
- * @returns {Html5Mode}
727
- */
728
- getHtml5Mode() {
729
- return this.html5ModeConf;
730
- }
731
-
732
521
  $get = [
733
- "$rootScope",
734
- "$rootElement",
522
+ $t.$rootScope,
523
+ $t.$rootElement,
735
524
  /**
736
525
  *
737
526
  * @param {import('../../core/scope/scope.js').Scope} $rootScope
738
527
  * @param {Element} $rootElement
739
- * @returns
528
+ * @returns {Location}
740
529
  */
741
530
  ($rootScope, $rootElement) => {
742
531
  /** @type {Location} */
743
532
  let $location;
744
- let LocationMode;
745
533
  const baseHref = getBaseHref(); // if base[href] is undefined, it defaults to ''
746
534
  const initialUrl = trimEmptyHash(window.location.href);
747
535
  let appBase;
748
536
 
749
- if (this.getHtml5Mode().enabled) {
750
- if (!baseHref && this.getHtml5Mode().requireBase) {
537
+ if (this.html5ModeConf.enabled) {
538
+ if (!baseHref && this.html5ModeConf.requireBase) {
751
539
  throw $locationMinErr(
752
540
  "nobase",
753
541
  "$location in HTML5 mode requires a <base> tag to be present!",
754
542
  );
755
543
  }
756
544
  appBase = serverBase(initialUrl) + (baseHref || "/");
757
- LocationMode = LocationHtml5Url;
758
545
  } else {
759
546
  appBase = stripHash(initialUrl);
760
- LocationMode = LocationHashbangUrl;
761
547
  }
762
548
  const appBaseNoFile = stripFile(appBase);
763
549
 
764
- $location = new LocationMode(
550
+ $location = new Location(
765
551
  appBase,
766
552
  appBaseNoFile,
767
- `#${this.getHashPrefix()}`,
553
+ this.html5ModeConf.enabled,
554
+ `#${this.hashPrefixConf}`,
768
555
  );
769
- $location.$$parseLinkUrl(initialUrl, initialUrl);
556
+ $location.parseLinkUrl(initialUrl, initialUrl);
770
557
 
771
558
  $location.$$state = this.state();
772
559
 
773
560
  const IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
774
561
 
775
562
  const setBrowserUrlWithFallback = (url, state) => {
776
- const oldUrl = $location.url();
563
+ const oldUrl = $location.getUrl();
777
564
  const oldState = $location.$$state;
778
565
  try {
779
566
  this.setUrl(url, state);
780
567
 
781
- // Make sure $location.state() returns referentially identical (not just deeply equal)
568
+ // Make sure $location.getState() returns referentially identical (not just deeply equal)
782
569
  // state object; this makes possible quick checking if the state changed in the digest
783
570
  // loop. Checking deep equality would be too expensive.
784
571
  $location.$$state = this.state();
785
572
  } catch (e) {
786
573
  // Restore old values if pushState fails
787
- $location.url(/** @type {string} */ (oldUrl));
574
+ $location.setUrl(/** @type {string} */ (oldUrl));
788
575
  $location.$$state = oldState;
789
576
 
790
577
  throw e;
@@ -795,7 +582,7 @@ export class LocationProvider {
795
582
  "click",
796
583
  /** @param {MouseEvent} event */
797
584
  (event) => {
798
- const rewriteLinks = this.getHtml5Mode().rewriteLinks;
585
+ const rewriteLinks = this.html5ModeConf.rewriteLinks;
799
586
  // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
800
587
  // currently we open nice url link and redirect then
801
588
 
@@ -804,7 +591,6 @@ export class LocationProvider {
804
591
  event.ctrlKey ||
805
592
  event.metaKey ||
806
593
  event.shiftKey ||
807
- event.which === 2 ||
808
594
  event.button === 2
809
595
  ) {
810
596
  return;
@@ -839,7 +625,7 @@ export class LocationProvider {
839
625
  // an animation.
840
626
 
841
627
  const scvAnimatedString = /** @type {unknown} */ (absHref);
842
- absHref = urlResolve(
628
+ absHref = new URL(
843
629
  /** @type {SVGAnimatedString } */ (scvAnimatedString).animVal,
844
630
  ).href;
845
631
  }
@@ -852,7 +638,7 @@ export class LocationProvider {
852
638
  !elm.getAttribute("target") &&
853
639
  !event.defaultPrevented
854
640
  ) {
855
- if ($location.$$parseLinkUrl(absHref, relHref)) {
641
+ if ($location.parseLinkUrl(absHref, relHref)) {
856
642
  // We do a preventDefault for all urls that are part of the AngularTS application,
857
643
  // in html5mode and also without, so that we are able to abort navigation without
858
644
  // getting double entries in the location history.
@@ -863,14 +649,14 @@ export class LocationProvider {
863
649
  );
864
650
 
865
651
  // rewrite hashbang url <> html5 url
866
- if ($location.absUrl() !== initialUrl) {
867
- this.setUrl($location.absUrl(), true);
652
+ if ($location.absUrl !== initialUrl) {
653
+ this.setUrl($location.absUrl, true);
868
654
  }
869
655
 
870
656
  let initializing = true;
871
657
 
872
658
  // update $location when $browser url changes
873
- this.onUrlChange((newUrl, newState) => {
659
+ this.#onUrlChange((newUrl, newState) => {
874
660
  if (!startsWith(newUrl, appBaseNoFile)) {
875
661
  // If we are navigating outside of the app then force a reload
876
662
  window.location.href = newUrl;
@@ -878,10 +664,10 @@ export class LocationProvider {
878
664
  }
879
665
 
880
666
  Promise.resolve().then(() => {
881
- const oldUrl = $location.absUrl();
667
+ const oldUrl = $location.absUrl;
882
668
  const oldState = $location.$$state;
883
669
  let defaultPrevented;
884
- $location.$$parse(newUrl);
670
+ $location.parse(newUrl);
885
671
  $location.$$state = newState;
886
672
 
887
673
  defaultPrevented = $rootScope.$broadcast(
@@ -894,10 +680,10 @@ export class LocationProvider {
894
680
 
895
681
  // if the location was changed by a `$locationChangeStart` handler then stop
896
682
  // processing this location change
897
- if ($location.absUrl() !== newUrl) return;
683
+ if ($location.absUrl !== newUrl) return;
898
684
 
899
685
  if (defaultPrevented) {
900
- $location.$$parse(oldUrl);
686
+ $location.parse(oldUrl);
901
687
  $location.$$state = oldState;
902
688
  setBrowserUrlWithFallback(oldUrl, oldState);
903
689
  } else {
@@ -909,21 +695,21 @@ export class LocationProvider {
909
695
 
910
696
  // update browser
911
697
  const updateBrowser = () => {
912
- if (initializing || $location.$$urlUpdatedByLocation) {
913
- $location.$$urlUpdatedByLocation = false;
698
+ if (initializing || urlUpdatedByLocation) {
699
+ urlUpdatedByLocation = false;
914
700
 
915
- const oldUrl = /** @type {string} */ (this.getUrl());
916
- const newUrl = $location.absUrl();
701
+ const oldUrl = /** @type {string} */ (this.getBrowserUrl());
702
+ const newUrl = $location.absUrl;
917
703
  const oldState = this.state();
918
704
  const urlOrStateChanged =
919
705
  !urlsEqual(oldUrl, newUrl) ||
920
- ($location.$$html5 && oldState !== $location.$$state);
706
+ ($location.html5 && oldState !== $location.$$state);
921
707
 
922
708
  if (initializing || urlOrStateChanged) {
923
709
  initializing = false;
924
710
 
925
711
  setTimeout(() => {
926
- const newUrl = $location.absUrl();
712
+ const newUrl = $location.absUrl;
927
713
  const { defaultPrevented } = $rootScope.$broadcast(
928
714
  "$locationChangeStart",
929
715
  newUrl,
@@ -934,10 +720,10 @@ export class LocationProvider {
934
720
 
935
721
  // if the location was changed by a `$locationChangeStart` handler then stop
936
722
  // processing this location change
937
- if ($location.absUrl() !== newUrl) return;
723
+ if ($location.absUrl !== newUrl) return;
938
724
 
939
725
  if (defaultPrevented) {
940
- $location.$$parse(oldUrl);
726
+ $location.parse(oldUrl);
941
727
  $location.$$state = oldState;
942
728
  } else {
943
729
  if (urlOrStateChanged) {
@@ -951,13 +737,8 @@ export class LocationProvider {
951
737
  });
952
738
  }
953
739
  }
954
-
955
- $location.$$replace = false;
956
-
957
- // we don't need to return anything because $evalAsync will make the digest loop dirty when
958
- // there is a change
959
740
  };
960
-
741
+ $location.$$updateBrowser = updateBrowser;
961
742
  updateBrowser();
962
743
  $rootScope.$on("$updateBrowser", updateBrowser);
963
744
 
@@ -966,7 +747,7 @@ export class LocationProvider {
966
747
  function afterLocationChange(oldUrl, oldState) {
967
748
  $rootScope.$broadcast(
968
749
  "$locationChangeSuccess",
969
- $location.absUrl(),
750
+ $location.absUrl,
970
751
  oldUrl,
971
752
  $location.$$state,
972
753
  oldState,
@@ -978,29 +759,64 @@ export class LocationProvider {
978
759
 
979
760
  /**
980
761
  * ///////////////////////////
981
- * HELPERS
762
+ * PRIVATE HELPERS
982
763
  * ///////////////////////////
983
764
  */
984
765
 
985
766
  /**
986
- * Encode path using encodeUriSegment, ignoring forward slashes
767
+ * @ignore
768
+ * Encodes a URL path by encoding each path segment individually using `encodeUriSegment`,
769
+ * while preserving forward slashes (`/`) as segment separators.
770
+ *
771
+ * This function first decodes any existing percent-encodings (such as `%20` or `%2F`)
772
+ * in each segment to prevent double encoding, except for encoded forward slashes (`%2F`),
773
+ * which are replaced with literal slashes before decoding to keep path boundaries intact.
774
+ *
775
+ * After decoding, each segment is re-encoded with `encodeUriSegment` according to RFC 3986,
776
+ * encoding only characters that must be encoded in a path segment.
777
+ *
778
+ * The encoded segments are then rejoined with `/` to form the encoded path.
987
779
  *
988
- * @param {string} path Path to encode
989
- * @returns {string}
780
+ * @param {string} path - The URL path string to encode. May contain multiple segments separated by `/`.
781
+ * @returns {string} The encoded path, where each segment is encoded, but forward slashes are preserved.
782
+ *
783
+ * @example
784
+ * encodePath("user profile/images/pic 1.jpg")
785
+ * // returns "user%20profile/images/pic%201.jpg"
786
+ *
787
+ * @example
788
+ * encodePath("folder1%2Fsub/folder2")
789
+ * // returns "folder1%2Fsub/folder2"
990
790
  */
991
- function encodePath(path) {
791
+ export function encodePath(path) {
992
792
  const segments = path.split("/");
993
793
  let i = segments.length;
994
794
 
995
795
  while (i--) {
996
- // decode forward slashes to prevent them from being double encoded
997
- segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, "/"));
796
+ // Decode any existing encodings (e.g. %20, %2F) to prevent double-encoding
797
+ // But keep slashes intact (they were split on)
798
+ const decodedSegment = decodeURIComponent(
799
+ segments[i].replace(/%2F/gi, "/"),
800
+ );
801
+ segments[i] = encodeUriSegment(decodedSegment);
998
802
  }
999
803
 
1000
804
  return segments.join("/");
1001
805
  }
1002
806
 
1003
- function decodePath(path, html5Mode) {
807
+ /**
808
+ * @ignore
809
+ * Decodes each segment of a URL path.
810
+ *
811
+ * Splits the input path by "/", decodes each segment using decodeURIComponent,
812
+ * and if html5Mode is enabled, re-encodes any forward slashes inside segments
813
+ * as "%2F" to avoid confusion with path separators.
814
+ *
815
+ * @param {string} path - The URL path to decode.
816
+ * @param {boolean} html5Mode - If true, encodes forward slashes in segments as "%2F".
817
+ * @returns {string} The decoded path with segments optionally encoding slashes.
818
+ */
819
+ export function decodePath(path, html5Mode) {
1004
820
  const segments = path.split("/");
1005
821
  let i = segments.length;
1006
822
 
@@ -1015,7 +831,34 @@ function decodePath(path, html5Mode) {
1015
831
  return segments.join("/");
1016
832
  }
1017
833
 
1018
- function normalizePath(pathValue, searchValue, hashValue) {
834
+ /**
835
+ * @ignore
836
+ * Normalizes a URL path by encoding the path segments, query parameters, and hash fragment.
837
+ *
838
+ * - Path segments are encoded using `encodePath`, which encodes each segment individually.
839
+ * - Query parameters (`searchValue`) are converted to a query string using `toKeyValue`.
840
+ * - Hash fragment (`hashValue`) is encoded using `encodeUriSegment` and prefixed with `#`.
841
+ *
842
+ * This function returns a fully constructed URL path with optional query and hash components.
843
+ *
844
+ * @param {string} pathValue - The base URL path (e.g., "folder/item name").
845
+ * @param {Object.<string, any> | string | null} searchValue - An object or string representing query parameters.
846
+ * - If an object, it can contain strings, numbers, booleans, or arrays of values.
847
+ * - If a string, it is assumed to be a raw query string.
848
+ * - If null or undefined, no query string is added.
849
+ * @param {string | null} hashValue - The URL fragment (everything after `#`). If null or undefined, no hash is added.
850
+ *
851
+ * @returns {string} The normalized URL path including encoded path, optional query string, and optional hash.
852
+ *
853
+ * @example
854
+ * normalizePath("products/list", { category: "books", page: 2 }, "section1")
855
+ * // returns "products/list?category=books&page=2#section1"
856
+ *
857
+ * @example
858
+ * normalizePath("user profile/images", null, null)
859
+ * // returns "user%20profile/images"
860
+ */
861
+ export function normalizePath(pathValue, searchValue, hashValue) {
1019
862
  const search = toKeyValue(searchValue);
1020
863
  const hash = hashValue ? `#${encodeUriSegment(hashValue)}` : "";
1021
864
  const path = encodePath(pathValue);
@@ -1023,7 +866,15 @@ function normalizePath(pathValue, searchValue, hashValue) {
1023
866
  return path + (search ? `?${search}` : "") + hash;
1024
867
  }
1025
868
 
1026
- function parseAppUrl(url, locationObj, html5Mode) {
869
+ /**
870
+ * @ignore
871
+ * Parses the application URL and updates the location object with path, search, and hash.
872
+ *
873
+ * @param {string} url - The URL string to parse.
874
+ * @param {boolean} html5Mode - Whether HTML5 mode is enabled (affects decoding).
875
+ * @throws Will throw an error if the URL starts with invalid slashes.
876
+ */
877
+ export function parseAppUrl(url, html5Mode) {
1027
878
  if (/^\s*[\\/]{2,}/.test(url)) {
1028
879
  throw $locationMinErr("badpath", 'Invalid url "{0}".', url);
1029
880
  }
@@ -1037,22 +888,20 @@ function parseAppUrl(url, locationObj, html5Mode) {
1037
888
  prefixed && match.pathname.charAt(0) === "/"
1038
889
  ? match.pathname.substring(1)
1039
890
  : match.pathname;
1040
- locationObj.$$path = decodePath(path, html5Mode);
1041
- locationObj.$$search = parseKeyValue(match.search);
1042
- locationObj.$$hash = decodeURIComponent(match.hash);
891
+ $$path = decodePath(path, html5Mode);
892
+ $$search = parseKeyValue(match.search);
893
+ $$hash = decodeURIComponent(match.hash);
1043
894
 
1044
895
  // make sure path starts with '/';
1045
- if (locationObj.$$path && locationObj.$$path.charAt(0) !== "/") {
1046
- locationObj.$$path = `/${locationObj.$$path}`;
896
+ if ($$path && $$path.charAt(0) !== "/") {
897
+ $$path = `/${$$path}`;
1047
898
  }
1048
899
  }
1049
900
 
1050
- function startsWith(str, search) {
1051
- return str.slice(0, search.length) === search;
1052
- }
1053
-
1054
901
  /**
1055
- *
902
+ * @ignore
903
+ * Returns the substring of `url` after the `base` string if `url` starts with `base`.
904
+ * Returns `undefined` if `url` does not start with `base`.
1056
905
  * @param {string} base
1057
906
  * @param {string} url
1058
907
  * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
@@ -1064,23 +913,94 @@ export function stripBaseUrl(base, url) {
1064
913
  }
1065
914
  }
1066
915
 
916
+ /**
917
+ * @ignore
918
+ * Removes the hash fragment (including the '#') from the given URL string.
919
+ *
920
+ * @param {string} url - The URL string to process.
921
+ * @returns {string} The URL without the hash fragment.
922
+ */
1067
923
  export function stripHash(url) {
1068
924
  const index = url.indexOf("#");
1069
925
  return index === -1 ? url : url.substring(0, index);
1070
926
  }
1071
927
 
928
+ /**
929
+ * @ignore
930
+ * Removes the file name (and any hash) from a URL, returning the base directory path.
931
+ *
932
+ * For example:
933
+ * - Input: "https://example.com/path/to/file.js"
934
+ * Output: "https://example.com/path/to/"
935
+ *
936
+ * - Input: "https://example.com/path/to/file.js#section"
937
+ * Output: "https://example.com/path/to/"
938
+ *
939
+ * @param {string} url - The URL from which to strip the file name and hash.
940
+ * @returns {string} The base path of the URL, ending with a slash.
941
+ */
1072
942
  export function stripFile(url) {
1073
943
  return url.substring(0, stripHash(url).lastIndexOf("/") + 1);
1074
944
  }
1075
945
 
1076
- /* return the server only (scheme://host:port) */
946
+ /**
947
+ * @ignore
948
+ * Extracts the base server URL (scheme, host, and optional port) from a full URL.
949
+ *
950
+ * If no path is present, returns the full URL.
951
+ *
952
+ * For example:
953
+ * - Input: "https://example.com/path/to/file"
954
+ * Output: "https://example.com"
955
+ *
956
+ * - Input: "http://localhost:3000/api/data"
957
+ * Output: "http://localhost:3000"
958
+ *
959
+ * @param {string} url - The full URL to extract the server base from.
960
+ * @returns {string} The server base, including scheme and host (and port if present).
961
+ */
1077
962
  export function serverBase(url) {
1078
- return url.substring(0, url.indexOf("/", url.indexOf("//") + 2));
963
+ const start = url.indexOf("//") + 2;
964
+ const slashIndex = url.indexOf("/", start);
965
+ return slashIndex === -1 ? url : url.substring(0, slashIndex);
966
+ }
967
+
968
+ /**
969
+ * @ignore
970
+ * Determine if two URLs are equal despite potential differences in encoding,
971
+ * trailing slashes, or empty hash fragments, such as between $location.absUrl() and $browser.url().
972
+ *
973
+ * @param {string} a - First URL to compare.
974
+ * @param {string} b - Second URL to compare.
975
+ * @returns {boolean} True if URLs are equivalent after normalization.
976
+ */
977
+ export function urlsEqual(a, b) {
978
+ return normalizeUrl(a) === normalizeUrl(b);
1079
979
  }
1080
980
 
1081
- // Determine if two URLs are equal despite potentially having different encoding/normalizing
1082
- // such as $location.absUrl() vs $browser.url()
1083
- // See https://github.com/angular/angular.js/issues/16592
1084
- function urlsEqual(a, b) {
1085
- return a === b || urlResolve(a).href === urlResolve(b).href;
981
+ /**
982
+ * @ignore
983
+ * Normalize a URL by resolving it via a DOM anchor element,
984
+ * removing trailing slashes (except root), and trimming empty hashes.
985
+ *
986
+ * @param {string} url - URL to normalize.
987
+ * @returns {string} Normalized URL string.
988
+ */
989
+ function normalizeUrl(url) {
990
+ const anchor = document.createElement("a");
991
+ anchor.href = url;
992
+
993
+ let normalized = anchor.href;
994
+
995
+ // Remove trailing slash unless it's root (e.g., https://example.com/)
996
+ if (normalized.endsWith("/") && !/^https?:\/\/[^/]+\/$/.test(normalized)) {
997
+ normalized = normalized.slice(0, -1);
998
+ }
999
+
1000
+ // Remove empty hash (e.g., https://example.com/foo# -> https://example.com/foo)
1001
+ if (normalized.endsWith("#")) {
1002
+ normalized = normalized.slice(0, -1);
1003
+ }
1004
+
1005
+ return normalized;
1086
1006
  }