@angular-wave/angular.ts 0.7.7 → 0.8.0

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