@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.
- package/@types/animations/raf-scheduler.d.ts +2 -2
- package/@types/animations/shared.d.ts +0 -1
- package/@types/core/compile/attributes.d.ts +3 -3
- package/@types/core/compile/compile.d.ts +1 -1
- package/@types/core/di/injector.d.ts +0 -1
- package/@types/core/di/internal-injector.d.ts +1 -0
- package/@types/core/di/ng-module.d.ts +5 -0
- package/@types/core/filter/filter.d.ts +11 -13
- package/@types/core/parse/parse.d.ts +6 -7
- package/@types/core/sanitize/sanitize-uri.d.ts +3 -6
- package/@types/core/scope/scope.d.ts +1 -1
- package/@types/directive/attrs/attrs.d.ts +7 -1
- package/@types/directive/bind/bind.d.ts +2 -1
- package/@types/directive/events/events.d.ts +9 -3
- package/@types/directive/http/http.d.ts +6 -2
- package/@types/directive/include/include.d.ts +2 -2
- package/@types/directive/input/input.d.ts +2 -12
- package/@types/directive/messages/messages.d.ts +9 -48
- package/@types/directive/model/model.d.ts +3 -3
- package/@types/directive/options/options.d.ts +13 -20
- package/@types/directive/switch/switch.d.ts +1 -0
- package/@types/directive/transclude/transclude.d.ts +10 -6
- package/@types/index.d.ts +1 -1
- package/@types/interface.d.ts +56 -18
- package/@types/{public.d.ts → ng.d.ts} +2 -2
- package/@types/router/directives/view-directive.d.ts +2 -19
- package/@types/router/{common → glob}/glob.d.ts +5 -1
- package/@types/router/globals.d.ts +2 -3
- package/@types/router/path/path-utils.d.ts +8 -11
- package/@types/router/state/interface.d.ts +1 -1
- package/@types/router/state/state-object.d.ts +1 -1
- package/@types/router/state/state-registry.d.ts +1 -2
- package/@types/router/state/state-service.d.ts +8 -7
- package/@types/router/state-filters.d.ts +24 -2
- package/@types/router/transition/transition.d.ts +12 -15
- package/@types/router/url/url-matcher.d.ts +3 -3
- package/@types/router/url/url-rule.d.ts +1 -0
- package/@types/router/url/url-rules.d.ts +26 -6
- package/@types/router/url/url-service.d.ts +30 -42
- package/@types/services/anchor-scroll.d.ts +1 -1
- package/@types/{core → services/exception}/exception-handler.d.ts +4 -4
- package/@types/{core/error-handler.d.ts → services/exception/interface.d.ts} +1 -1
- package/@types/services/http/http.d.ts +48 -3
- package/@types/services/http/interface.d.ts +2 -2
- package/@types/services/http-backend/http-backend.d.ts +49 -44
- package/@types/services/location/interface.d.ts +63 -0
- package/@types/services/location/location.d.ts +330 -0
- package/@types/{core → services}/sce/sce.d.ts +1 -1
- package/@types/services/template-cache/interface.d.ts +8 -2
- package/@types/services/template-cache/template-cache.d.ts +1 -1
- package/@types/services/template-request.d.ts +1 -1
- package/@types/shared/cache.d.ts +0 -2
- package/@types/shared/common.d.ts +0 -2
- package/@types/shared/dom.d.ts +6 -0
- package/@types/shared/interface.d.ts +0 -4
- package/@types/{router/common → shared}/queue.d.ts +2 -2
- package/@types/shared/test-utils.d.ts +1 -0
- package/@types/shared/url-utils/interface.d.ts +46 -0
- package/@types/shared/url-utils/url-utils.d.ts +64 -0
- package/@types/shared/utils.d.ts +44 -6
- package/Makefile +8 -4
- package/dist/angular-ts.esm.js +1889 -2199
- package/dist/angular-ts.umd.js +1889 -2199
- package/dist/angular-ts.umd.min.js +1 -1
- package/docs/assets/scss/index.scss +23 -0
- package/docs/content/_index.md +9 -8
- package/docs/content/docs/_index.md +1 -1
- package/docs/content/docs/directive/app.md +1 -1
- package/docs/content/docs/directive/bind.md +10 -8
- package/docs/content/docs/directive/blur.md +1 -1
- package/docs/content/docs/directive/channel.md +2 -2
- package/docs/content/docs/directive/class-even.md +1 -1
- package/docs/content/docs/directive/class-odd.md +1 -1
- package/docs/content/docs/directive/class.md +1 -1
- package/docs/content/docs/directive/click.md +1 -1
- package/docs/content/docs/directive/copy.md +1 -1
- package/docs/content/docs/directive/cut.md +1 -1
- package/docs/content/docs/directive/dblclick.md +1 -1
- package/docs/content/docs/directive/focus.md +1 -1
- package/docs/content/docs/directive/get.md +203 -0
- package/docs/content/docs/directive/keydown.md +1 -1
- package/docs/content/docs/directive/keyup.md +1 -1
- package/docs/content/docs/directive/load.md +1 -1
- package/docs/content/docs/directive/mousedown.md +1 -1
- package/docs/content/docs/directive/mouseenter.md +1 -1
- package/docs/content/docs/directive/mouseleave.md +1 -1
- package/docs/content/docs/directive/mousemove.md +1 -1
- package/docs/content/docs/directive/mouseout.md +1 -1
- package/docs/content/docs/directive/mouseover.md +1 -1
- package/docs/content/docs/directive/mouseup.md +1 -1
- package/docs/content/docs/directive/non-bindable.md +28 -0
- package/docs/content/docs/provider/locationProvider.md +26 -0
- package/docs/content/docs/provider/templateCacheProvider.md +66 -1
- package/docs/content/docs/service/location.md +57 -0
- package/docs/content/docs/service/templateCache.md +2 -2
- package/docs/content/docs/service/url.md +5 -0
- package/docs/layouts/partials/hooks/head-end.html +1 -1
- package/docs/layouts/shortcodes/showcss.html +2 -0
- package/docs/layouts/shortcodes/version.html +1 -0
- package/docs/static/examples/counter/counter-test.html +0 -4
- package/docs/static/examples/eventbus/eventbus-test.html +0 -4
- package/docs/static/examples/ng-bind/ng-bind.html +2 -2
- package/docs/static/examples/ng-non-bindable/ng-non-bindable-test.html +13 -0
- package/docs/static/examples/ng-non-bindable/ng-non-bindable.html +3 -0
- package/docs/static/examples/ng-non-bindable/ng-non-bindable.test.js +11 -0
- package/docs/static/typedoc/assets/hierarchy.js +1 -1
- package/docs/static/typedoc/assets/highlight.css +6 -6
- package/docs/static/typedoc/assets/navigation.js +1 -1
- package/docs/static/typedoc/assets/search.js +1 -1
- package/docs/static/typedoc/classes/Location.html +55 -0
- package/docs/static/typedoc/classes/LocationProvider.html +20 -0
- package/docs/static/typedoc/classes/NgModule.html +32 -0
- package/docs/static/typedoc/classes/TemplateCacheProvider.html +1 -1
- package/docs/static/typedoc/hierarchy.html +1 -1
- package/docs/static/typedoc/index.html +1 -1
- package/docs/static/typedoc/interfaces/DefaultPorts.html +5 -0
- package/docs/static/typedoc/interfaces/Directive.html +5 -4
- package/docs/static/typedoc/interfaces/Html5Mode.html +23 -0
- package/docs/static/typedoc/interfaces/HttpProviderDefaults.html +1 -1
- package/docs/static/typedoc/interfaces/HttpResponse.html +2 -3
- package/docs/static/typedoc/interfaces/Provider.html +16 -10
- package/docs/static/typedoc/interfaces/RequestConfig.html +1 -1
- package/docs/static/typedoc/interfaces/RequestShortcutConfig.html +1 -1
- package/docs/static/typedoc/interfaces/TemplateCache.html +7 -0
- package/docs/static/typedoc/interfaces/UrlParts.html +9 -0
- package/docs/static/typedoc/types/AnnotatedDirectiveFactory.html +1 -0
- package/docs/static/typedoc/types/AnnotatedFactory.html +1 -1
- package/docs/static/typedoc/types/DirectiveFactory.html +1 -2
- package/docs/static/typedoc/types/DirectiveFactoryFn.html +1 -0
- package/docs/static/typedoc/types/Expression.html +1 -1
- package/docs/static/typedoc/types/HttpResponseStatus.html +1 -0
- package/docs/static/typedoc/types/{TemplateCache.html → SwapModeType.html} +1 -1
- package/docs/static/typedoc/types/UrlChangeListener.html +5 -0
- package/docs/static/typedoc/variables/SwapMode.html +11 -0
- package/docs/static/version.js +13 -0
- package/docs/test-results/.last-run.json +4 -0
- package/docs/test-results/static-examples-counter-counter-counter-example/error-context.md +50 -0
- package/legacy.d.ts +0 -10
- package/package.json +1 -3
- package/src/{loader.js → angular.js} +5 -10
- package/src/angular.spec.js +189 -21
- package/src/animations/animate-children-directive.js +2 -2
- package/src/animations/animate-css.js +17 -18
- package/src/animations/animate.spec.js +1 -1
- package/src/animations/raf-scheduler.js +1 -1
- package/src/animations/shared.js +2 -12
- package/src/binding.spec.js +1 -1
- package/src/core/compile/attributes.js +1 -1
- package/src/core/compile/compile.js +7 -10
- package/src/core/compile/compile.spec.js +1 -1
- package/src/core/controller/controller.spec.js +1 -1
- package/src/core/controller/controller.test.js +1 -0
- package/src/core/di/injector.js +11 -25
- package/src/core/di/injector.spec.js +2 -2
- package/src/core/di/injector.test.js +2 -2
- package/src/core/di/internal-injector.js +7 -7
- package/src/core/di/ng-module.js +12 -27
- package/src/core/filter/filter.js +28 -28
- package/src/core/filter/filter.spec.js +1 -1
- package/src/core/filter/filter.test.js +1 -0
- package/src/core/interpolate/interpolate.js +4 -6
- package/src/core/interpolate/interpolate.spec.js +1 -1
- package/src/core/interpolate/interpolate.test.js +1 -0
- package/src/core/parse/ast/ast.spec.js +1 -1
- package/src/core/parse/ast/ast.test.js +1 -1
- package/src/core/parse/interpreter.js +32 -38
- package/src/core/parse/lexer/lexer.spec.js +1 -1
- package/src/core/parse/parse.js +150 -146
- package/src/core/parse/parse.spec.js +17 -16
- package/src/core/prop.spec.js +1 -1
- package/src/core/root-element.spec.js +1 -1
- package/src/core/sanitize/sanitize-uri.js +3 -3
- package/src/core/scope/scope.js +12 -13
- package/src/core/scope/scope.spec.js +3 -4
- package/src/directive/aria/aria.spec.js +1 -1
- package/src/directive/aria/aria.test.js +1 -0
- package/src/directive/attrs/attrs.js +7 -4
- package/src/directive/attrs/attrs.spec.js +1 -1
- package/src/directive/attrs/attrs.test.js +1 -0
- package/src/directive/attrs/boolean.spec.js +1 -1
- package/src/directive/attrs/boolean.test.js +1 -0
- package/src/directive/attrs/element-style.spec.js +1 -1
- package/src/directive/attrs/element-style.test.js +1 -0
- package/src/directive/attrs/src.spec.js +1 -1
- package/src/directive/attrs/src.test.js +1 -0
- package/src/directive/bind/bind-html.spec.js +1 -1
- package/src/directive/bind/bind.js +1 -0
- package/src/directive/bind/bind.spec.js +1 -1
- package/src/directive/bind/bind.test.js +1 -0
- package/src/directive/channel/channel.spec.js +1 -1
- package/src/directive/channel/channel.test.js +1 -0
- package/src/directive/class/class.spec.js +1 -1
- package/src/directive/class/class.test.js +1 -0
- package/src/directive/cloak/cloak.spec.js +1 -1
- package/src/directive/cloak/cloak.test.js +1 -0
- package/src/directive/controller/controller.spec.js +1 -1
- package/src/directive/controller/controller.test.js +1 -0
- package/src/directive/events/click.spec.js +1 -1
- package/src/directive/events/event.spec.js +1 -1
- package/src/directive/events/events.js +6 -2
- package/src/directive/events/events.test.js +1 -0
- package/src/directive/form/form.js +8 -5
- package/src/directive/form/form.spec.js +1 -1
- package/src/directive/form/form.test.js +1 -0
- package/src/directive/http/delete.spec.js +3 -1
- package/src/directive/http/form-test.html +18 -0
- package/src/directive/http/get.spec.js +281 -4
- package/src/directive/http/http.js +112 -15
- package/src/directive/http/http.test.js +2 -2
- package/src/directive/http/post.spec.js +506 -9
- package/src/directive/http/put.spec.js +3 -1
- package/src/directive/if/if.spec.js +1 -1
- package/src/directive/include/include.js +7 -7
- package/src/directive/include/include.spec.js +1 -1
- package/src/directive/init/init.spec.js +1 -1
- package/src/directive/init/init.test.js +1 -0
- package/src/directive/input/input.js +19 -43
- package/src/directive/input/input.spec.js +1 -2
- package/src/directive/input/input.test.js +1 -0
- package/src/directive/messages/messages.js +4 -0
- package/src/directive/messages/messages.spec.js +1 -1
- package/src/directive/messages/messages.test.js +1 -0
- package/src/directive/model/model.js +14 -14
- package/src/directive/model/model.spec.js +1 -1
- package/src/directive/model/model.test.js +1 -0
- package/src/directive/model-options/model-option.test.js +1 -0
- package/src/directive/model-options/model-options.js +1 -1
- package/src/directive/model-options/model-options.spec.js +1 -1
- package/src/directive/non-bindable/non-bindable.spec.js +1 -1
- package/src/directive/non-bindable/non-bindable.test.js +1 -0
- package/src/directive/observe/observe.spec.js +1 -1
- package/src/directive/observe/observe.test.js +1 -0
- package/src/directive/on/on.spec.js +1 -1
- package/src/directive/on/on.test.js +1 -0
- package/src/directive/options/options.js +454 -464
- package/src/directive/options/options.spec.js +1 -1
- package/src/directive/options/options.test.js +1 -0
- package/src/directive/ref/href.spec.js +1 -1
- package/src/directive/ref/href.test.js +2 -0
- package/src/directive/ref/ref.spec.js +1 -1
- package/src/directive/repeat/repeat.spec.js +2 -3
- package/src/directive/repeat/repeat.test.js +1 -0
- package/src/directive/script/script.spec.js +1 -1
- package/src/directive/script/script.test.js +1 -0
- package/src/directive/select/select.js +1 -1
- package/src/directive/select/select.spec.js +1 -1
- package/src/directive/select/select.test.js +1 -0
- package/src/directive/setter/setter.js +12 -14
- package/src/directive/setter/setter.spec.js +40 -17
- package/src/directive/setter/setter.test.js +1 -0
- package/src/directive/show-hide/show-hide.spec.js +1 -1
- package/src/directive/show-hide/show-hide.test.js +1 -0
- package/src/directive/style/style.spec.js +1 -1
- package/src/directive/style/style.test.js +1 -0
- package/src/directive/switch/switch.js +1 -0
- package/src/directive/switch/switch.spec.js +1 -1
- package/src/directive/switch/switch.test.js +1 -0
- package/src/directive/transclude/transclude.js +87 -89
- package/src/directive/validators/validators.js +82 -84
- package/src/directive/validators/validators.spec.js +5 -4
- package/src/directive/validators/validators.test.js +1 -0
- package/src/filters/filter.spec.js +1 -1
- package/src/filters/filters.spec.js +1 -1
- package/src/filters/limit-to.js +2 -3
- package/src/filters/limit-to.spec.js +1 -1
- package/src/filters/order-by.spec.js +1 -1
- package/src/index.js +1 -1
- package/src/injection-tokens.js +6 -2
- package/src/interface.ts +70 -19
- package/src/loader.md +0 -155
- package/src/{public.js → ng.js} +16 -23
- package/src/{public.spec.js → ng.spec.js} +1 -1
- package/src/router/directives/state-directives.spec.js +9 -8
- package/src/router/directives/view-directive.js +11 -9
- package/src/router/directives/view-directive.spec.js +8 -9
- package/src/router/{common/common.html → glob/glob.html} +2 -3
- package/src/router/{common → glob}/glob.js +5 -0
- package/src/router/{common/common.test.js → glob/glob.test.js} +2 -1
- package/src/router/globals.js +1 -2
- package/src/router/path/path-utils.js +5 -0
- package/src/router/router-test-hashbang.html +45 -0
- package/src/router/services.spec.js +5 -6
- package/src/router/state/interface.ts +1 -1
- package/src/router/state/state-builder.js +3 -3
- package/src/router/state/state-builder.spec.js +1 -1
- package/src/router/state/state-object.js +1 -1
- package/src/router/state/state-registry.js +2 -3
- package/src/router/state/state-service.js +13 -10
- package/src/router/state/state.spec.js +23 -22
- package/src/router/state/state.test.js +1 -0
- package/src/router/state/views.js +1 -1
- package/src/router/state-filter.spec.js +1 -1
- package/src/router/state-filters.js +15 -11
- package/src/router/template-factory.js +5 -4
- package/src/router/template-factory.spec.js +1 -1
- package/src/router/transition/hook-registry.js +1 -1
- package/src/router/transition/transition-service.js +6 -5
- package/src/router/transition/transition.js +4 -4
- package/src/router/url/url-matcher.js +3 -3
- package/src/router/url/url-rule.js +1 -0
- package/src/router/url/url-rules.js +8 -5
- package/src/router/url/url-service.js +82 -85
- package/src/router/url/url-service.spec.js +55 -39
- package/src/router/url/url.test.js +1 -0
- package/src/router/view/view.js +4 -5
- package/src/router/view/view.spec.js +10 -12
- package/src/router/view/view.test.js +1 -0
- package/src/router/view-hook.spec.js +1 -1
- package/src/router/view-scroll.spec.js +1 -1
- package/src/services/anchor-scroll.html +2 -9
- package/src/services/anchor-scroll.js +6 -5
- package/src/{core → services/exception}/exception-handler.js +2 -2
- package/src/{core/error-handler.ts → services/exception/interface.ts} +1 -1
- package/src/services/http/http.js +11 -17
- package/src/services/http/http.spec.js +2 -7
- package/src/services/http/interface.ts +2 -2
- package/src/services/http/template-request.spec.js +1 -1
- package/src/services/http-backend/http-backend.js +53 -89
- package/src/services/http-backend/http-backend.spec.js +2 -6
- package/src/services/http-backend/http-backend.test.js +1 -0
- package/src/services/location/interface.ts +70 -0
- package/src/{core → services}/location/location.html +4 -1
- package/src/services/location/location.js +999 -0
- package/src/{core → services}/location/location.spec.js +911 -532
- package/src/{core → services}/location/location.test.js +2 -2
- package/src/services/log/log.spec.js +1 -1
- package/src/services/log/log.test.js +1 -0
- package/src/services/pubsub/pubsub.spec.js +1 -1
- package/src/{core → services}/sce/sce.html +1 -1
- package/src/{core → services}/sce/sce.js +14 -10
- package/src/{core → services}/sce/sce.md +2 -2
- package/src/{core → services}/sce/sce.spec.js +3 -4
- package/src/{core → services}/sce/sce.test.js +1 -1
- package/src/services/template-cache/interface.ts +8 -2
- package/src/services/template-cache/template-cache.js +3 -1
- package/src/services/template-cache/template-cache.spec.js +73 -1
- package/src/services/template-cache/template-cache.test.js +1 -0
- package/src/services/template-request.js +2 -1
- package/src/shared/cache.js +0 -2
- package/src/shared/common.js +0 -5
- package/src/shared/common.spec.js +1 -1
- package/src/shared/dom.js +10 -0
- package/src/shared/interface.ts +0 -4
- package/src/{router/common → shared}/queue.js +7 -7
- package/src/shared/shared.html +1 -0
- package/src/shared/shared.test.js +1 -0
- package/src/shared/test-utils.js +1 -0
- package/src/shared/url-utils/interface.ts +54 -0
- package/src/{core → shared}/url-utils/url-utils.html +4 -1
- package/src/{core → shared}/url-utils/url-utils.js +26 -47
- package/src/{core → shared}/url-utils/url-utils.spec.js +10 -17
- package/src/{core → shared}/url-utils/url-utils.test.js +1 -1
- package/src/shared/utils.js +60 -9
- package/src/shared/utils.spec.js +35 -1
- package/src/src.html +1 -2
- package/typedoc.json +0 -1
- package/utils/express.js +36 -2
- package/utils/version.cjs +23 -0
- package/@types/core/location/location.d.ts +0 -317
- package/@types/core/task-tracker-factory.d.ts +0 -76
- package/@types/core/url-utils/url-utils.d.ts +0 -56
- package/@types/router/state-provider.d.ts +0 -123
- package/@types/services/browser.d.ts +0 -101
- package/docs/static/typedoc/types/SwapInsertPosition.html +0 -2
- package/jsdoc.json +0 -22
- package/src/core/location/location.js +0 -984
- package/src/core/location/location.md +0 -114
- package/src/core/task-tracker-factory.js +0 -145
- package/src/core/url-utils/url-utils.md +0 -46
- package/src/directive/non-bindable/non-bindable.md +0 -17
- package/src/loader.spec.js +0 -169
- package/src/router/state-provider.js +0 -146
- package/src/services/browser.js +0 -212
- /package/@types/{loader.d.ts → angular.d.ts} +0 -0
- /package/src/router/{common → glob}/glob.spec.js +0 -0
- /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
|
-
}
|