ember-source 5.11.0 → 5.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/build-metadata.json +3 -3
  2. package/dist/ember-template-compiler.js +48 -42
  3. package/dist/ember-testing.js +1 -1
  4. package/dist/ember.debug.js +23102 -23100
  5. package/dist/ember.prod.js +31562 -31563
  6. package/dist/packages/@ember/-internals/container/index.js +1 -1
  7. package/dist/packages/@ember/-internals/deprecations/index.js +2 -1
  8. package/dist/packages/@ember/-internals/glimmer/index.js +2 -1
  9. package/dist/packages/@ember/-internals/meta/lib/meta.js +4 -3
  10. package/dist/packages/@ember/-internals/metal/index.js +9 -8
  11. package/dist/packages/@ember/-internals/routing/index.js +6 -5
  12. package/dist/packages/@ember/-internals/runtime/lib/ext/rsvp.js +3 -2
  13. package/dist/packages/@ember/-internals/runtime/lib/mixins/-proxy.js +6 -5
  14. package/dist/packages/@ember/-internals/runtime/lib/mixins/action_handler.js +4 -3
  15. package/dist/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js +1 -1
  16. package/dist/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js +2 -1
  17. package/dist/packages/@ember/-internals/runtime/lib/mixins/target_action_support.js +4 -3
  18. package/dist/packages/@ember/-internals/string/index.js +1 -1
  19. package/dist/packages/@ember/-internals/utils/index.js +4 -4
  20. package/dist/packages/@ember/-internals/views/index.js +1 -1
  21. package/dist/packages/@ember/-internals/views/lib/compat/fallback-view-registry.js +1 -1
  22. package/dist/packages/@ember/-internals/views/lib/component_lookup.js +1 -1
  23. package/dist/packages/@ember/-internals/views/lib/mixins/action_support.js +5 -3
  24. package/dist/packages/@ember/-internals/views/lib/mixins/child_views_support.js +3 -3
  25. package/dist/packages/@ember/-internals/views/lib/mixins/class_names_support.js +4 -3
  26. package/dist/packages/@ember/-internals/views/lib/mixins/view_support.js +4 -3
  27. package/dist/packages/@ember/-internals/views/lib/system/event_dispatcher.js +6 -12
  28. package/dist/packages/@ember/-internals/views/lib/system/utils.js +3 -2
  29. package/dist/packages/@ember/-internals/views/lib/views/core_view.js +76 -8
  30. package/dist/packages/@ember/-internals/views/lib/views/states.js +4 -3
  31. package/dist/packages/@ember/application/index.js +16 -7
  32. package/dist/packages/@ember/application/instance.js +13 -9
  33. package/dist/packages/@ember/application/namespace.js +7 -6
  34. package/dist/packages/@ember/array/index.js +617 -11
  35. package/dist/packages/@ember/array/make.js +1 -0
  36. package/dist/packages/@ember/array/mutable.js +1 -1
  37. package/dist/packages/@ember/array/proxy.js +8 -5
  38. package/dist/packages/@ember/component/helper.js +4 -4
  39. package/dist/packages/@ember/component/index.js +4 -4
  40. package/dist/packages/@ember/controller/index.js +6 -6
  41. package/dist/packages/@ember/debug/container-debug-adapter.js +5 -4
  42. package/dist/packages/@ember/debug/data-adapter.js +7 -4
  43. package/dist/packages/@ember/debug/index.js +213 -4
  44. package/dist/packages/@ember/debug/lib/assert.js +47 -0
  45. package/dist/packages/@ember/debug/lib/deprecate.js +194 -4
  46. package/dist/packages/@ember/debug/lib/inspect.js +120 -2
  47. package/dist/packages/@ember/debug/lib/warn.js +94 -3
  48. package/dist/packages/@ember/engine/index.js +440 -17
  49. package/dist/packages/@ember/engine/instance.js +175 -11
  50. package/dist/packages/@ember/engine/parent.js +1 -0
  51. package/dist/packages/@ember/helper/index.js +4 -4
  52. package/dist/packages/@ember/instrumentation/index.js +2 -1
  53. package/dist/packages/@ember/modifier/index.js +13 -5
  54. package/dist/packages/@ember/modifier/on.js +15 -0
  55. package/dist/packages/@ember/object/-internals.js +6 -5
  56. package/dist/packages/@ember/object/compat.js +4 -3
  57. package/dist/packages/@ember/object/computed.js +4 -4
  58. package/dist/packages/@ember/object/core.js +861 -14
  59. package/dist/packages/@ember/object/evented.js +4 -4
  60. package/dist/packages/@ember/object/events.js +3 -3
  61. package/dist/packages/@ember/object/index.js +260 -9
  62. package/dist/packages/@ember/object/internals.js +1 -1
  63. package/dist/packages/@ember/object/lib/computed/computed_macros.js +8 -6
  64. package/dist/packages/@ember/object/lib/computed/reduce_computed_macros.js +8 -4
  65. package/dist/packages/@ember/object/mixin.js +6 -5
  66. package/dist/packages/@ember/object/observable.js +103 -9
  67. package/dist/packages/@ember/object/observers.js +3 -3
  68. package/dist/packages/@ember/object/promise-proxy-mixin.js +5 -5
  69. package/dist/packages/@ember/renderer/index.js +4 -4
  70. package/dist/packages/@ember/routing/-internals.js +3 -1
  71. package/dist/packages/@ember/routing/hash-location.js +2 -2
  72. package/dist/packages/@ember/routing/history-location.js +3 -2
  73. package/dist/packages/@ember/routing/index.js +4 -4
  74. package/dist/packages/@ember/routing/lib/dsl.js +2 -1
  75. package/dist/packages/@ember/routing/lib/generate_controller.js +4 -3
  76. package/dist/packages/@ember/routing/lib/router_state.js +26 -1
  77. package/dist/packages/@ember/routing/lib/routing-service.js +107 -9
  78. package/dist/packages/@ember/routing/lib/utils.js +238 -7
  79. package/dist/packages/@ember/routing/none-location.js +3 -2
  80. package/dist/packages/@ember/routing/route.js +1618 -22
  81. package/dist/packages/@ember/routing/router-service.js +638 -12
  82. package/dist/packages/@ember/routing/router.js +1449 -14
  83. package/dist/packages/@ember/runloop/index.js +760 -6
  84. package/dist/packages/@ember/service/index.js +3 -3
  85. package/dist/packages/@ember/template/index.js +4 -4
  86. package/dist/packages/@ember/utils/index.js +2 -1
  87. package/dist/packages/@ember/utils/lib/compare.js +159 -4
  88. package/dist/packages/@ember/utils/lib/is_empty.js +4 -4
  89. package/dist/packages/@ember/utils/lib/type-of.js +110 -1
  90. package/dist/packages/@glimmer/tracking/index.js +3 -3
  91. package/dist/packages/@glimmer/tracking/primitives/cache.js +3 -3
  92. package/dist/packages/ember/barrel.js +28 -13
  93. package/dist/packages/ember/version.js +1 -1
  94. package/dist/packages/ember-testing/lib/adapters/adapter.js +1 -1
  95. package/dist/packages/ember-testing/lib/adapters/qunit.js +2 -1
  96. package/dist/packages/ember-testing/lib/ext/application.js +2 -1
  97. package/dist/packages/ember-testing/lib/ext/rsvp.js +1 -1
  98. package/dist/packages/ember-testing/lib/helpers/and_then.js +2 -1
  99. package/dist/packages/ember-testing/lib/helpers/current_path.js +8 -6
  100. package/dist/packages/ember-testing/lib/helpers/current_route_name.js +8 -6
  101. package/dist/packages/ember-testing/lib/helpers/current_url.js +6 -5
  102. package/dist/packages/ember-testing/lib/helpers/pause_test.js +2 -1
  103. package/dist/packages/ember-testing/lib/helpers/visit.js +4 -3
  104. package/dist/packages/ember-testing/lib/helpers/wait.js +4 -3
  105. package/dist/packages/ember-testing/lib/initializers.js +15 -8
  106. package/dist/packages/ember-testing/lib/setup_for_testing.js +1 -1
  107. package/dist/packages/ember-testing/lib/test/run.js +1 -1
  108. package/dist/packages/router_js/index.js +2 -1
  109. package/dist/packages/shared-chunks/{alias-By_2yu5c.js → alias-Dri0koi2.js} +5 -3
  110. package/dist/packages/shared-chunks/array-3xbmc_4J.js +119 -0
  111. package/dist/packages/shared-chunks/{cache-gDE3bkXq.js → cache-BESCGvbE.js} +667 -1529
  112. package/dist/packages/shared-chunks/{core_view-Cxne2_wu.js → chunk-3SQBS3Y5-Cj4eryg1.js} +1 -88
  113. package/dist/packages/shared-chunks/{index-BXPoca1S.js → index-Llq6dmgX.js} +40 -4660
  114. package/dist/packages/shared-chunks/{is_proxy-Dmis-70B.js → is_proxy-DjvCKvd5.js} +1 -1
  115. package/dist/packages/shared-chunks/{mandatory-setter-1UQhiJOb.js → mandatory-setter-BiXq-dpN.js} +2 -1
  116. package/dist/packages/shared-chunks/{name-z9D9Yibn.js → name-Dx2bGFVv.js} +1 -1
  117. package/dist/packages/shared-chunks/{namespace_search-CBgHTkDh.js → namespace_search-btMaPM-_.js} +2 -2
  118. package/dist/packages/shared-chunks/{property_set-CW4q-uo4.js → property_set-BapAkp3X.js} +5 -4
  119. package/dist/packages/shared-chunks/{registry-DzfcDwii.js → registry-B8WARvkP.js} +3 -2
  120. package/dist/packages/shared-chunks/{router-B-Q1aYBn.js → router-DrLZsJeE.js} +2 -482
  121. package/dist/packages/shared-chunks/{set_properties-DvalyQdu.js → set_properties-BScfxzvI.js} +2 -2
  122. package/dist/packages/shared-chunks/setup-registry-du4pSGZi.js +48 -0
  123. package/dist/packages/shared-chunks/{to-string-D8i3mjEU.js → to-string-B1BmwUkt.js} +1 -1
  124. package/dist/packages/shared-chunks/unrecognized-url-error-zpz-JEoG.js +484 -0
  125. package/docs/data.json +152 -142
  126. package/package.json +2 -2
  127. package/types/stable/@ember/-internals/metal/lib/array.d.ts +1 -2
  128. package/types/stable/@ember/-internals/metal/lib/object-at.d.ts +4 -0
  129. package/types/stable/@ember/-internals/metal/lib/observer.d.ts +2 -1
  130. package/types/stable/@ember/array/index.d.ts +1 -1
  131. package/types/stable/@ember/array/make.d.ts +3 -0
  132. package/types/stable/@ember/debug/index.d.ts +3 -7
  133. package/types/stable/@ember/debug/lib/assert.d.ts +8 -0
  134. package/types/stable/@ember/engine/index.d.ts +1 -1
  135. package/types/stable/@ember/engine/instance.d.ts +2 -2
  136. package/types/stable/@ember/engine/parent.d.ts +3 -0
  137. package/types/stable/@ember/modifier/index.d.ts +1 -3
  138. package/types/stable/@ember/modifier/on.d.ts +5 -0
  139. package/types/stable/@ember/routing/lib/routing-service.d.ts +1 -1
  140. package/types/stable/@ember/routing/route.d.ts +2 -3
  141. package/types/stable/@ember/routing/router-service.d.ts +1 -1
  142. package/types/stable/@ember/routing/router.d.ts +4 -4
  143. package/types/stable/ember/barrel.d.ts +1 -1
  144. package/types/stable/ember/index.d.ts +1 -1
  145. package/types/stable/index.d.ts +5 -0
  146. package/dist/packages/shared-chunks/index-DTxy4Zgx.js +0 -641
  147. package/dist/packages/shared-chunks/index-PYiGj1jp.js +0 -2071
@@ -1,70 +1,65 @@
1
1
  import { templateFactory, programCompilationContext } from '../@glimmer/opcode-compiler/index.js';
2
- import { g as getFactoryFor, p as privatize, R as Registry } from './registry-DzfcDwii.js';
3
- import { a as assert, w as warn, b as inspect, h as debugFreeze, d as deprecate, i as info } from './index-DTxy4Zgx.js';
4
- import { on as on$1, reifyPositional, normalizeProperty, EMPTY_ARGS, createCapturedArgs, EMPTY_POSITIONAL, curry, hash, array, concat, fn, get as get$1, templateOnlyComponent, TEMPLATE_ONLY_COMPONENT_MANAGER, runtimeContext, DOMTreeConstruction, DOMChanges, clientBuilder, inTransaction, renderMain, rehydrationBuilder } from '../@glimmer/runtime/index.js';
5
- import { a0 as tracked, g as get, j as join, Q as PROPERTY_DID_CHANGE, t as tagForObject, R as objectAt, a as tagForProperty, _ as _backburner, a6 as _getProp, s as schedule, Z as _getCurrentRunLoop, ac as flushAsyncObservers, N as once, B as descriptorForProperty, d as defineProperty, x as addObserver, c as computed, O as run, ag as scheduleOnce, ah as cancel } from './cache-gDE3bkXq.js';
2
+ import { g as getFactoryFor, p as privatize } from './registry-B8WARvkP.js';
3
+ import { warn, debugFreeze, deprecate } from '../@ember/debug/index.js';
4
+ import { reifyPositional, normalizeProperty, EMPTY_ARGS, createCapturedArgs, EMPTY_POSITIONAL, curry, hash, array, concat, fn, get as get$1, templateOnlyComponent, TEMPLATE_ONLY_COMPONENT_MANAGER, on as on$1, runtimeContext, DOMTreeConstruction, DOMChanges, clientBuilder, inTransaction, renderMain } from '../@glimmer/runtime/index.js';
5
+ import { join, _backburner, schedule, _getCurrentRunLoop } from '../@ember/runloop/index.js';
6
6
  import { valueForRef, isConstRef, createConstRef, isUpdatableRef, updateRef, createPrimitiveRef, childRefFor, createComputeRef, childRefFromParts, isInvokableRef, createUnboundRef, createInvokableRef, createReadOnlyRef, createDebugAliasRef, UNDEFINED_REFERENCE } from '../@glimmer/reference/index.js';
7
7
  import { untrack, consumeTag, tagFor, createCache, getValue, valueForTag, beginUntrackFrame, endUntrackFrame, beginTrackFrame, endTrackFrame, validateTag, createTag, dirtyTag as DIRTY_TAG$1, CONSTANT_TAG, isTracking, debug, createUpdatableTag, CURRENT_TAG } from '../@glimmer/validator/index.js';
8
8
  import { isDevelopingApp } from '@embroider/macros';
9
- import { setModifierManager as setModifierManager$1, setInternalComponentManager, setComponentTemplate, setInternalHelperManager, setHelperManager, getInternalHelperManager, helperCapabilities, capabilityFlagsFrom, setInternalModifierManager, getInternalComponentManager, getComponentTemplate } from '../@glimmer/manager/index.js';
9
+ import { setInternalComponentManager, setComponentTemplate, setInternalHelperManager, setHelperManager, getInternalHelperManager, helperCapabilities, capabilityFlagsFrom, setInternalModifierManager, getInternalComponentManager, getComponentTemplate } from '../@glimmer/manager/index.js';
10
10
  import { h as hasDOM } from './index-BGP1rw3B.js';
11
- import { b as action$1, i as isArray, E as EmberObject, t as typeOf, A } from './index-PYiGj1jp.js';
12
- import { isSimpleClick, getViewElement, clearElementView, clearViewElement, addChildView, setViewElement, setElementView, constructStyleDeprecationMessage, getViewId } from '../@ember/-internals/views/lib/system/utils.js';
11
+ import { action as action$1 } from '../@ember/object/index.js';
12
+ import { on } from '../@ember/modifier/on.js';
13
13
  import '../@ember/-internals/meta/lib/meta.js';
14
- import { g as guidFor, a as getDebugName, e as isObject, u as uuid, l as lookupDescriptor } from './mandatory-setter-1UQhiJOb.js';
14
+ import { g as guidFor, a as getDebugName, e as isObject, u as uuid } from './mandatory-setter-BiXq-dpN.js';
15
15
  import { registerDestructor, associateDestroyableChild, destroy } from '../@glimmer/destroyable/index.js';
16
+ import { S as tracked, g as get, Q as PROPERTY_DID_CHANGE, t as tagForObject, o as objectAt, a as tagForProperty, V as _getProp } from './cache-BESCGvbE.js';
16
17
  import { E as ENV } from './env-BJLX2Arx.js';
18
+ import { setOwner, getOwner, isFactory } from '../@ember/-internals/owner/index.js';
19
+ import { assert } from '../@ember/debug/lib/assert.js';
20
+ import { d as decorateFieldV2, i as initializeDeferredDecorator, a as decorateMethodV2 } from './chunk-3SQBS3Y5-Cj4eryg1.js';
21
+ import { isSimpleClick, getViewElement, clearElementView, clearViewElement, addChildView, setViewElement, setElementView, constructStyleDeprecationMessage, getViewId } from '../@ember/-internals/views/lib/system/utils.js';
17
22
  import ActionManager from '../@ember/-internals/views/lib/system/action_manager.js';
18
- import ComponentLookup from '../@ember/-internals/views/lib/component_lookup.js';
19
- import { d as decorateFieldV2, i as initializeDeferredDecorator, a as decorateMethodV2, C as CoreView } from './core_view-Cxne2_wu.js';
23
+ import '../@ember/-internals/views/lib/component_lookup.js';
24
+ import CoreView from '../@ember/-internals/views/lib/views/core_view.js';
20
25
  import ClassNamesSupport from '../@ember/-internals/views/lib/mixins/class_names_support.js';
21
26
  import ChildViewsSupport from '../@ember/-internals/views/lib/mixins/child_views_support.js';
22
27
  import ViewStateSupport from '../@ember/-internals/views/lib/mixins/view_state_support.js';
23
28
  import ViewMixin from '../@ember/-internals/views/lib/mixins/view_support.js';
24
29
  import ActionSupport from '../@ember/-internals/views/lib/mixins/action_support.js';
25
- import { getEngineParent, ENGINE_PARENT, setEngineParent } from '../@ember/engine/lib/engine-parent.js';
26
- import { c as canInvoke } from './invoke-BjRgvK2V.js';
27
- import Controller from '../@ember/controller/index.js';
28
- import Namespace from '../@ember/application/namespace.js';
29
- import DAG from '../dag-map/index.js';
30
- import ContainerDebugAdapter from '../@ember/debug/container-debug-adapter.js';
31
- import RegistryProxyMixin from '../@ember/-internals/runtime/lib/mixins/registry_proxy.js';
32
- import ContainerProxyMixin from '../@ember/-internals/runtime/lib/mixins/container_proxy.js';
30
+ import { getEngineParent } from '../@ember/engine/lib/engine-parent.js';
31
+ import { flaggedInstrument, _instrumentStart } from '../@ember/instrumentation/index.js';
32
+ import { service } from '../@ember/service/index.js';
33
+ import inspect from '../@ember/debug/lib/inspect.js';
34
+ import '../@ember/-internals/runtime/lib/mixins/registry_proxy.js';
35
+ import '../@ember/-internals/runtime/lib/mixins/container_proxy.js';
33
36
  import '../@ember/-internals/runtime/lib/mixins/comparable.js';
34
- import ActionHandler from '../@ember/-internals/runtime/lib/mixins/action_handler.js';
37
+ import '../@ember/-internals/runtime/lib/mixins/action_handler.js';
35
38
  import { contentFor } from '../@ember/-internals/runtime/lib/mixins/-proxy.js';
36
39
  import '../@ember/enumerable/mutable.js';
37
40
  import TargetActionSupport from '../@ember/-internals/runtime/lib/mixins/target_action_support.js';
38
41
  import '../@ember/-internals/runtime/lib/ext/rsvp.js';
39
- import { setOwner, getOwner, isFactory } from '../@ember/-internals/owner/index.js';
40
- import { a as RSVP, R as RSVP$1 } from './rsvp-DaQAFb0W.js';
41
- import { _ as _setProp, s as set } from './property_set-CW4q-uo4.js';
42
- import '../route-recognizer/index.js';
43
- import { S as STATE_SYMBOL, P as PARAMS_SYMBOL, R as Router, l as logAbort } from './router-B-Q1aYBn.js';
44
- import { readOnly } from '../@ember/object/lib/computed/computed_macros.js';
45
- import Service, { service } from '../@ember/service/index.js';
46
- import { getOwner as getOwner$1 } from '../@ember/owner/index.js';
47
- import BucketCache from '../@ember/routing/lib/cache.js';
48
- import DSLImpl from '../@ember/routing/lib/dsl.js';
49
- import Evented from '../@ember/object/evented.js';
50
- import { i as isProxy } from './is_proxy-Dmis-70B.js';
51
- import { g as getProperties, s as setProperties } from './set_properties-DvalyQdu.js';
52
- import generateController, { generateControllerFactory } from '../@ember/routing/lib/generate_controller.js';
53
- import { deprecateUntil, DEPRECATIONS } from '../@ember/-internals/deprecations/index.js';
54
- import { dependentKeyCompat } from '../@ember/object/compat.js';
55
- import { isTesting } from '../@ember/debug/lib/testing.js';
56
42
  import EventDispatcher from '../@ember/-internals/views/lib/system/event_dispatcher.js';
57
- import { e as enumerableSymbol } from './to-string-D8i3mjEU.js';
58
- import { flaggedInstrument, _instrumentStart } from '../@ember/instrumentation/index.js';
43
+ import { e as enumerableSymbol } from './to-string-B1BmwUkt.js';
59
44
  import { unwrapTemplate, EMPTY_ARRAY as EMPTY_ARRAY$1, dict } from '../@glimmer/util/index.js';
60
45
  import { dasherize } from '../@ember/-internals/string/index.js';
61
46
  import { MUTABLE_CELL } from '../@ember/-internals/views/lib/compat/attrs.js';
47
+ import { deprecateUntil, DEPRECATIONS } from '../@ember/-internals/deprecations/index.js';
62
48
  import { FrameworkObject } from '../@ember/object/-internals.js';
63
49
  import { CurriedType as CurriedTypes } from '../@glimmer/vm/index.js';
64
50
  import { RuntimeOpImpl, artifacts } from '../@glimmer/program/index.js';
65
- import { NodeDOMTreeConstruction, serializeBuilder } from '../@glimmer/node/index.js';
51
+ import { a as RSVP } from './rsvp-DaQAFb0W.js';
52
+ import EngineInstance from '../@ember/engine/instance.js';
53
+ import { NodeDOMTreeConstruction } from '../@glimmer/node/index.js';
54
+ import { _ as _setProp, s as set } from './property_set-BapAkp3X.js';
66
55
  import setGlobalContext from '../@glimmer/global-context/index.js';
67
56
  import { isEmberArray } from '../@ember/array/-internals.js';
57
+ import { i as isProxy } from './is_proxy-DjvCKvd5.js';
58
+ import { isArray } from '../@ember/array/index.js';
59
+ import '../route-recognizer/index.js';
60
+ import './unrecognized-url-error-zpz-JEoG.js';
61
+ import '../@ember/routing/lib/routing-service.js';
62
+ import { generateControllerFactory } from '../@ember/routing/lib/generate_controller.js';
68
63
 
69
64
  const RootTemplate = templateFactory(
70
65
  /*
@@ -77,22 +72,6 @@ const RootTemplate = templateFactory(
77
72
  "isStrictMode": true
78
73
  });
79
74
 
80
- // In normal TypeScript, this modifier is essentially an opaque token that just
81
- // needs to be importable. Declaring it with a unique interface like this,
82
- // however, gives tools like Glint (that *do* have a richer notion of what it
83
- // is) a place to install more detailed type information.
84
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
85
-
86
- // SAFETY: at the time of writing, the cast here is from `{}` to `OnModifier`,
87
- // which makes it strictly safer to use outside this module because it is not
88
- // usable as "any non-null item", which is what `{}` means, without loss of any
89
- // information from the type itself.
90
- const on = on$1;
91
-
92
- // NOTE: this uses assignment to *require* that the `glimmerSetModifierManager`
93
- // is legally assignable to this type, i.e. that variance is properly upheld.
94
- const setModifierManager = setModifierManager$1;
95
-
96
75
  const InputTemplate = templateFactory(
97
76
  /*
98
77
  <input
@@ -1059,11 +1038,11 @@ class _LinkTo extends InternalComponent {
1059
1038
  }
1060
1039
  get isEngine() {
1061
1040
  let owner = this.owner;
1062
- return owner instanceof EmberEngineInstance && getEngineParent(owner) !== undefined;
1041
+ return getEngineParent(owner) !== undefined;
1063
1042
  }
1064
1043
  get engineMountPoint() {
1065
1044
  let owner = this.owner;
1066
- return owner instanceof EmberEngineInstance ? owner.mountPoint : undefined;
1045
+ return owner.mountPoint;
1067
1046
  }
1068
1047
  classFor(state) {
1069
1048
  let className = this.named(`${state}Class`);
@@ -1800,7 +1779,6 @@ function invokeRef(value) {
1800
1779
  function processComponentArgs(namedArgs) {
1801
1780
  let attrs = Object.create(null);
1802
1781
  let props = Object.create(null);
1803
- props[ARGS] = namedArgs;
1804
1782
  for (let name in namedArgs) {
1805
1783
  let ref = namedArgs[name];
1806
1784
  (isDevelopingApp() && !(ref) && assert('expected ref', ref));
@@ -1980,6 +1958,7 @@ class CurlyComponentManager {
1980
1958
  let capturedArgs = args.named.capture();
1981
1959
  beginTrackFrame();
1982
1960
  let props = processComponentArgs(capturedArgs);
1961
+ props[ARGS] = capturedArgs;
1983
1962
  let argsTag = endTrackFrame();
1984
1963
 
1985
1964
  // Alias `id` argument to `elementId` property on the component instance.
@@ -3652,7 +3631,7 @@ class OutletComponentManager {
3652
3631
  let parentOwner = parentState && parentState.render && parentState.render.owner;
3653
3632
  let currentOwner = valueForRef(currentStateRef).render.owner;
3654
3633
  if (parentOwner && parentOwner !== currentOwner) {
3655
- (isDevelopingApp() && !(currentOwner instanceof EmberEngineInstance) && assert('Expected currentOwner to be an EngineInstance', currentOwner instanceof EmberEngineInstance));
3634
+ (isDevelopingApp() && !(currentOwner instanceof EngineInstance) && assert('Expected currentOwner to be an EngineInstance', currentOwner instanceof EngineInstance));
3656
3635
  let mountPoint = currentOwner.mountPoint;
3657
3636
  state.engine = currentOwner;
3658
3637
  if (mountPoint) {
@@ -4595,7 +4574,7 @@ class MountManager {
4595
4574
  // mount is a runtime helper, this shouldn't use dynamic layout
4596
4575
  // we should resolve the engine app template in the helper
4597
4576
  // it also should use the owner that looked up the mount helper.
4598
- (isDevelopingApp() && !(owner instanceof EmberEngineInstance) && assert('Expected owner to be an EngineInstance', owner instanceof EmberEngineInstance));
4577
+ (isDevelopingApp() && !(owner instanceof EngineInstance) && assert('Expected owner to be an EngineInstance', owner instanceof EngineInstance));
4599
4578
  let engine = owner.buildChildEngineInstance(name);
4600
4579
  engine.boot();
4601
4580
  let applicationFactory = engine.factoryFor(`controller:application`);
@@ -5515,4603 +5494,4 @@ const OutletTemplate = templateFactory(
5515
5494
  "isStrictMode": true
5516
5495
  });
5517
5496
 
5518
- function setupApplicationRegistry(registry) {
5519
- // because we are using injections we can't use instantiate false
5520
- // we need to use bind() to copy the function so factory for
5521
- // association won't leak
5522
- registry.register('service:-dom-builder', {
5523
- // Additionally, we *must* constrain this to require `props` on create, else
5524
- // we *know* it cannot have an owner.
5525
- create(props) {
5526
- let owner = getOwner(props);
5527
- (isDevelopingApp() && !(owner) && assert('DomBuilderService is unexpectedly missing an owner', owner));
5528
- let env = owner.lookup('-environment:main');
5529
- switch (env._renderMode) {
5530
- case 'serialize':
5531
- return serializeBuilder.bind(null);
5532
- case 'rehydrate':
5533
- return rehydrationBuilder.bind(null);
5534
- default:
5535
- return clientBuilder.bind(null);
5536
- }
5537
- }
5538
- });
5539
- registry.register(privatize`template:-root`, RootTemplate);
5540
- registry.register('renderer:-dom', Renderer);
5541
- }
5542
- function setupEngineRegistry(registry) {
5543
- registry.optionsForType('template', {
5544
- instantiate: false
5545
- });
5546
- registry.register('view:-outlet', OutletView);
5547
- registry.register('template:-outlet', OutletTemplate);
5548
- registry.optionsForType('helper', {
5549
- instantiate: false
5550
- });
5551
- registry.register('component:input', Input);
5552
- registry.register('component:link-to', LinkTo);
5553
- registry.register('component:textarea', Textarea);
5554
- }
5555
-
5556
- function props(obj) {
5557
- let properties = [];
5558
- for (let key in obj) {
5559
- properties.push(key);
5560
- }
5561
- return properties;
5562
- }
5563
-
5564
- /**
5565
- @module @ember/engine
5566
- */
5567
-
5568
- /**
5569
- The `Engine` class contains core functionality for both applications and
5570
- engines.
5571
-
5572
- Each engine manages a registry that's used for dependency injection and
5573
- exposed through `RegistryProxy`.
5574
-
5575
- Engines also manage initializers and instance initializers.
5576
-
5577
- Engines can spawn `EngineInstance` instances via `buildInstance()`.
5578
-
5579
- @class Engine
5580
- @extends Ember.Namespace
5581
- @uses RegistryProxyMixin
5582
- @public
5583
- */
5584
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
5585
-
5586
- class Engine extends Namespace.extend(RegistryProxyMixin) {
5587
- static initializers = Object.create(null);
5588
- static instanceInitializers = Object.create(null);
5589
-
5590
- /**
5591
- The goal of initializers should be to register dependencies and injections.
5592
- This phase runs once. Because these initializers may load code, they are
5593
- allowed to defer application readiness and advance it. If you need to access
5594
- the container or store you should use an InstanceInitializer that will be run
5595
- after all initializers and therefore after all code is loaded and the app is
5596
- ready.
5597
- Initializer receives an object which has the following attributes:
5598
- `name`, `before`, `after`, `initialize`. The only required attribute is
5599
- `initialize`, all others are optional.
5600
- * `name` allows you to specify under which name the initializer is registered.
5601
- This must be a unique name, as trying to register two initializers with the
5602
- same name will result in an error.
5603
- ```app/initializer/named-initializer.js
5604
- import { debug } from '@ember/debug';
5605
- export function initialize() {
5606
- debug('Running namedInitializer!');
5607
- }
5608
- export default {
5609
- name: 'named-initializer',
5610
- initialize
5611
- };
5612
- ```
5613
- * `before` and `after` are used to ensure that this initializer is ran prior
5614
- or after the one identified by the value. This value can be a single string
5615
- or an array of strings, referencing the `name` of other initializers.
5616
- An example of ordering initializers, we create an initializer named `first`:
5617
- ```app/initializer/first.js
5618
- import { debug } from '@ember/debug';
5619
- export function initialize() {
5620
- debug('First initializer!');
5621
- }
5622
- export default {
5623
- name: 'first',
5624
- initialize
5625
- };
5626
- ```
5627
- ```bash
5628
- // DEBUG: First initializer!
5629
- ```
5630
- We add another initializer named `second`, specifying that it should run
5631
- after the initializer named `first`:
5632
- ```app/initializer/second.js
5633
- import { debug } from '@ember/debug';
5634
- export function initialize() {
5635
- debug('Second initializer!');
5636
- }
5637
- export default {
5638
- name: 'second',
5639
- after: 'first',
5640
- initialize
5641
- };
5642
- ```
5643
- ```
5644
- // DEBUG: First initializer!
5645
- // DEBUG: Second initializer!
5646
- ```
5647
- Afterwards we add a further initializer named `pre`, this time specifying
5648
- that it should run before the initializer named `first`:
5649
- ```app/initializer/pre.js
5650
- import { debug } from '@ember/debug';
5651
- export function initialize() {
5652
- debug('Pre initializer!');
5653
- }
5654
- export default {
5655
- name: 'pre',
5656
- before: 'first',
5657
- initialize
5658
- };
5659
- ```
5660
- ```bash
5661
- // DEBUG: Pre initializer!
5662
- // DEBUG: First initializer!
5663
- // DEBUG: Second initializer!
5664
- ```
5665
- Finally we add an initializer named `post`, specifying it should run after
5666
- both the `first` and the `second` initializers:
5667
- ```app/initializer/post.js
5668
- import { debug } from '@ember/debug';
5669
- export function initialize() {
5670
- debug('Post initializer!');
5671
- }
5672
- export default {
5673
- name: 'post',
5674
- after: ['first', 'second'],
5675
- initialize
5676
- };
5677
- ```
5678
- ```bash
5679
- // DEBUG: Pre initializer!
5680
- // DEBUG: First initializer!
5681
- // DEBUG: Second initializer!
5682
- // DEBUG: Post initializer!
5683
- ```
5684
- * `initialize` is a callback function that receives one argument,
5685
- `application`, on which you can operate.
5686
- Example of using `application` to register an adapter:
5687
- ```app/initializer/api-adapter.js
5688
- import ApiAdapter from '../utils/api-adapter';
5689
- export function initialize(application) {
5690
- application.register('api-adapter:main', ApiAdapter);
5691
- }
5692
- export default {
5693
- name: 'post',
5694
- after: ['first', 'second'],
5695
- initialize
5696
- };
5697
- ```
5698
- @method initializer
5699
- @param initializer {Object}
5700
- @public
5701
- */
5702
-
5703
- static initializer = buildInitializerMethod('initializers', 'initializer');
5704
-
5705
- /**
5706
- Instance initializers run after all initializers have run. Because
5707
- instance initializers run after the app is fully set up. We have access
5708
- to the store, container, and other items. However, these initializers run
5709
- after code has loaded and are not allowed to defer readiness.
5710
- Instance initializer receives an object which has the following attributes:
5711
- `name`, `before`, `after`, `initialize`. The only required attribute is
5712
- `initialize`, all others are optional.
5713
- * `name` allows you to specify under which name the instanceInitializer is
5714
- registered. This must be a unique name, as trying to register two
5715
- instanceInitializer with the same name will result in an error.
5716
- ```app/initializer/named-instance-initializer.js
5717
- import { debug } from '@ember/debug';
5718
- export function initialize() {
5719
- debug('Running named-instance-initializer!');
5720
- }
5721
- export default {
5722
- name: 'named-instance-initializer',
5723
- initialize
5724
- };
5725
- ```
5726
- * `before` and `after` are used to ensure that this initializer is ran prior
5727
- or after the one identified by the value. This value can be a single string
5728
- or an array of strings, referencing the `name` of other initializers.
5729
- * See Application.initializer for discussion on the usage of before
5730
- and after.
5731
- Example instanceInitializer to preload data into the store.
5732
- ```app/initializer/preload-data.js
5733
- export function initialize(application) {
5734
- var userConfig, userConfigEncoded, store;
5735
- // We have a HTML escaped JSON representation of the user's basic
5736
- // configuration generated server side and stored in the DOM of the main
5737
- // index.html file. This allows the app to have access to a set of data
5738
- // without making any additional remote calls. Good for basic data that is
5739
- // needed for immediate rendering of the page. Keep in mind, this data,
5740
- // like all local models and data can be manipulated by the user, so it
5741
- // should not be relied upon for security or authorization.
5742
- // Grab the encoded data from the meta tag
5743
- userConfigEncoded = document.querySelector('head meta[name=app-user-config]').attr('content');
5744
- // Unescape the text, then parse the resulting JSON into a real object
5745
- userConfig = JSON.parse(unescape(userConfigEncoded));
5746
- // Lookup the store
5747
- store = application.lookup('service:store');
5748
- // Push the encoded JSON into the store
5749
- store.pushPayload(userConfig);
5750
- }
5751
- export default {
5752
- name: 'named-instance-initializer',
5753
- initialize
5754
- };
5755
- ```
5756
- @method instanceInitializer
5757
- @param instanceInitializer
5758
- @public
5759
- */
5760
- static instanceInitializer = buildInitializerMethod('instanceInitializers', 'instance initializer');
5761
-
5762
- /**
5763
- This creates a registry with the default Ember naming conventions.
5764
- It also configures the registry:
5765
- * registered views are created every time they are looked up (they are
5766
- not singletons)
5767
- * registered templates are not factories; the registered value is
5768
- returned directly.
5769
- * the router receives the application as its `namespace` property
5770
- * all controllers receive the router as their `target` and `controllers`
5771
- properties
5772
- * all controllers receive the application as their `namespace` property
5773
- * the application view receives the application controller as its
5774
- `controller` property
5775
- * the application view receives the application template as its
5776
- `defaultTemplate` property
5777
- @method buildRegistry
5778
- @static
5779
- @param {Application} namespace the application for which to
5780
- build the registry
5781
- @return {Ember.Registry} the built registry
5782
- @private
5783
- */
5784
- static buildRegistry(namespace) {
5785
- let registry = new Registry({
5786
- resolver: resolverFor(namespace)
5787
- });
5788
- registry.set = set;
5789
- registry.register('application:main', namespace, {
5790
- instantiate: false
5791
- });
5792
- commonSetupRegistry(registry);
5793
- setupEngineRegistry(registry);
5794
- return registry;
5795
- }
5796
-
5797
- /**
5798
- Set this to provide an alternate class to `DefaultResolver`
5799
- @property resolver
5800
- @public
5801
- */
5802
-
5803
- init(properties) {
5804
- super.init(properties);
5805
- this.buildRegistry();
5806
- }
5807
-
5808
- /**
5809
- A private flag indicating whether an engine's initializers have run yet.
5810
- @private
5811
- @property _initializersRan
5812
- */
5813
- _initializersRan = false;
5814
-
5815
- /**
5816
- Ensure that initializers are run once, and only once, per engine.
5817
- @private
5818
- @method ensureInitializers
5819
- */
5820
- ensureInitializers() {
5821
- if (!this._initializersRan) {
5822
- this.runInitializers();
5823
- this._initializersRan = true;
5824
- }
5825
- }
5826
-
5827
- /**
5828
- Create an EngineInstance for this engine.
5829
- @public
5830
- @method buildInstance
5831
- @return {EngineInstance} the engine instance
5832
- */
5833
- buildInstance(options = {}) {
5834
- this.ensureInitializers();
5835
- return EmberEngineInstance.create({
5836
- ...options,
5837
- base: this
5838
- });
5839
- }
5840
-
5841
- /**
5842
- Build and configure the registry for the current engine.
5843
- @private
5844
- @method buildRegistry
5845
- @return {Ember.Registry} the configured registry
5846
- */
5847
- buildRegistry() {
5848
- let registry = this.__registry__ = this.constructor.buildRegistry(this);
5849
- return registry;
5850
- }
5851
-
5852
- /**
5853
- @private
5854
- @method initializer
5855
- */
5856
- initializer(initializer) {
5857
- this.constructor.initializer(initializer);
5858
- }
5859
-
5860
- /**
5861
- @private
5862
- @method instanceInitializer
5863
- */
5864
- instanceInitializer(initializer) {
5865
- this.constructor.instanceInitializer(initializer);
5866
- }
5867
-
5868
- /**
5869
- @private
5870
- @method runInitializers
5871
- */
5872
- runInitializers() {
5873
- this._runInitializer('initializers', (name, initializer) => {
5874
- (isDevelopingApp() && !(initializer) && assert(`No application initializer named '${name}'`, initializer));
5875
- initializer.initialize(this);
5876
- });
5877
- }
5878
-
5879
- /**
5880
- @private
5881
- @since 1.12.0
5882
- @method runInstanceInitializers
5883
- */
5884
- runInstanceInitializers(instance) {
5885
- this._runInitializer('instanceInitializers', (name, initializer) => {
5886
- (isDevelopingApp() && !(initializer) && assert(`No instance initializer named '${name}'`, initializer));
5887
- initializer.initialize(instance);
5888
- });
5889
- }
5890
- _runInitializer(bucketName, cb) {
5891
- let initializersByName = get(this.constructor, bucketName);
5892
- let initializers = props(initializersByName);
5893
- let graph = new DAG();
5894
- let initializer;
5895
- for (let name of initializers) {
5896
- initializer = initializersByName[name];
5897
- (isDevelopingApp() && !(initializer) && assert(`missing ${bucketName}: ${name}`, initializer));
5898
- graph.add(initializer.name, initializer, initializer.before, initializer.after);
5899
- }
5900
- graph.topsort(cb);
5901
- }
5902
- }
5903
-
5904
- /**
5905
- This function defines the default lookup rules for container lookups:
5906
-
5907
- * templates are looked up on `Ember.TEMPLATES`
5908
- * other names are looked up on the application after classifying the name.
5909
- For example, `controller:post` looks up `App.PostController` by default.
5910
- * if the default lookup fails, look for registered classes on the container
5911
-
5912
- This allows the application to register default injections in the container
5913
- that could be overridden by the normal naming convention.
5914
-
5915
- @private
5916
- @method resolverFor
5917
- @param {Ember.Enginer} namespace the namespace to look for classes
5918
- @return {*} the resolved value for a given lookup
5919
- */
5920
- function resolverFor(namespace) {
5921
- let ResolverClass = namespace.Resolver;
5922
- let props = {
5923
- namespace
5924
- };
5925
- return ResolverClass.create(props);
5926
- }
5927
-
5928
- /** @internal */
5929
- function buildInitializerMethod(bucketName, humanName) {
5930
- return function (initializer) {
5931
- // If this is the first initializer being added to a subclass, we are going to reopen the class
5932
- // to make sure we have a new `initializers` object, which extends from the parent class' using
5933
- // prototypal inheritance. Without this, attempting to add initializers to the subclass would
5934
- // pollute the parent class as well as other subclasses.
5935
- // SAFETY: The superclass may be an Engine, we don't call unless we confirmed it was ok.
5936
- let superclass = this.superclass;
5937
- if (superclass[bucketName] !== undefined && superclass[bucketName] === this[bucketName]) {
5938
- let attrs = {
5939
- [bucketName]: Object.create(this[bucketName])
5940
- };
5941
- this.reopenClass(attrs);
5942
- }
5943
- (isDevelopingApp() && !(!this[bucketName][initializer.name]) && assert(`The ${humanName} '${initializer.name}' has already been registered`, !this[bucketName][initializer.name]));
5944
- (isDevelopingApp() && !(canInvoke(initializer, 'initialize')) && assert(`An ${humanName} cannot be registered without an initialize function`, canInvoke(initializer, 'initialize')));
5945
- (isDevelopingApp() && !(initializer.name !== undefined) && assert(`An ${humanName} cannot be registered without a name property`, initializer.name !== undefined));
5946
- let initializers = this[bucketName];
5947
- initializers[initializer.name] = initializer;
5948
- };
5949
- }
5950
- function commonSetupRegistry(registry) {
5951
- registry.optionsForType('component', {
5952
- singleton: false
5953
- });
5954
- registry.optionsForType('view', {
5955
- singleton: false
5956
- });
5957
- registry.register('controller:basic', Controller, {
5958
- instantiate: false
5959
- });
5960
-
5961
- // Register the routing service...
5962
- registry.register('service:-routing', RoutingService);
5963
-
5964
- // DEBUGGING
5965
- registry.register('resolver-for-debugging:main', registry.resolver, {
5966
- instantiate: false
5967
- });
5968
- registry.register('container-debug-adapter:main', ContainerDebugAdapter);
5969
- registry.register('component-lookup:main', ComponentLookup);
5970
- }
5971
-
5972
- /**
5973
- @module @ember/engine
5974
- */
5975
-
5976
- class EngineInstance extends EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin) {
5977
- /**
5978
- @private
5979
- @method setupRegistry
5980
- @param {Registry} registry
5981
- @param {BootOptions} options
5982
- */
5983
- // This is effectively an "abstract" method: it defines the contract a
5984
- // subclass (e.g. `ApplicationInstance`) must follow to implement this
5985
- // behavior, but an `EngineInstance` has no behavior of its own here.
5986
- static setupRegistry(_registry, _options) {}
5987
-
5988
- /**
5989
- The base `Engine` for which this is an instance.
5990
- @property {Engine} engine
5991
- @private
5992
- */
5993
-
5994
- [ENGINE_PARENT];
5995
- _booted = false;
5996
- init(properties) {
5997
- super.init(properties);
5998
-
5999
- // Ensure the guid gets setup for this instance
6000
- guidFor(this);
6001
- this.base ??= this.application;
6002
-
6003
- // Create a per-instance registry that will use the application's registry
6004
- // as a fallback for resolving registrations.
6005
- let registry = this.__registry__ = new Registry({
6006
- fallback: this.base.__registry__
6007
- });
6008
-
6009
- // Create a per-instance container from the instance's registry
6010
- this.__container__ = registry.container({
6011
- owner: this
6012
- });
6013
- this._booted = false;
6014
- }
6015
- _bootPromise = null;
6016
-
6017
- /**
6018
- Initialize the `EngineInstance` and return a promise that resolves
6019
- with the instance itself when the boot process is complete.
6020
- The primary task here is to run any registered instance initializers.
6021
- See the documentation on `BootOptions` for the options it takes.
6022
- @public
6023
- @method boot
6024
- @param options {Object}
6025
- @return {Promise<EngineInstance,Error>}
6026
- */
6027
- boot(options) {
6028
- if (this._bootPromise) {
6029
- return this._bootPromise;
6030
- }
6031
- this._bootPromise = new RSVP$1.Promise(resolve => {
6032
- resolve(this._bootSync(options));
6033
- });
6034
- return this._bootPromise;
6035
- }
6036
-
6037
- /**
6038
- Unfortunately, a lot of existing code assumes booting an instance is
6039
- synchronous – specifically, a lot of tests assume the last call to
6040
- `app.advanceReadiness()` or `app.reset()` will result in a new instance
6041
- being fully-booted when the current runloop completes.
6042
- We would like new code (like the `visit` API) to stop making this
6043
- assumption, so we created the asynchronous version above that returns a
6044
- promise. But until we have migrated all the code, we would have to expose
6045
- this method for use *internally* in places where we need to boot an instance
6046
- synchronously.
6047
- @private
6048
- */
6049
- _bootSync(options) {
6050
- if (this._booted) {
6051
- return this;
6052
- }
6053
- (isDevelopingApp() && !(getEngineParent(this)) && assert("An engine instance's parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.", getEngineParent(this)));
6054
- this.cloneParentDependencies();
6055
- this.setupRegistry(options);
6056
- this.base.runInstanceInitializers(this);
6057
- this._booted = true;
6058
- return this;
6059
- }
6060
- setupRegistry(options = this.__container__.lookup('-environment:main')) {
6061
- this.constructor.setupRegistry(this.__registry__, options);
6062
- }
6063
-
6064
- /**
6065
- Unregister a factory.
6066
- Overrides `RegistryProxy#unregister` in order to clear any cached instances
6067
- of the unregistered factory.
6068
- @public
6069
- @method unregister
6070
- @param {String} fullName
6071
- */
6072
- unregister(fullName) {
6073
- this.__container__.reset(fullName);
6074
-
6075
- // We overwrote this method from RegistryProxyMixin.
6076
- this.__registry__.unregister(fullName);
6077
- }
6078
-
6079
- /**
6080
- Build a new `EngineInstance` that's a child of this instance.
6081
- Engines must be registered by name with their parent engine
6082
- (or application).
6083
- @private
6084
- @method buildChildEngineInstance
6085
- @param name {String} the registered name of the engine.
6086
- @param options {Object} options provided to the engine instance.
6087
- @return {EngineInstance,Error}
6088
- */
6089
- buildChildEngineInstance(name, options = {}) {
6090
- let ChildEngine = this.lookup(`engine:${name}`);
6091
- if (!ChildEngine) {
6092
- throw new Error(`You attempted to mount the engine '${name}', but it is not registered with its parent.`);
6093
- }
6094
- (isDevelopingApp() && !(ChildEngine instanceof Engine) && assert('expected an Engine', ChildEngine instanceof Engine));
6095
- let engineInstance = ChildEngine.buildInstance(options);
6096
- setEngineParent(engineInstance, this);
6097
- return engineInstance;
6098
- }
6099
-
6100
- /**
6101
- Clone dependencies shared between an engine instance and its parent.
6102
- @private
6103
- @method cloneParentDependencies
6104
- */
6105
- cloneParentDependencies() {
6106
- const parent = getEngineParent(this);
6107
- (isDevelopingApp() && !(parent) && assert('expected parent', parent));
6108
- let registrations = ['route:basic', 'service:-routing'];
6109
- registrations.forEach(key => {
6110
- let registration = parent.resolveRegistration(key);
6111
- (isDevelopingApp() && !(isFactory(registration)) && assert('expected registration to be a factory', isFactory(registration)));
6112
- this.register(key, registration);
6113
- });
6114
- let env = parent.lookup('-environment:main');
6115
- this.register('-environment:main', env, {
6116
- instantiate: false
6117
- });
6118
-
6119
- // The type annotation forces TS to (a) validate that these match and (b)
6120
- // *notice* that they match, e.g. below on the `singletons.push()`.
6121
- let singletons = ['router:main', privatize`-bucket-cache:main`, '-view-registry:main', `renderer:-dom`, 'service:-document'];
6122
- if (env['isInteractive']) {
6123
- singletons.push('event_dispatcher:main');
6124
- }
6125
- singletons.forEach(key => {
6126
- // SAFETY: We already expect this to be a singleton
6127
- let singleton = parent.lookup(key);
6128
- this.register(key, singleton, {
6129
- instantiate: false
6130
- });
6131
- });
6132
- }
6133
- }
6134
- const EmberEngineInstance = EngineInstance;
6135
-
6136
- const ALL_PERIODS_REGEX = /\./g;
6137
- function extractRouteArgs(args) {
6138
- // SAFETY: This should just be the same thing
6139
- args = args.slice();
6140
- let possibleOptions = args[args.length - 1];
6141
- let queryParams;
6142
- if (isRouteOptions(possibleOptions)) {
6143
- args.pop(); // Remove options
6144
- queryParams = possibleOptions.queryParams;
6145
- } else {
6146
- queryParams = {};
6147
- }
6148
- let routeName;
6149
- if (typeof args[0] === 'string') {
6150
- routeName = args.shift();
6151
- // We just checked this!
6152
- (isDevelopingApp() && !(typeof routeName === 'string') && assert('routeName is a string', typeof routeName === 'string'));
6153
- }
6154
-
6155
- // SAFTEY: We removed the name and options if they existed, only models left.
6156
- let models = args;
6157
- return {
6158
- routeName,
6159
- models,
6160
- queryParams
6161
- };
6162
- }
6163
- function getActiveTargetName(router) {
6164
- let routeInfos = router.activeTransition ? router.activeTransition[STATE_SYMBOL].routeInfos : router.state.routeInfos;
6165
- let lastRouteInfo = routeInfos[routeInfos.length - 1];
6166
- (isDevelopingApp() && !(lastRouteInfo) && assert('has last route info', lastRouteInfo));
6167
- return lastRouteInfo.name;
6168
- }
6169
- function stashParamNames(router, routeInfos) {
6170
- if (routeInfos['_namesStashed']) {
6171
- return;
6172
- }
6173
-
6174
- // This helper exists because router.js/route-recognizer.js awkwardly
6175
- // keeps separate a routeInfo's list of parameter names depending
6176
- // on whether a URL transition or named transition is happening.
6177
- // Hopefully we can remove this in the future.
6178
- let routeInfo = routeInfos[routeInfos.length - 1];
6179
- (isDevelopingApp() && !(routeInfo) && assert('has route info', routeInfo));
6180
- let targetRouteName = routeInfo.name;
6181
- let recogHandlers = router._routerMicrolib.recognizer.handlersFor(targetRouteName);
6182
- let dynamicParent;
6183
- for (let i = 0; i < routeInfos.length; ++i) {
6184
- let routeInfo = routeInfos[i];
6185
- (isDevelopingApp() && !(routeInfo) && assert('has route info', routeInfo));
6186
- let names = recogHandlers[i].names;
6187
- if (names.length) {
6188
- dynamicParent = routeInfo;
6189
- }
6190
- routeInfo['_names'] = names;
6191
- let route = routeInfo.route;
6192
- route._stashNames(routeInfo, dynamicParent);
6193
- }
6194
- routeInfos['_namesStashed'] = true;
6195
- }
6196
- function _calculateCacheValuePrefix(prefix, part) {
6197
- // calculates the dot separated sections from prefix that are also
6198
- // at the start of part - which gives us the route name
6199
-
6200
- // given : prefix = site.article.comments, part = site.article.id
6201
- // - returns: site.article (use get(values[site.article], 'id') to get the dynamic part - used below)
6202
-
6203
- // given : prefix = site.article, part = site.article.id
6204
- // - returns: site.article. (use get(values[site.article], 'id') to get the dynamic part - used below)
6205
-
6206
- let prefixParts = prefix.split('.');
6207
- let currPrefix = '';
6208
- for (let i = 0; i < prefixParts.length; i++) {
6209
- let currPart = prefixParts.slice(0, i + 1).join('.');
6210
- if (part.indexOf(currPart) !== 0) {
6211
- break;
6212
- }
6213
- currPrefix = currPart;
6214
- }
6215
- return currPrefix;
6216
- }
6217
-
6218
- /*
6219
- Stolen from Controller
6220
- */
6221
- function calculateCacheKey(prefix, parts = [], values) {
6222
- let suffixes = '';
6223
- for (let part of parts) {
6224
- let cacheValuePrefix = _calculateCacheValuePrefix(prefix, part);
6225
- let value;
6226
- if (values) {
6227
- if (cacheValuePrefix && cacheValuePrefix in values) {
6228
- let partRemovedPrefix = part.indexOf(cacheValuePrefix) === 0 ? part.substring(cacheValuePrefix.length + 1) : part;
6229
- value = get(values[cacheValuePrefix], partRemovedPrefix);
6230
- } else {
6231
- value = get(values, part);
6232
- }
6233
- }
6234
- suffixes += `::${part}:${value}`;
6235
- }
6236
- return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-');
6237
- }
6238
-
6239
- /*
6240
- Controller-defined query parameters can come in three shapes:
6241
-
6242
- Array
6243
- queryParams: ['foo', 'bar']
6244
- Array of simple objects where value is an alias
6245
- queryParams: [
6246
- {
6247
- 'foo': 'rename_foo_to_this'
6248
- },
6249
- {
6250
- 'bar': 'call_bar_this_instead'
6251
- }
6252
- ]
6253
- Array of fully defined objects
6254
- queryParams: [
6255
- {
6256
- 'foo': {
6257
- as: 'rename_foo_to_this'
6258
- },
6259
- }
6260
- {
6261
- 'bar': {
6262
- as: 'call_bar_this_instead',
6263
- scope: 'controller'
6264
- }
6265
- }
6266
- ]
6267
-
6268
- This helper normalizes all three possible styles into the
6269
- 'Array of fully defined objects' style.
6270
- */
6271
- function normalizeControllerQueryParams(queryParams) {
6272
- let qpMap = {};
6273
- for (let queryParam of queryParams) {
6274
- accumulateQueryParamDescriptors(queryParam, qpMap);
6275
- }
6276
- return qpMap;
6277
- }
6278
- function accumulateQueryParamDescriptors(_desc, accum) {
6279
- let desc = typeof _desc === 'string' ? {
6280
- [_desc]: {
6281
- as: null
6282
- }
6283
- } : _desc;
6284
- for (let key in desc) {
6285
- if (!Object.prototype.hasOwnProperty.call(desc, key)) {
6286
- return;
6287
- }
6288
- let _singleDesc = desc[key];
6289
- let singleDesc = typeof _singleDesc === 'string' ? {
6290
- as: _singleDesc
6291
- } : _singleDesc;
6292
- let partialVal = accum[key] || {
6293
- as: null,
6294
- scope: 'model'
6295
- };
6296
- let val = {
6297
- ...partialVal,
6298
- ...singleDesc
6299
- };
6300
- accum[key] = val;
6301
- }
6302
- }
6303
-
6304
- /*
6305
- Check if a routeName resembles a url instead
6306
-
6307
- @private
6308
- */
6309
- function resemblesURL(str) {
6310
- return typeof str === 'string' && (str === '' || str[0] === '/');
6311
- }
6312
-
6313
- /*
6314
- Returns an arguments array where the route name arg is prefixed based on the mount point
6315
-
6316
- @private
6317
- */
6318
- function prefixRouteNameArg(route, args) {
6319
- let routeName;
6320
- let owner = getOwner(route);
6321
- (isDevelopingApp() && !(owner instanceof EmberEngineInstance) && assert('Expected route to have EngineInstance as owner', owner instanceof EmberEngineInstance));
6322
- let prefix = owner.mountPoint;
6323
-
6324
- // only alter the routeName if it's actually referencing a route.
6325
- if (owner.routable && typeof args[0] === 'string') {
6326
- routeName = args[0];
6327
- if (resemblesURL(routeName)) {
6328
- throw new Error('Programmatic transitions by URL cannot be used within an Engine. Please use the route name instead.');
6329
- } else {
6330
- routeName = `${prefix}.${routeName}`;
6331
- args[0] = routeName;
6332
- }
6333
- }
6334
- return args;
6335
- }
6336
- function shallowEqual(a, b) {
6337
- let aCount = 0;
6338
- let bCount = 0;
6339
- for (let kA in a) {
6340
- if (Object.prototype.hasOwnProperty.call(a, kA)) {
6341
- if (a[kA] !== b[kA]) {
6342
- return false;
6343
- }
6344
- aCount++;
6345
- }
6346
- }
6347
- for (let kB in b) {
6348
- if (Object.prototype.hasOwnProperty.call(b, kB)) {
6349
- bCount++;
6350
- }
6351
- }
6352
- return aCount === bCount;
6353
- }
6354
- function isRouteOptions(value) {
6355
- if (value && typeof value === 'object') {
6356
- let qps = value.queryParams;
6357
- if (qps && typeof qps === 'object') {
6358
- return Object.keys(qps).every(k => typeof k === 'string');
6359
- }
6360
- }
6361
- return false;
6362
- }
6363
-
6364
- class RouterState {
6365
- router;
6366
- emberRouter;
6367
- routerJsState;
6368
- constructor(emberRouter, router, routerJsState) {
6369
- this.emberRouter = emberRouter;
6370
- this.router = router;
6371
- this.routerJsState = routerJsState;
6372
- }
6373
- isActiveIntent(routeName, models, queryParams) {
6374
- let state = this.routerJsState;
6375
- if (!this.router.isActiveIntent(routeName, models, undefined, state)) {
6376
- return false;
6377
- }
6378
- if (queryParams !== undefined && Object.keys(queryParams).length > 0) {
6379
- let visibleQueryParams = Object.assign({}, queryParams);
6380
- this.emberRouter._prepareQueryParams(routeName, models, visibleQueryParams);
6381
- return shallowEqual(visibleQueryParams, state.queryParams);
6382
- }
6383
- return true;
6384
- }
6385
- }
6386
-
6387
- function isStoreLike(store) {
6388
- return typeof store === 'object' && store !== null && typeof store.find === 'function';
6389
- }
6390
- const RENDER = Symbol('render');
6391
- const RENDER_STATE = Symbol('render-state');
6392
-
6393
- /**
6394
- @module @ember/routing/route
6395
- */
6396
-
6397
- /**
6398
- The `Route` class is used to define individual routes. Refer to
6399
- the [routing guide](https://guides.emberjs.com/release/routing/) for documentation.
6400
-
6401
- @class Route
6402
- @extends EmberObject
6403
- @uses ActionHandler
6404
- @uses Evented
6405
- @since 1.0.0
6406
- @public
6407
- */
6408
-
6409
- class Route extends EmberObject.extend(ActionHandler, Evented) {
6410
- static isRouteFactory = true;
6411
-
6412
- // These properties will end up appearing in the public interface because we
6413
- // `implements IRoute` from `router.js`, which has them as part of *its*
6414
- // public contract. We mark them as `@internal` so they at least signal to
6415
- // people subclassing `Route` that they should not use them.
6416
- /** @internal */
6417
- context = {};
6418
- /** @internal */
6419
-
6420
- /** @internal */
6421
- _bucketCache;
6422
- /** @internal */
6423
- _internalName;
6424
- _names;
6425
- _router;
6426
- constructor(owner) {
6427
- super(owner);
6428
- if (owner) {
6429
- let router = owner.lookup('router:main');
6430
- let bucketCache = owner.lookup(privatize`-bucket-cache:main`);
6431
- (isDevelopingApp() && !(router instanceof EmberRouter$1 && bucketCache instanceof BucketCache) && assert('ROUTER BUG: Expected route injections to be defined on the route. This is an internal bug, please open an issue on Github if you see this message!', router instanceof EmberRouter$1 && bucketCache instanceof BucketCache));
6432
- this._router = router;
6433
- this._bucketCache = bucketCache;
6434
- this._topLevelViewTemplate = owner.lookup('template:-outlet');
6435
- this._environment = owner.lookup('-environment:main');
6436
- }
6437
- }
6438
-
6439
- /**
6440
- A hook you can implement to convert the route's model into parameters
6441
- for the URL.
6442
- ```app/router.js
6443
- // ...
6444
- Router.map(function() {
6445
- this.route('post', { path: '/posts/:post_id' });
6446
- });
6447
- ```
6448
- ```app/routes/post.js
6449
- import Route from '@ember/routing/route';
6450
- export default class PostRoute extends Route {
6451
- model({ post_id }) {
6452
- // the server returns `{ id: 12 }`
6453
- return fetch(`/posts/${post_id}`;
6454
- }
6455
- serialize(model) {
6456
- // this will make the URL `/posts/12`
6457
- return { post_id: model.id };
6458
- }
6459
- }
6460
- ```
6461
- The default `serialize` method will insert the model's `id` into the
6462
- route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
6463
- If the route has multiple dynamic segments or does not contain '_id', `serialize`
6464
- will return `getProperties(model, params)`
6465
- This method is called when `transitionTo` is called with a context
6466
- in order to populate the URL.
6467
- @method serialize
6468
- @param {Object} model the routes model
6469
- @param {Array} params an Array of parameter names for the current
6470
- route (in the example, `['post_id']`.
6471
- @return {Object} the serialized parameters
6472
- @since 1.0.0
6473
- @public
6474
- */
6475
- serialize(model, params) {
6476
- if (params.length < 1 || !model) {
6477
- return;
6478
- }
6479
- let object = {};
6480
- if (params.length === 1) {
6481
- let [name] = params;
6482
- (isDevelopingApp() && !(name) && assert('has name', name));
6483
- if (typeof model === 'object' && name in model) {
6484
- object[name] = get(model, name);
6485
- } else if (/_id$/.test(name)) {
6486
- object[name] = get(model, 'id');
6487
- } else if (isProxy(model)) {
6488
- object[name] = get(model, name);
6489
- }
6490
- } else {
6491
- object = getProperties(model, params);
6492
- }
6493
- return object;
6494
- }
6495
-
6496
- /**
6497
- Configuration hash for this route's queryParams. The possible
6498
- configuration options and their defaults are as follows
6499
- (assuming a query param whose controller property is `page`):
6500
- ```javascript
6501
- queryParams = {
6502
- page: {
6503
- // By default, controller query param properties don't
6504
- // cause a full transition when they are changed, but
6505
- // rather only cause the URL to update. Setting
6506
- // `refreshModel` to true will cause an "in-place"
6507
- // transition to occur, whereby the model hooks for
6508
- // this route (and any child routes) will re-fire, allowing
6509
- // you to reload models (e.g., from the server) using the
6510
- // updated query param values.
6511
- refreshModel: false,
6512
- // By default, changes to controller query param properties
6513
- // cause the URL to update via `pushState`, which means an
6514
- // item will be added to the browser's history, allowing
6515
- // you to use the back button to restore the app to the
6516
- // previous state before the query param property was changed.
6517
- // Setting `replace` to true will use `replaceState` (or its
6518
- // hash location equivalent), which causes no browser history
6519
- // item to be added. This options name and default value are
6520
- // the same as the `link-to` helper's `replace` option.
6521
- replace: false,
6522
- // By default, the query param URL key is the same name as
6523
- // the controller property name. Use `as` to specify a
6524
- // different URL key.
6525
- as: 'page'
6526
- }
6527
- };
6528
- ```
6529
- @property queryParams
6530
- @for Route
6531
- @type Object
6532
- @since 1.6.0
6533
- @public
6534
- */
6535
- // Set in reopen so it can be overriden with extend
6536
-
6537
- /**
6538
- The name of the template to use by default when rendering this route's
6539
- template.
6540
- ```app/routes/posts/list.js
6541
- import Route from '@ember/routing/route';
6542
- export default class PostsListRoute extends Route {
6543
- templateName = 'posts/list';
6544
- }
6545
- ```
6546
- ```app/routes/posts/index.js
6547
- import PostsListRoute from '../posts/list';
6548
- export default class PostsIndexRoute extends PostsListRoute {};
6549
- ```
6550
- ```app/routes/posts/archived.js
6551
- import PostsListRoute from '../posts/list';
6552
- export default class PostsArchivedRoute extends PostsListRoute {};
6553
- ```
6554
- @property templateName
6555
- @type String
6556
- @default null
6557
- @since 1.4.0
6558
- @public
6559
- */
6560
- // Set in reopen so it can be overriden with extend
6561
-
6562
- /**
6563
- The name of the controller to associate with this route.
6564
- By default, Ember will lookup a route's controller that matches the name
6565
- of the route (i.e. `posts.new`). However,
6566
- if you would like to define a specific controller to use, you can do so
6567
- using this property.
6568
- This is useful in many ways, as the controller specified will be:
6569
- * passed to the `setupController` method.
6570
- * used as the controller for the template being rendered by the route.
6571
- * returned from a call to `controllerFor` for the route.
6572
- @property controllerName
6573
- @type String
6574
- @default null
6575
- @since 1.4.0
6576
- @public
6577
- */
6578
- // Set in reopen so it can be overriden with extend
6579
-
6580
- /**
6581
- The controller associated with this route.
6582
- Example
6583
- ```app/routes/form.js
6584
- import Route from '@ember/routing/route';
6585
- import { action } from '@ember/object';
6586
- export default class FormRoute extends Route {
6587
- @action
6588
- willTransition(transition) {
6589
- if (this.controller.get('userHasEnteredData') &&
6590
- !confirm('Are you sure you want to abandon progress?')) {
6591
- transition.abort();
6592
- } else {
6593
- // Bubble the `willTransition` action so that
6594
- // parent routes can decide whether or not to abort.
6595
- return true;
6596
- }
6597
- }
6598
- }
6599
- ```
6600
- @property controller
6601
- @type Controller
6602
- @since 1.6.0
6603
- @public
6604
- */
6605
-
6606
- /**
6607
- The name of the route, dot-delimited.
6608
- For example, a route found at `app/routes/posts/post.js` will have
6609
- a `routeName` of `posts.post`.
6610
- @property routeName
6611
- @for Route
6612
- @type String
6613
- @since 1.0.0
6614
- @public
6615
- */
6616
-
6617
- /**
6618
- The name of the route, dot-delimited, including the engine prefix
6619
- if applicable.
6620
- For example, a route found at `addon/routes/posts/post.js` within an
6621
- engine named `admin` will have a `fullRouteName` of `admin.posts.post`.
6622
- @property fullRouteName
6623
- @for Route
6624
- @type String
6625
- @since 2.10.0
6626
- @public
6627
- */
6628
-
6629
- /**
6630
- Sets the name for this route, including a fully resolved name for routes
6631
- inside engines.
6632
- @private
6633
- @method _setRouteName
6634
- @param {String} name
6635
- */
6636
- _setRouteName(name) {
6637
- this.routeName = name;
6638
- let owner = getOwner(this);
6639
- (isDevelopingApp() && !(owner instanceof EmberEngineInstance) && assert('Expected route to have EngineInstance as owner', owner instanceof EmberEngineInstance));
6640
- this.fullRouteName = getEngineRouteName(owner, name);
6641
- }
6642
-
6643
- /**
6644
- @private
6645
- @method _stashNames
6646
- */
6647
- _stashNames(routeInfo, dynamicParent) {
6648
- if (this._names) {
6649
- return;
6650
- }
6651
- let names = this._names = routeInfo['_names'];
6652
- if (!names.length) {
6653
- routeInfo = dynamicParent;
6654
- names = routeInfo && routeInfo['_names'] || [];
6655
- }
6656
-
6657
- // SAFETY: Since `_qp` is protected we can't infer the type
6658
- let qps = get(this, '_qp').qps;
6659
- let namePaths = new Array(names.length);
6660
- for (let a = 0; a < names.length; ++a) {
6661
- namePaths[a] = `${routeInfo.name}.${names[a]}`;
6662
- }
6663
- for (let qp of qps) {
6664
- if (qp.scope === 'model') {
6665
- qp.parts = namePaths;
6666
- }
6667
- }
6668
- }
6669
-
6670
- /**
6671
- @private
6672
- @property _activeQPChanged
6673
- */
6674
- _activeQPChanged(qp, value) {
6675
- this._router._activeQPChanged(qp.scopedPropertyName, value);
6676
- }
6677
-
6678
- /**
6679
- @private
6680
- @method _updatingQPChanged
6681
- */
6682
- _updatingQPChanged(qp) {
6683
- this._router._updatingQPChanged(qp.urlKey);
6684
- }
6685
-
6686
- /**
6687
- Returns a hash containing the parameters of an ancestor route.
6688
- You may notice that `this.paramsFor` sometimes works when referring to a
6689
- child route, but this behavior should not be relied upon as only ancestor
6690
- routes are certain to be loaded in time.
6691
- Example
6692
- ```app/router.js
6693
- // ...
6694
- Router.map(function() {
6695
- this.route('member', { path: ':name' }, function() {
6696
- this.route('interest', { path: ':interest' });
6697
- });
6698
- });
6699
- ```
6700
- ```app/routes/member.js
6701
- import Route from '@ember/routing/route';
6702
- export default class MemberRoute extends Route {
6703
- queryParams = {
6704
- memberQp: { refreshModel: true }
6705
- }
6706
- }
6707
- ```
6708
- ```app/routes/member/interest.js
6709
- import Route from '@ember/routing/route';
6710
- export default class MemberInterestRoute extends Route {
6711
- queryParams = {
6712
- interestQp: { refreshModel: true }
6713
- }
6714
- model() {
6715
- return this.paramsFor('member');
6716
- }
6717
- }
6718
- ```
6719
- If we visit `/turing/maths?memberQp=member&interestQp=interest` the model for
6720
- the `member.interest` route is a hash with:
6721
- * `name`: `turing`
6722
- * `memberQp`: `member`
6723
- @method paramsFor
6724
- @param {String} name
6725
- @return {Object} hash containing the parameters of the route `name`
6726
- @since 1.4.0
6727
- @public
6728
- */
6729
- paramsFor(name) {
6730
- let owner = getOwner(this);
6731
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
6732
- let route = owner.lookup(`route:${name}`);
6733
- if (route === undefined) {
6734
- return {};
6735
- }
6736
- let transition = this._router._routerMicrolib.activeTransition;
6737
- let state = transition ? transition[STATE_SYMBOL] : this._router._routerMicrolib.state;
6738
- let fullName = route.fullRouteName;
6739
- let params = {
6740
- ...state.params[fullName]
6741
- };
6742
- let queryParams = getQueryParamsFor(route, state);
6743
- return Object.entries(queryParams).reduce((params, [key, value]) => {
6744
- (isDevelopingApp() && !(!params[key]) && assert(`The route '${this.routeName}' has both a dynamic segment and query param with name '${key}'. Please rename one to avoid collisions.`, !params[key]));
6745
- params[key] = value;
6746
- return params;
6747
- }, params);
6748
- }
6749
-
6750
- /**
6751
- Serializes the query parameter key
6752
- @method serializeQueryParamKey
6753
- @param {String} controllerPropertyName
6754
- @private
6755
- */
6756
- serializeQueryParamKey(controllerPropertyName) {
6757
- return controllerPropertyName;
6758
- }
6759
-
6760
- /**
6761
- Serializes value of the query parameter based on defaultValueType
6762
- @method serializeQueryParam
6763
- @param {Object} value
6764
- @param {String} urlKey
6765
- @param {String} defaultValueType
6766
- @private
6767
- */
6768
- serializeQueryParam(value, _urlKey, defaultValueType) {
6769
- // urlKey isn't used here, but anyone overriding
6770
- // can use it to provide serialization specific
6771
- // to a certain query param.
6772
- return this._router._serializeQueryParam(value, defaultValueType);
6773
- }
6774
-
6775
- /**
6776
- Deserializes value of the query parameter based on defaultValueType
6777
- @method deserializeQueryParam
6778
- @param {Object} value
6779
- @param {String} urlKey
6780
- @param {String} defaultValueType
6781
- @private
6782
- */
6783
- deserializeQueryParam(value, _urlKey, defaultValueType) {
6784
- // urlKey isn't used here, but anyone overriding
6785
- // can use it to provide deserialization specific
6786
- // to a certain query param.
6787
- return this._router._deserializeQueryParam(value, defaultValueType);
6788
- }
6789
-
6790
- /**
6791
- @private
6792
- @property _optionsForQueryParam
6793
- */
6794
- _optionsForQueryParam(qp) {
6795
- const queryParams = get(this, 'queryParams');
6796
- return get(queryParams, qp.urlKey) || get(queryParams, qp.prop) || queryParams[qp.urlKey] || queryParams[qp.prop] || {};
6797
- }
6798
-
6799
- /**
6800
- A hook you can use to reset controller values either when the model
6801
- changes or the route is exiting.
6802
- ```app/routes/articles.js
6803
- import Route from '@ember/routing/route';
6804
- export default class ArticlesRoute extends Route {
6805
- resetController(controller, isExiting, transition) {
6806
- if (isExiting && transition.targetName !== 'error') {
6807
- controller.set('page', 1);
6808
- }
6809
- }
6810
- }
6811
- ```
6812
- @method resetController
6813
- @param {Controller} controller instance
6814
- @param {Boolean} isExiting
6815
- @param {Object} transition
6816
- @since 1.7.0
6817
- @public
6818
- */
6819
- resetController(_controller, _isExiting, _transition) {
6820
- // We document that subclasses do not have to return *anything* and in fact
6821
- // do not even have to call super, so whiel we *do* return `this`, we need
6822
- // to be explicit in the types that our return type is *effectively* `void`.
6823
- return this;
6824
- }
6825
-
6826
- /**
6827
- @private
6828
- @method exit
6829
- */
6830
- exit(transition) {
6831
- this.deactivate(transition);
6832
- this.trigger('deactivate', transition);
6833
- this.teardownViews();
6834
- }
6835
-
6836
- /**
6837
- @private
6838
- @method _internalReset
6839
- @since 3.6.0
6840
- */
6841
- _internalReset(isExiting, transition) {
6842
- let controller = this.controller;
6843
- // SAFETY: Since `_qp` is protected we can't infer the type
6844
- controller['_qpDelegate'] = get(this, '_qp').states.inactive;
6845
- this.resetController(controller, isExiting, transition);
6846
- }
6847
-
6848
- /**
6849
- @private
6850
- @method enter
6851
- */
6852
- enter(transition) {
6853
- this[RENDER_STATE] = undefined;
6854
- this.activate(transition);
6855
- this.trigger('activate', transition);
6856
- }
6857
-
6858
- /**
6859
- This event is triggered when the router enters the route. It is
6860
- not executed when the model for the route changes.
6861
- ```app/routes/application.js
6862
- import { on } from '@ember/object/evented';
6863
- import Route from '@ember/routing/route';
6864
- export default Route.extend({
6865
- collectAnalytics: on('activate', function(){
6866
- collectAnalytics();
6867
- })
6868
- });
6869
- ```
6870
- @event activate
6871
- @since 1.9.0
6872
- @public
6873
- */
6874
-
6875
- /**
6876
- This event is triggered when the router completely exits this
6877
- route. It is not executed when the model for the route changes.
6878
- ```app/routes/index.js
6879
- import { on } from '@ember/object/evented';
6880
- import Route from '@ember/routing/route';
6881
- export default Route.extend({
6882
- trackPageLeaveAnalytics: on('deactivate', function(){
6883
- trackPageLeaveAnalytics();
6884
- })
6885
- });
6886
- ```
6887
- @event deactivate
6888
- @since 1.9.0
6889
- @public
6890
- */
6891
-
6892
- /**
6893
- This hook is executed when the router completely exits this route. It is
6894
- not executed when the model for the route changes.
6895
- @method deactivate
6896
- @param {Transition} transition
6897
- @since 1.0.0
6898
- @public
6899
- */
6900
- deactivate(_transition) {}
6901
-
6902
- /**
6903
- This hook is executed when the router enters the route. It is not executed
6904
- when the model for the route changes.
6905
- @method activate
6906
- @param {Transition} transition
6907
- @since 1.0.0
6908
- @public
6909
- */
6910
- activate(_transition) {}
6911
-
6912
- /**
6913
- Perform a synchronous transition into another route without attempting
6914
- to resolve promises, update the URL, or abort any currently active
6915
- asynchronous transitions (i.e. regular transitions caused by
6916
- `transitionTo` or URL changes).
6917
- This method is handy for performing intermediate transitions on the
6918
- way to a final destination route, and is called internally by the
6919
- default implementations of the `error` and `loading` handlers.
6920
- @method intermediateTransitionTo
6921
- @param {String} name the name of the route
6922
- @param {...Object} models the model(s) to be used while transitioning
6923
- to the route.
6924
- @since 1.2.0
6925
- @public
6926
- */
6927
- intermediateTransitionTo(...args) {
6928
- let [name, ...preparedArgs] = prefixRouteNameArg(this, args);
6929
- this._router.intermediateTransitionTo(name, ...preparedArgs);
6930
- }
6931
-
6932
- /**
6933
- Refresh the model on this route and any child routes, firing the
6934
- `beforeModel`, `model`, and `afterModel` hooks in a similar fashion
6935
- to how routes are entered when transitioning in from other route.
6936
- The current route params (e.g. `article_id`) will be passed in
6937
- to the respective model hooks, and if a different model is returned,
6938
- `setupController` and associated route hooks will re-fire as well.
6939
- An example usage of this method is re-querying the server for the
6940
- latest information using the same parameters as when the route
6941
- was first entered.
6942
- Note that this will cause `model` hooks to fire even on routes
6943
- that were provided a model object when the route was initially
6944
- entered.
6945
- @method refresh
6946
- @return {Transition} the transition object associated with this
6947
- attempted transition
6948
- @since 1.4.0
6949
- @public
6950
- */
6951
- refresh() {
6952
- return this._router._routerMicrolib.refresh(this);
6953
- }
6954
-
6955
- /**
6956
- This hook is the entry point for router.js
6957
- @private
6958
- @method setup
6959
- */
6960
- setup(context, transition) {
6961
- let controllerName = this.controllerName || this.routeName;
6962
- let definedController = this.controllerFor(controllerName, true);
6963
- let controller = definedController ?? this.generateController(controllerName);
6964
-
6965
- // SAFETY: Since `_qp` is protected we can't infer the type
6966
- let queryParams = get(this, '_qp');
6967
-
6968
- // Assign the route's controller so that it can more easily be
6969
- // referenced in action handlers. Side effects. Side effects everywhere.
6970
- if (!this.controller) {
6971
- let propNames = queryParams.propertyNames;
6972
- addQueryParamsObservers(controller, propNames);
6973
- this.controller = controller;
6974
- }
6975
- let states = queryParams.states;
6976
- controller._qpDelegate = states.allowOverrides;
6977
- if (transition) {
6978
- // Update the model dep values used to calculate cache keys.
6979
- stashParamNames(this._router, transition[STATE_SYMBOL].routeInfos);
6980
- let cache = this._bucketCache;
6981
- let params = transition[PARAMS_SYMBOL];
6982
- let allParams = queryParams.propertyNames;
6983
- allParams.forEach(prop => {
6984
- let aQp = queryParams.map[prop];
6985
- (isDevelopingApp() && !(aQp) && assert('expected aQp', aQp));
6986
- aQp.values = params;
6987
- let cacheKey = calculateCacheKey(aQp.route.fullRouteName, aQp.parts, aQp.values);
6988
- let value = cache.lookup(cacheKey, prop, aQp.undecoratedDefaultValue);
6989
- set(controller, prop, value);
6990
- });
6991
- let qpValues = getQueryParamsFor(this, transition[STATE_SYMBOL]);
6992
- setProperties(controller, qpValues);
6993
- }
6994
- this.setupController(controller, context, transition);
6995
- if (this._environment.options.shouldRender) {
6996
- this[RENDER]();
6997
- }
6998
-
6999
- // Setup can cause changes to QPs which need to be propogated immediately in
7000
- // some situations. Eventually, we should work on making these async somehow.
7001
- flushAsyncObservers(false);
7002
- }
7003
-
7004
- /*
7005
- Called when a query parameter for this route changes, regardless of whether the route
7006
- is currently part of the active route hierarchy. This will update the query parameter's
7007
- value in the cache so if this route becomes active, the cache value has been updated.
7008
- */
7009
- _qpChanged(prop, value, qp) {
7010
- if (!qp) {
7011
- return;
7012
- }
7013
-
7014
- // Update model-dep cache
7015
- let cache = this._bucketCache;
7016
- let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, qp.values);
7017
- cache.stash(cacheKey, prop, value);
7018
- }
7019
-
7020
- /**
7021
- This hook is the first of the route entry validation hooks
7022
- called when an attempt is made to transition into a route
7023
- or one of its children. It is called before `model` and
7024
- `afterModel`, and is appropriate for cases when:
7025
- 1) A decision can be made to redirect elsewhere without
7026
- needing to resolve the model first.
7027
- 2) Any async operations need to occur first before the
7028
- model is attempted to be resolved.
7029
- This hook is provided the current `transition` attempt
7030
- as a parameter, which can be used to `.abort()` the transition,
7031
- save it for a later `.retry()`, or retrieve values set
7032
- on it from a previous hook. You can also just call
7033
- `router.transitionTo` to another route to implicitly
7034
- abort the `transition`.
7035
- You can return a promise from this hook to pause the
7036
- transition until the promise resolves (or rejects). This could
7037
- be useful, for instance, for retrieving async code from
7038
- the server that is required to enter a route.
7039
- @method beforeModel
7040
- @param {Transition} transition
7041
- @return {any | Promise<any>} if the value returned from this hook is
7042
- a promise, the transition will pause until the transition
7043
- resolves. Otherwise, non-promise return values are not
7044
- utilized in any way.
7045
- @since 1.0.0
7046
- @public
7047
- */
7048
-
7049
- beforeModel(_transition) {}
7050
-
7051
- /**
7052
- This hook is called after this route's model has resolved.
7053
- It follows identical async/promise semantics to `beforeModel`
7054
- but is provided the route's resolved model in addition to
7055
- the `transition`, and is therefore suited to performing
7056
- logic that can only take place after the model has already
7057
- resolved.
7058
- ```app/routes/posts.js
7059
- import Route from '@ember/routing/route';
7060
- import { service } from '@ember/service';
7061
- export default class PostsRoute extends Route {
7062
- @service router;
7063
- afterModel(posts, transition) {
7064
- if (posts.get('length') === 1) {
7065
- this.router.transitionTo('post.show', posts.get('firstObject'));
7066
- }
7067
- }
7068
- }
7069
- ```
7070
- Refer to documentation for `beforeModel` for a description
7071
- of transition-pausing semantics when a promise is returned
7072
- from this hook.
7073
- @method afterModel
7074
- @param {Object} resolvedModel the value returned from `model`,
7075
- or its resolved value if it was a promise
7076
- @param {Transition} transition
7077
- @return {any | Promise<any>} if the value returned from this hook is
7078
- a promise, the transition will pause until the transition
7079
- resolves. Otherwise, non-promise return values are not
7080
- utilized in any way.
7081
- @since 1.0.0
7082
- @public
7083
- */
7084
-
7085
- afterModel(_resolvedModel, _transition) {}
7086
-
7087
- /**
7088
- A hook you can implement to optionally redirect to another route.
7089
- Calling `this.router.transitionTo` from inside of the `redirect` hook will
7090
- abort the current transition (into the route that has implemented `redirect`).
7091
- `redirect` and `afterModel` behave very similarly and are
7092
- called almost at the same time, but they have an important
7093
- distinction when calling `this.router.transitionTo` to a child route
7094
- of the current route. From `afterModel`, this new transition
7095
- invalidates the current transition, causing `beforeModel`,
7096
- `model`, and `afterModel` hooks to be called again. But the
7097
- same transition started from `redirect` does _not_ invalidate
7098
- the current transition. In other words, by the time the `redirect`
7099
- hook has been called, both the resolved model and the attempted
7100
- entry into this route are considered fully validated.
7101
- @method redirect
7102
- @param {Object} model the model for this route
7103
- @param {Transition} transition the transition object associated with the current transition
7104
- @since 1.0.0
7105
- @public
7106
- */
7107
- redirect(_model, _transition) {}
7108
-
7109
- /**
7110
- Called when the context is changed by router.js.
7111
- @private
7112
- @method contextDidChange
7113
- */
7114
- contextDidChange() {
7115
- this.currentModel = this.context;
7116
- }
7117
-
7118
- /**
7119
- A hook you can implement to convert the URL into the model for
7120
- this route.
7121
- ```app/router.js
7122
- // ...
7123
- Router.map(function() {
7124
- this.route('post', { path: '/posts/:post_id' });
7125
- });
7126
- export default Router;
7127
- ```
7128
- Note that for routes with dynamic segments, this hook is not always
7129
- executed. If the route is entered through a transition (e.g. when
7130
- using the `link-to` Handlebars helper or the `transitionTo` method
7131
- of routes), and a model context is already provided this hook
7132
- is not called.
7133
- A model context does not include a primitive string or number,
7134
- which does cause the model hook to be called.
7135
- Routes without dynamic segments will always execute the model hook.
7136
- ```javascript
7137
- // no dynamic segment, model hook always called
7138
- this.router.transitionTo('posts');
7139
- // model passed in, so model hook not called
7140
- thePost = store.findRecord('post', 1);
7141
- this.router.transitionTo('post', thePost);
7142
- // integer passed in, model hook is called
7143
- this.router.transitionTo('post', 1);
7144
- // model id passed in, model hook is called
7145
- // useful for forcing the hook to execute
7146
- thePost = store.findRecord('post', 1);
7147
- this.router.transitionTo('post', thePost.id);
7148
- ```
7149
- This hook follows the asynchronous/promise semantics
7150
- described in the documentation for `beforeModel`. In particular,
7151
- if a promise returned from `model` fails, the error will be
7152
- handled by the `error` hook on `Route`.
7153
- Note that the legacy behavior of automatically defining a model
7154
- hook when a dynamic segment ending in `_id` is present is
7155
- [deprecated](https://deprecations.emberjs.com/v5.x#toc_deprecate-implicit-route-model).
7156
- You should explicitly define a model hook whenever any segments are
7157
- present.
7158
- Example
7159
- ```app/routes/post.js
7160
- import Route from '@ember/routing/route';
7161
- import { service } from '@ember/service';
7162
- export default class PostRoute extends Route {
7163
- @service store;
7164
- model(params) {
7165
- return this.store.findRecord('post', params.post_id);
7166
- }
7167
- }
7168
- ```
7169
- @method model
7170
- @param {Object} params the parameters extracted from the URL
7171
- @param {Transition} transition
7172
- @return {any | Promise<any>} the model for this route. If
7173
- a promise is returned, the transition will pause until
7174
- the promise resolves, and the resolved value of the promise
7175
- will be used as the model for this route.
7176
- @since 1.0.0
7177
- @public
7178
- */
7179
- model(params, transition) {
7180
- let name, sawParams, value;
7181
- // SAFETY: Since `_qp` is protected we can't infer the type
7182
- let queryParams = get(this, '_qp').map;
7183
- for (let prop in params) {
7184
- if (prop === 'queryParams' || queryParams && prop in queryParams) {
7185
- continue;
7186
- }
7187
- let match = prop.match(/^(.*)_id$/);
7188
- if (match !== null) {
7189
- name = match[1];
7190
- value = params[prop];
7191
- }
7192
- sawParams = true;
7193
- }
7194
- if (!name) {
7195
- if (sawParams) {
7196
- // SAFETY: This should be equivalent
7197
- return Object.assign({}, params);
7198
- } else {
7199
- if (transition.resolveIndex < 1) {
7200
- return;
7201
- }
7202
- // SAFETY: This should be correct, but TS is unable to infer this.
7203
- return transition[STATE_SYMBOL].routeInfos[transition.resolveIndex - 1].context;
7204
- }
7205
- }
7206
- return this.findModel(name, value);
7207
- }
7208
-
7209
- /**
7210
- @private
7211
- @method deserialize
7212
- @param {Object} params the parameters extracted from the URL
7213
- @param {Transition} transition
7214
- @return {any | Promise<any>} the model for this route.
7215
- Router.js hook.
7216
- */
7217
- deserialize(_params, transition) {
7218
- return this.model(this._paramsFor(this.routeName, _params), transition);
7219
- }
7220
-
7221
- /**
7222
- @method findModel
7223
- @param {String} type the model type
7224
- @param {Object} value the value passed to find
7225
- @private
7226
- */
7227
- findModel(type, value) {
7228
- if (ENV._NO_IMPLICIT_ROUTE_MODEL) {
7229
- return;
7230
- }
7231
- deprecateUntil(`The implicit model loading behavior for routes is deprecated. ` + `Please define an explicit model hook for ${this.fullRouteName}.`, DEPRECATIONS.DEPRECATE_IMPLICIT_ROUTE_MODEL);
7232
- const store = 'store' in this ? this.store : get(this, '_store');
7233
- (isDevelopingApp() && !(isStoreLike(store)) && assert('Expected route to have a store with a find method', isStoreLike(store))); // SAFETY: We don't actually know it will return this, but this code path is also deprecated.
7234
- return store.find(type, value);
7235
- }
7236
-
7237
- /**
7238
- A hook you can use to setup the controller for the current route.
7239
- This method is called with the controller for the current route and the
7240
- model supplied by the `model` hook.
7241
- By default, the `setupController` hook sets the `model` property of
7242
- the controller to the specified `model` when it is not `undefined`.
7243
- If you implement the `setupController` hook in your Route, it will
7244
- prevent this default behavior. If you want to preserve that behavior
7245
- when implementing your `setupController` function, make sure to call
7246
- `super`:
7247
- ```app/routes/photos.js
7248
- import Route from '@ember/routing/route';
7249
- import { service } from '@ember/service';
7250
- export default class PhotosRoute extends Route {
7251
- @service store;
7252
- model() {
7253
- return this.store.findAll('photo');
7254
- }
7255
- setupController(controller, model) {
7256
- super.setupController(controller, model);
7257
- this.controllerFor('application').set('showingPhotos', true);
7258
- }
7259
- }
7260
- ```
7261
- The provided controller will be one resolved based on the name
7262
- of this route.
7263
- If no explicit controller is defined, Ember will automatically create one.
7264
- As an example, consider the router:
7265
- ```app/router.js
7266
- // ...
7267
- Router.map(function() {
7268
- this.route('post', { path: '/posts/:post_id' });
7269
- });
7270
- export default Router;
7271
- ```
7272
- If you have defined a file for the post controller,
7273
- the framework will use it.
7274
- If it is not defined, a basic `Controller` instance would be used.
7275
- @example Behavior of a basic Controller
7276
- ```app/routes/post.js
7277
- import Route from '@ember/routing/route';
7278
- export default class PostRoute extends Route {
7279
- setupController(controller, model) {
7280
- controller.set('model', model);
7281
- }
7282
- });
7283
- ```
7284
- @method setupController
7285
- @param {Controller} controller instance
7286
- @param {Object} model
7287
- @param {Transition} [transition]
7288
- @since 1.0.0
7289
- @public
7290
- */
7291
- setupController(controller, context, _transition) {
7292
- if (controller && context !== undefined) {
7293
- set(controller, 'model', context);
7294
- }
7295
- }
7296
-
7297
- /**
7298
- Returns the controller of the current route, or a parent (or any ancestor)
7299
- route in a route hierarchy.
7300
- The controller instance must already have been created, either through entering the
7301
- associated route or using `generateController`.
7302
- ```app/routes/post.js
7303
- import Route from '@ember/routing/route';
7304
- export default class PostRoute extends Route {
7305
- setupController(controller, post) {
7306
- super.setupController(controller, post);
7307
- this.controllerFor('posts').set('currentPost', post);
7308
- }
7309
- }
7310
- ```
7311
- @method controllerFor
7312
- @param {String} name the name of the route or controller
7313
- @return {Controller | undefined}
7314
- @since 1.0.0
7315
- @public
7316
- */
7317
-
7318
- controllerFor(name, _skipAssert = false) {
7319
- let owner = getOwner(this);
7320
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
7321
- let route = owner.lookup(`route:${name}`);
7322
- if (route && route.controllerName) {
7323
- name = route.controllerName;
7324
- }
7325
- let controller = owner.lookup(`controller:${name}`);
7326
-
7327
- // NOTE: We're specifically checking that skipAssert is true, because according
7328
- // to the old API the second parameter was model. We do not want people who
7329
- // passed a model to skip the assertion.
7330
- (isDevelopingApp() && !(controller !== undefined || _skipAssert === true) && assert(`The controller named '${name}' could not be found. Make sure that this route exists and has already been entered at least once. If you are accessing a controller not associated with a route, make sure the controller class is explicitly defined.`, controller !== undefined || _skipAssert === true));
7331
- (isDevelopingApp() && !(controller === undefined || controller instanceof Controller) && assert(`Expected controller:${name} to be an instance of Controller`, controller === undefined || controller instanceof Controller));
7332
- return controller;
7333
- }
7334
-
7335
- /**
7336
- Generates a controller for a route.
7337
- Example
7338
- ```app/routes/post.js
7339
- import Route from '@ember/routing/route';
7340
- export default class Post extends Route {
7341
- setupController(controller, post) {
7342
- super.setupController(controller, post);
7343
- this.generateController('posts');
7344
- }
7345
- }
7346
- ```
7347
- @method generateController
7348
- @param {String} name the name of the controller
7349
- @private
7350
- */
7351
- generateController(name) {
7352
- let owner = getOwner(this);
7353
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
7354
- return generateController(owner, name);
7355
- }
7356
-
7357
- /**
7358
- Returns the resolved model of a parent (or any ancestor) route
7359
- in a route hierarchy. During a transition, all routes
7360
- must resolve a model object, and if a route
7361
- needs access to a parent route's model in order to
7362
- resolve a model (or just reuse the model from a parent),
7363
- it can call `this.modelFor(theNameOfParentRoute)` to
7364
- retrieve it. If the ancestor route's model was a promise,
7365
- its resolved result is returned.
7366
- Example
7367
- ```app/router.js
7368
- // ...
7369
- Router.map(function() {
7370
- this.route('post', { path: '/posts/:post_id' }, function() {
7371
- this.route('comments');
7372
- });
7373
- });
7374
- export default Router;
7375
- ```
7376
- ```app/routes/post/comments.js
7377
- import Route from '@ember/routing/route';
7378
- export default class PostCommentsRoute extends Route {
7379
- model() {
7380
- let post = this.modelFor('post');
7381
- return post.comments;
7382
- }
7383
- }
7384
- ```
7385
- @method modelFor
7386
- @param {String} name the name of the route
7387
- @return {Object} the model object
7388
- @since 1.0.0
7389
- @public
7390
- */
7391
- modelFor(_name) {
7392
- let name;
7393
- let owner = getOwner(this);
7394
- (isDevelopingApp() && !(owner instanceof EmberEngineInstance) && assert('Expected router owner to be an EngineInstance', owner instanceof EmberEngineInstance));
7395
- let transition = this._router && this._router._routerMicrolib ? this._router._routerMicrolib.activeTransition : undefined;
7396
-
7397
- // Only change the route name when there is an active transition.
7398
- // Otherwise, use the passed in route name.
7399
- if (owner.routable && transition !== undefined) {
7400
- name = getEngineRouteName(owner, _name);
7401
- } else {
7402
- name = _name;
7403
- }
7404
- let route = owner.lookup(`route:${name}`);
7405
- // If we are mid-transition, we want to try and look up
7406
- // resolved parent contexts on the current transitionEvent.
7407
- if (transition !== undefined && transition !== null) {
7408
- let modelLookupName = route && route.routeName || name;
7409
- if (Object.prototype.hasOwnProperty.call(transition.resolvedModels, modelLookupName)) {
7410
- return transition.resolvedModels[modelLookupName];
7411
- }
7412
- }
7413
- return route?.currentModel;
7414
- }
7415
- [RENDER_STATE] = undefined;
7416
-
7417
- /**
7418
- `this[RENDER]` is used to set up the rendering option for the outlet state.
7419
- @method this[RENDER]
7420
- @private
7421
- */
7422
- [RENDER]() {
7423
- this[RENDER_STATE] = buildRenderState(this);
7424
- once(this._router, '_setOutlets');
7425
- }
7426
- willDestroy() {
7427
- this.teardownViews();
7428
- }
7429
-
7430
- /**
7431
- @private
7432
- @method teardownViews
7433
- */
7434
- teardownViews() {
7435
- if (this[RENDER_STATE]) {
7436
- this[RENDER_STATE] = undefined;
7437
- once(this._router, '_setOutlets');
7438
- }
7439
- }
7440
-
7441
- /**
7442
- Allows you to produce custom metadata for the route.
7443
- The return value of this method will be attached to
7444
- its corresponding RouteInfoWithAttributes object.
7445
- Example
7446
- ```app/routes/posts/index.js
7447
- import Route from '@ember/routing/route';
7448
- export default class PostsIndexRoute extends Route {
7449
- buildRouteInfoMetadata() {
7450
- return { title: 'Posts Page' }
7451
- }
7452
- }
7453
- ```
7454
- ```app/routes/application.js
7455
- import Route from '@ember/routing/route';
7456
- import { service } from '@ember/service';
7457
- export default class ApplicationRoute extends Route {
7458
- @service router
7459
- constructor() {
7460
- super(...arguments);
7461
- this.router.on('routeDidChange', transition => {
7462
- document.title = transition.to.metadata.title;
7463
- // would update document's title to "Posts Page"
7464
- });
7465
- }
7466
- }
7467
- ```
7468
- @method buildRouteInfoMetadata
7469
- @return any
7470
- @since 3.10.0
7471
- @public
7472
- */
7473
-
7474
- buildRouteInfoMetadata() {}
7475
- _paramsFor(routeName, params) {
7476
- let transition = this._router._routerMicrolib.activeTransition;
7477
- if (transition !== undefined) {
7478
- return this.paramsFor(routeName);
7479
- }
7480
- return params;
7481
- }
7482
-
7483
- /** @deprecated Manually define your own store, such as with `@service store` */
7484
- get _store() {
7485
- const owner = getOwner(this);
7486
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
7487
- let routeName = this.routeName;
7488
- return {
7489
- find(name, value) {
7490
- let modelClass = owner.factoryFor(`model:${name}`);
7491
- (isDevelopingApp() && !(Boolean(modelClass)) && assert(`You used the dynamic segment \`${name}_id\` in your route ` + `\`${routeName}\` for which Ember requires you provide a ` + `data-loading implementation. Commonly, that is done by ` + `adding a model hook implementation on the route ` + `(\`model({${name}_id}) {\`) or by injecting an implemention of ` + `a data store: \`@service store;\`.`, Boolean(modelClass)));
7492
- if (!modelClass) {
7493
- return;
7494
- }
7495
- modelClass = modelClass.class;
7496
- (isDevelopingApp() && !(typeof modelClass.find === 'function') && assert(`You used the dynamic segment \`${name}_id\` in your route ` + `\`${routeName}\` for which Ember requires you provide a ` + `data-loading implementation. Commonly, that is done by ` + `adding a model hook implementation on the route ` + `(\`model({${name}_id}) {\`) or by injecting an implemention of ` + `a data store: \`@service store;\`.\n\n` + `Rarely, applications may attempt to use a legacy behavior where ` + `the model class (in this case \`${name}\`) is resolved and the ` + `\`find\` method on that class is invoked to load data. In this ` + `application, a model of \`${name}\` was found but it did not ` + `provide a \`find\` method. You should not add a \`find\` ` + `method to your model. Instead, please implement an appropriate ` + `\`model\` hook on the \`${routeName}\` route.`, typeof modelClass.find === 'function'));
7497
- return modelClass.find(value);
7498
- }
7499
- };
7500
- }
7501
-
7502
- /**
7503
- @private
7504
- @property _qp
7505
- */
7506
- static {
7507
- decorateMethodV2(this.prototype, "_store", [computed]);
7508
- }
7509
- get _qp() {
7510
- let combinedQueryParameterConfiguration = {};
7511
- let controllerName = this.controllerName || this.routeName;
7512
- let owner = getOwner(this);
7513
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
7514
- let controller = owner.lookup(`controller:${controllerName}`);
7515
- let queryParameterConfiguraton = get(this, 'queryParams');
7516
- let hasRouterDefinedQueryParams = Object.keys(queryParameterConfiguraton).length > 0;
7517
- if (controller) {
7518
- (isDevelopingApp() && !(controller instanceof Controller) && assert('Expected an instance of controller', controller instanceof Controller)); // the developer has authored a controller class in their application for
7519
- // this route find its query params and normalize their object shape them
7520
- // merge in the query params for the route. As a mergedProperty,
7521
- // Route#queryParams is always at least `{}`
7522
- let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || [];
7523
- let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration);
7524
- combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton);
7525
- } else if (hasRouterDefinedQueryParams) {
7526
- // the developer has not defined a controller but *has* supplied route query params.
7527
- // Generate a class for them so we can later insert default values
7528
- controller = generateController(owner, controllerName);
7529
- combinedQueryParameterConfiguration = queryParameterConfiguraton;
7530
- }
7531
- let qps = [];
7532
- let map = {};
7533
- let propertyNames = [];
7534
- for (let propName in combinedQueryParameterConfiguration) {
7535
- if (!Object.prototype.hasOwnProperty.call(combinedQueryParameterConfiguration, propName)) {
7536
- continue;
7537
- }
7538
-
7539
- // to support the dubious feature of using unknownProperty
7540
- // on queryParams configuration
7541
- if (propName === 'unknownProperty' || propName === '_super') {
7542
- // possible todo: issue deprecation warning?
7543
- continue;
7544
- }
7545
- let desc = combinedQueryParameterConfiguration[propName];
7546
- (isDevelopingApp() && !(desc) && assert(`[BUG] missing query parameter configuration for ${propName}`, desc));
7547
- let scope = desc.scope || 'model';
7548
- let parts = undefined;
7549
- if (scope === 'controller') {
7550
- parts = [];
7551
- }
7552
- let urlKey = desc.as || this.serializeQueryParamKey(propName);
7553
- let defaultValue = get(controller, propName);
7554
- defaultValue = copyDefaultValue(defaultValue);
7555
- let type = desc.type || typeOf(defaultValue);
7556
- let defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type);
7557
- let scopedPropertyName = `${controllerName}:${propName}`;
7558
- let qp = {
7559
- undecoratedDefaultValue: get(controller, propName),
7560
- defaultValue,
7561
- serializedDefaultValue: defaultValueSerialized,
7562
- serializedValue: defaultValueSerialized,
7563
- type,
7564
- urlKey,
7565
- prop: propName,
7566
- scopedPropertyName,
7567
- controllerName,
7568
- route: this,
7569
- parts,
7570
- // provided later when stashNames is called if 'model' scope
7571
- values: null,
7572
- // provided later when setup is called. no idea why.
7573
- scope
7574
- };
7575
- map[propName] = map[urlKey] = map[scopedPropertyName] = qp;
7576
- qps.push(qp);
7577
- propertyNames.push(propName);
7578
- }
7579
- return {
7580
- qps,
7581
- map,
7582
- propertyNames,
7583
- states: {
7584
- /*
7585
- Called when a query parameter changes in the URL, this route cares
7586
- about that query parameter, but the route is not currently
7587
- in the active route hierarchy.
7588
- */
7589
- inactive: (prop, value) => {
7590
- let qp = map[prop];
7591
- (isDevelopingApp() && !(qp) && assert('expected inactive callback to only be called for registered qps', qp));
7592
- this._qpChanged(prop, value, qp);
7593
- },
7594
- /*
7595
- Called when a query parameter changes in the URL, this route cares
7596
- about that query parameter, and the route is currently
7597
- in the active route hierarchy.
7598
- */
7599
- active: (prop, value) => {
7600
- let qp = map[prop];
7601
- (isDevelopingApp() && !(qp) && assert('expected active callback to only be called for registered qps', qp));
7602
- this._qpChanged(prop, value, qp);
7603
- return this._activeQPChanged(qp, value);
7604
- },
7605
- /*
7606
- Called when a value of a query parameter this route handles changes in a controller
7607
- and the route is currently in the active route hierarchy.
7608
- */
7609
- allowOverrides: (prop, value) => {
7610
- let qp = map[prop];
7611
- (isDevelopingApp() && !(qp) && assert('expected allowOverrides callback to only be called for registered qps', qp));
7612
- this._qpChanged(prop, value, qp);
7613
- return this._updatingQPChanged(qp);
7614
- }
7615
- }
7616
- };
7617
- }
7618
-
7619
- // Set in reopen
7620
- static {
7621
- decorateMethodV2(this.prototype, "_qp", [computed]);
7622
- }
7623
- /**
7624
- Sends an action to the router, which will delegate it to the currently
7625
- active route hierarchy per the bubbling rules explained under `actions`.
7626
- Example
7627
- ```app/router.js
7628
- // ...
7629
- Router.map(function() {
7630
- this.route('index');
7631
- });
7632
- export default Router;
7633
- ```
7634
- ```app/routes/application.js
7635
- import Route from '@ember/routing/route';
7636
- import { action } from '@ember/object';
7637
- export default class ApplicationRoute extends Route {
7638
- @action
7639
- track(arg) {
7640
- console.log(arg, 'was clicked');
7641
- }
7642
- }
7643
- ```
7644
- ```app/routes/index.js
7645
- import Route from '@ember/routing/route';
7646
- import { action } from '@ember/object';
7647
- export default class IndexRoute extends Route {
7648
- @action
7649
- trackIfDebug(arg) {
7650
- if (debug) {
7651
- this.send('track', arg);
7652
- }
7653
- }
7654
- }
7655
- ```
7656
- @method send
7657
- @param {String} name the name of the action to trigger
7658
- @param {...*} args
7659
- @since 1.0.0
7660
- @public
7661
- */
7662
- // Set with reopen to override parent behavior
7663
- }
7664
- function getRenderState(route) {
7665
- return route[RENDER_STATE];
7666
- }
7667
- function buildRenderState(route) {
7668
- let owner = getOwner(route);
7669
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
7670
- let name = route.routeName;
7671
- let controller = owner.lookup(`controller:${route.controllerName || name}`);
7672
- (isDevelopingApp() && !(controller instanceof Controller) && assert('Expected an instance of controller', controller instanceof Controller));
7673
- let model = route.currentModel;
7674
- let template = owner.lookup(`template:${route.templateName || name}`);
7675
- let render = {
7676
- owner,
7677
- into: undefined,
7678
- outlet: 'main',
7679
- name,
7680
- controller,
7681
- model,
7682
- template: template?.(owner) ?? route._topLevelViewTemplate(owner)
7683
- };
7684
- if (isDevelopingApp()) {
7685
- let LOG_VIEW_LOOKUPS = get(route._router, 'namespace.LOG_VIEW_LOOKUPS');
7686
- if (LOG_VIEW_LOOKUPS && !template) {
7687
- info(`Could not find "${name}" template. Nothing will be rendered`, {
7688
- fullName: `template:${name}`
7689
- });
7690
- }
7691
- }
7692
- return render;
7693
- }
7694
- function getFullQueryParams(router, state) {
7695
- if (state.fullQueryParams) {
7696
- return state.fullQueryParams;
7697
- }
7698
- let haveAllRouteInfosResolved = state.routeInfos.every(routeInfo => routeInfo.route);
7699
- let fullQueryParamsState = {
7700
- ...state.queryParams
7701
- };
7702
- router._deserializeQueryParams(state.routeInfos, fullQueryParamsState);
7703
-
7704
- // only cache query params state if all routeinfos have resolved; it's possible
7705
- // for lazy routes to not have resolved when `getFullQueryParams` is called, so
7706
- // we wait until all routes have resolved prior to caching query params state
7707
- if (haveAllRouteInfosResolved) {
7708
- state.fullQueryParams = fullQueryParamsState;
7709
- }
7710
- return fullQueryParamsState;
7711
- }
7712
- function getQueryParamsFor(route, state) {
7713
- state.queryParamsFor = state.queryParamsFor || {};
7714
- let name = route.fullRouteName;
7715
- let existing = state.queryParamsFor[name];
7716
- if (existing) {
7717
- return existing;
7718
- }
7719
- let fullQueryParams = getFullQueryParams(route._router, state);
7720
- let params = state.queryParamsFor[name] = {};
7721
-
7722
- // Copy over all the query params for this route/controller into params hash.
7723
- // SAFETY: Since `_qp` is protected we can't infer the type
7724
- let qps = get(route, '_qp').qps;
7725
- for (let qp of qps) {
7726
- // Put deserialized qp on params hash.
7727
- let qpValueWasPassedIn = (qp.prop in fullQueryParams);
7728
- params[qp.prop] = qpValueWasPassedIn ? fullQueryParams[qp.prop] : copyDefaultValue(qp.defaultValue);
7729
- }
7730
- return params;
7731
- }
7732
-
7733
- // FIXME: This should probably actually return a `NativeArray` if the passed in value is an Array.
7734
- function copyDefaultValue(value) {
7735
- if (Array.isArray(value)) {
7736
- // SAFETY: We lost the type data about the array if we don't cast.
7737
- return A(value.slice());
7738
- }
7739
- return value;
7740
- }
7741
-
7742
- /*
7743
- Merges all query parameters from a controller with those from
7744
- a route, returning a new object and avoiding any mutations to
7745
- the existing objects.
7746
- */
7747
- function mergeEachQueryParams(controllerQP, routeQP) {
7748
- let qps = {};
7749
- let keysAlreadyMergedOrSkippable = {
7750
- defaultValue: true,
7751
- type: true,
7752
- scope: true,
7753
- as: true
7754
- };
7755
-
7756
- // first loop over all controller qps, merging them with any matching route qps
7757
- // into a new empty object to avoid mutating.
7758
- for (let cqpName in controllerQP) {
7759
- if (!Object.prototype.hasOwnProperty.call(controllerQP, cqpName)) {
7760
- continue;
7761
- }
7762
- qps[cqpName] = {
7763
- ...controllerQP[cqpName],
7764
- ...routeQP[cqpName]
7765
- };
7766
-
7767
- // allows us to skip this QP when we check route QPs.
7768
- keysAlreadyMergedOrSkippable[cqpName] = true;
7769
- }
7770
-
7771
- // loop over all route qps, skipping those that were merged in the first pass
7772
- // because they also appear in controller qps
7773
- for (let rqpName in routeQP) {
7774
- if (!Object.prototype.hasOwnProperty.call(routeQP, rqpName) || keysAlreadyMergedOrSkippable[rqpName]) {
7775
- continue;
7776
- }
7777
- qps[rqpName] = {
7778
- ...routeQP[rqpName],
7779
- ...controllerQP[rqpName]
7780
- };
7781
- }
7782
- return qps;
7783
- }
7784
- function addQueryParamsObservers(controller, propNames) {
7785
- propNames.forEach(prop => {
7786
- if (descriptorForProperty(controller, prop) === undefined) {
7787
- let desc = lookupDescriptor(controller, prop);
7788
- if (desc !== null && (typeof desc.get === 'function' || typeof desc.set === 'function')) {
7789
- defineProperty(controller, prop, dependentKeyCompat({
7790
- get: desc.get,
7791
- set: desc.set
7792
- }));
7793
- }
7794
- }
7795
- addObserver(controller, `${prop}.[]`, controller, controller._qpChanged, false);
7796
- });
7797
- }
7798
- function getEngineRouteName(engine, routeName) {
7799
- if (engine.routable) {
7800
- let prefix = engine.mountPoint;
7801
- if (routeName === 'application') {
7802
- return prefix;
7803
- } else {
7804
- return `${prefix}.${routeName}`;
7805
- }
7806
- }
7807
- return routeName;
7808
- }
7809
- const defaultSerialize = Route.prototype.serialize;
7810
- function hasDefaultSerialize(route) {
7811
- return route.serialize === defaultSerialize;
7812
- }
7813
-
7814
- // Set these here so they can be overridden with extend
7815
- Route.reopen({
7816
- mergedProperties: ['queryParams'],
7817
- queryParams: {},
7818
- templateName: null,
7819
- controllerName: null,
7820
- send(...args) {
7821
- (isDevelopingApp() && !(!this.isDestroying && !this.isDestroyed) && assert(`Attempted to call .send() with the action '${args[0]}' on the destroyed route '${this.routeName}'.`, !this.isDestroying && !this.isDestroyed));
7822
- if (this._router && this._router._routerMicrolib || !isTesting()) {
7823
- this._router.send(...args);
7824
- } else {
7825
- let name = args.shift();
7826
- let action = this.actions[name];
7827
- if (action) {
7828
- return action.apply(this, args);
7829
- }
7830
- }
7831
- },
7832
- /**
7833
- The controller associated with this route.
7834
- Example
7835
- ```app/routes/form.js
7836
- import Route from '@ember/routing/route';
7837
- import { action } from '@ember/object';
7838
- export default class FormRoute extends Route {
7839
- @action
7840
- willTransition(transition) {
7841
- if (this.controller.get('userHasEnteredData') &&
7842
- !confirm('Are you sure you want to abandon progress?')) {
7843
- transition.abort();
7844
- } else {
7845
- // Bubble the `willTransition` action so that
7846
- // parent routes can decide whether or not to abort.
7847
- return true;
7848
- }
7849
- }
7850
- }
7851
- ```
7852
- @property controller
7853
- @type Controller
7854
- @since 1.6.0
7855
- @public
7856
- */
7857
-
7858
- actions: {
7859
- /**
7860
- This action is called when one or more query params have changed. Bubbles.
7861
- @method queryParamsDidChange
7862
- @param changed {Object} Keys are names of query params that have changed.
7863
- @param totalPresent {Object} Keys are names of query params that are currently set.
7864
- @param removed {Object} Keys are names of query params that have been removed.
7865
- @returns {boolean}
7866
- @private
7867
- */
7868
- queryParamsDidChange(changed, _totalPresent, removed) {
7869
- // SAFETY: Since `_qp` is protected we can't infer the type
7870
- let qpMap = get(this, '_qp').map;
7871
- let totalChanged = Object.keys(changed).concat(Object.keys(removed));
7872
- for (let change of totalChanged) {
7873
- let qp = qpMap[change];
7874
- if (qp) {
7875
- let options = this._optionsForQueryParam(qp);
7876
- (isDevelopingApp() && !(options && typeof options === 'object') && assert('options exists', options && typeof options === 'object'));
7877
- if (get(options, 'refreshModel') && this._router.currentState) {
7878
- this.refresh();
7879
- break;
7880
- }
7881
- }
7882
- }
7883
- return true;
7884
- },
7885
- finalizeQueryParamChange(params, finalParams, transition) {
7886
- if (this.fullRouteName !== 'application') {
7887
- return true;
7888
- }
7889
-
7890
- // Transition object is absent for intermediate transitions.
7891
- if (!transition) {
7892
- return;
7893
- }
7894
- let routeInfos = transition[STATE_SYMBOL].routeInfos;
7895
- let router = this._router;
7896
- let qpMeta = router._queryParamsFor(routeInfos);
7897
- let changes = router._qpUpdates;
7898
- let qpUpdated = false;
7899
- let replaceUrl;
7900
- stashParamNames(router, routeInfos);
7901
- for (let qp of qpMeta.qps) {
7902
- let route = qp.route;
7903
- let controller = route.controller;
7904
- let presentKey = qp.urlKey in params && qp.urlKey;
7905
-
7906
- // Do a reverse lookup to see if the changed query
7907
- // param URL key corresponds to a QP property on
7908
- // this controller.
7909
- let value;
7910
- let svalue;
7911
- if (changes.has(qp.urlKey)) {
7912
- // Value updated in/before setupController
7913
- value = get(controller, qp.prop);
7914
- svalue = route.serializeQueryParam(value, qp.urlKey, qp.type);
7915
- } else {
7916
- if (presentKey) {
7917
- svalue = params[presentKey];
7918
- if (svalue !== undefined) {
7919
- value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type);
7920
- }
7921
- } else {
7922
- // No QP provided; use default value.
7923
- svalue = qp.serializedDefaultValue;
7924
- value = copyDefaultValue(qp.defaultValue);
7925
- }
7926
- }
7927
-
7928
- // SAFETY: Since `_qp` is protected we can't infer the type
7929
- controller._qpDelegate = get(route, '_qp').states.inactive;
7930
- let thisQueryParamChanged = svalue !== qp.serializedValue;
7931
- if (thisQueryParamChanged) {
7932
- if (transition.queryParamsOnly && replaceUrl !== false) {
7933
- let options = route._optionsForQueryParam(qp);
7934
- let replaceConfigValue = get(options, 'replace');
7935
- if (replaceConfigValue) {
7936
- replaceUrl = true;
7937
- } else if (replaceConfigValue === false) {
7938
- // Explicit pushState wins over any other replaceStates.
7939
- replaceUrl = false;
7940
- }
7941
- }
7942
- set(controller, qp.prop, value);
7943
- qpUpdated = true;
7944
- }
7945
-
7946
- // Stash current serialized value of controller.
7947
- qp.serializedValue = svalue;
7948
- let thisQueryParamHasDefaultValue = qp.serializedDefaultValue === svalue;
7949
- if (!thisQueryParamHasDefaultValue) {
7950
- finalParams.push({
7951
- value: svalue,
7952
- visible: true,
7953
- key: presentKey || qp.urlKey
7954
- });
7955
- }
7956
- }
7957
-
7958
- // Some QPs have been updated, and those changes need to be propogated
7959
- // immediately. Eventually, we should work on making this async somehow.
7960
- if (qpUpdated === true) {
7961
- flushAsyncObservers(false);
7962
- }
7963
- if (replaceUrl) {
7964
- transition.method('replace');
7965
- }
7966
- qpMeta.qps.forEach(qp => {
7967
- // SAFETY: Since `_qp` is protected we can't infer the type
7968
- let routeQpMeta = get(qp.route, '_qp');
7969
- let finalizedController = qp.route.controller;
7970
- finalizedController['_qpDelegate'] = get(routeQpMeta, 'states.active');
7971
- });
7972
- router._qpUpdates.clear();
7973
- return;
7974
- }
7975
- }
7976
- });
7977
-
7978
- /**
7979
- @module @ember/routing/router
7980
- */
7981
-
7982
- function defaultDidTransition(infos) {
7983
- updatePaths(this);
7984
- this._cancelSlowTransitionTimer();
7985
- this.notifyPropertyChange('url');
7986
- this.set('currentState', this.targetState);
7987
- if (isDevelopingApp()) {
7988
- // @ts-expect-error namespace isn't public
7989
- if (this.namespace.LOG_TRANSITIONS) {
7990
- // eslint-disable-next-line no-console
7991
- console.log(`Transitioned into '${EmberRouter._routePath(infos)}'`);
7992
- }
7993
- }
7994
- }
7995
- function defaultWillTransition(oldInfos, newInfos) {
7996
- if (isDevelopingApp()) {
7997
- // @ts-expect-error namespace isn't public
7998
- if (this.namespace.LOG_TRANSITIONS) {
7999
- // eslint-disable-next-line no-console
8000
- console.log(`Preparing to transition from '${EmberRouter._routePath(oldInfos)}' to '${EmberRouter._routePath(newInfos)}'`);
8001
- }
8002
- }
8003
- }
8004
- let freezeRouteInfo;
8005
- if (isDevelopingApp()) {
8006
- freezeRouteInfo = transition => {
8007
- if (transition.from !== null && !Object.isFrozen(transition.from)) {
8008
- Object.freeze(transition.from);
8009
- }
8010
- if (transition.to !== null && !Object.isFrozen(transition.to)) {
8011
- Object.freeze(transition.to);
8012
- }
8013
- };
8014
- }
8015
- function K() {
8016
- return this;
8017
- }
8018
- const {
8019
- slice
8020
- } = Array.prototype;
8021
-
8022
- /**
8023
- The `EmberRouter` class manages the application state and URLs. Refer to
8024
- the [routing guide](https://guides.emberjs.com/release/routing/) for documentation.
8025
-
8026
- @class EmberRouter
8027
- @extends EmberObject
8028
- @uses Evented
8029
- @public
8030
- */
8031
- class EmberRouter extends EmberObject.extend(Evented) {
8032
- /**
8033
- Represents the URL of the root of the application, often '/'. This prefix is
8034
- assumed on all routes defined on this router.
8035
- @property rootURL
8036
- @default '/'
8037
- @public
8038
- */
8039
- // Set with reopen to allow overriding via extend
8040
-
8041
- /**
8042
- The `location` property determines the type of URL's that your
8043
- application will use.
8044
- The following location types are currently available:
8045
- * `history` - use the browser's history API to make the URLs look just like any standard URL
8046
- * `hash` - use `#` to separate the server part of the URL from the Ember part: `/blog/#/posts/new`
8047
- * `none` - do not store the Ember URL in the actual browser URL (mainly used for testing)
8048
- * `auto` - use the best option based on browser capabilities: `history` if possible, then `hash` if possible, otherwise `none`
8049
- This value is defaulted to `history` by the `locationType` setting of `/config/environment.js`
8050
- @property location
8051
- @default 'hash'
8052
- @see {Location}
8053
- @public
8054
- */
8055
- // Set with reopen to allow overriding via extend
8056
-
8057
- _routerMicrolib;
8058
- _didSetupRouter = false;
8059
- _initialTransitionStarted = false;
8060
- currentURL = null;
8061
- currentRouteName = null;
8062
- currentPath = null;
8063
- currentRoute = null;
8064
- _qpCache = Object.create(null);
8065
-
8066
- // Set of QueryParam['urlKey']
8067
- _qpUpdates = new Set();
8068
- _queuedQPChanges = {};
8069
- _bucketCache;
8070
- _toplevelView = null;
8071
- _handledErrors = new Set();
8072
- _engineInstances = Object.create(null);
8073
- _engineInfoByRoute = Object.create(null);
8074
- _routerService;
8075
- _slowTransitionTimer = null;
8076
- namespace;
8077
-
8078
- // Begin Evented
8079
-
8080
- // End Evented
8081
-
8082
- // Set with reopenClass
8083
- static dslCallbacks;
8084
-
8085
- /**
8086
- The `Router.map` function allows you to define mappings from URLs to routes
8087
- in your application. These mappings are defined within the
8088
- supplied callback function using `this.route`.
8089
- The first parameter is the name of the route which is used by default as the
8090
- path name as well.
8091
- The second parameter is the optional options hash. Available options are:
8092
- * `path`: allows you to provide your own path as well as mark dynamic
8093
- segments.
8094
- * `resetNamespace`: false by default; when nesting routes, ember will
8095
- combine the route names to form the fully-qualified route name, which is
8096
- used with `{{link-to}}` or manually transitioning to routes. Setting
8097
- `resetNamespace: true` will cause the route not to inherit from its
8098
- parent route's names. This is handy for preventing extremely long route names.
8099
- Keep in mind that the actual URL path behavior is still retained.
8100
- The third parameter is a function, which can be used to nest routes.
8101
- Nested routes, by default, will have the parent route tree's route name and
8102
- path prepended to it's own.
8103
- ```app/router.js
8104
- Router.map(function(){
8105
- this.route('post', { path: '/post/:post_id' }, function() {
8106
- this.route('edit');
8107
- this.route('comments', { resetNamespace: true }, function() {
8108
- this.route('new');
8109
- });
8110
- });
8111
- });
8112
- ```
8113
- @method map
8114
- @param callback
8115
- @public
8116
- */
8117
- static map(callback) {
8118
- if (!this.dslCallbacks) {
8119
- this.dslCallbacks = [];
8120
- // FIXME: Can we remove this?
8121
- this.reopenClass({
8122
- dslCallbacks: this.dslCallbacks
8123
- });
8124
- }
8125
- this.dslCallbacks.push(callback);
8126
- return this;
8127
- }
8128
- static _routePath(routeInfos) {
8129
- let path = [];
8130
-
8131
- // We have to handle coalescing resource names that
8132
- // are prefixed with their parent's names, e.g.
8133
- // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz'
8134
-
8135
- function intersectionMatches(a1, a2) {
8136
- for (let i = 0; i < a1.length; ++i) {
8137
- if (a1[i] !== a2[i]) {
8138
- return false;
8139
- }
8140
- }
8141
- return true;
8142
- }
8143
- let name, nameParts, oldNameParts;
8144
- for (let i = 1; i < routeInfos.length; i++) {
8145
- let routeInfo = routeInfos[i];
8146
- (isDevelopingApp() && !(routeInfo) && assert('has routeInfo', routeInfo));
8147
- name = routeInfo.name;
8148
- nameParts = name.split('.');
8149
- oldNameParts = slice.call(path);
8150
- while (oldNameParts.length) {
8151
- if (intersectionMatches(oldNameParts, nameParts)) {
8152
- break;
8153
- }
8154
- oldNameParts.shift();
8155
- }
8156
- path.push(...nameParts.slice(oldNameParts.length));
8157
- }
8158
- return path.join('.');
8159
- }
8160
-
8161
- // Note that owner is actually required in this scenario, but since it is strictly
8162
- // optional in other contexts trying to make it required here confuses TS.
8163
- constructor(owner) {
8164
- super(owner);
8165
- (isDevelopingApp() && !(owner) && assert('BUG: Missing owner', owner));
8166
- this._resetQueuedQueryParameterChanges();
8167
- this.namespace = owner.lookup('application:main');
8168
- let bucketCache = owner.lookup(privatize`-bucket-cache:main`);
8169
- (isDevelopingApp() && !(bucketCache instanceof BucketCache) && assert('BUG: BucketCache should always be present', bucketCache instanceof BucketCache));
8170
- this._bucketCache = bucketCache;
8171
- let routerService = owner.lookup('service:router');
8172
- (isDevelopingApp() && !(routerService !== undefined) && assert('BUG: RouterService should always be present', routerService !== undefined));
8173
- this._routerService = routerService;
8174
- }
8175
- _initRouterJs() {
8176
- let location = get(this, 'location');
8177
- let router = this;
8178
- const owner = getOwner$1(this);
8179
- (isDevelopingApp() && !(owner) && assert('Router is unexpectedly missing an owner', owner));
8180
- let seen = Object.create(null);
8181
- class PrivateRouter extends Router {
8182
- getRoute(name) {
8183
- let routeName = name;
8184
- let routeOwner = owner;
8185
- let engineInfo = router._engineInfoByRoute[routeName];
8186
- if (engineInfo) {
8187
- let engineInstance = router._getEngineInstance(engineInfo);
8188
- routeOwner = engineInstance;
8189
- routeName = engineInfo.localFullName;
8190
- }
8191
- let fullRouteName = `route:${routeName}`;
8192
- (isDevelopingApp() && !(routeOwner) && assert('Route is unexpectedly missing an owner', routeOwner));
8193
- let route = routeOwner.lookup(fullRouteName);
8194
- if (seen[name]) {
8195
- (isDevelopingApp() && !(route) && assert('seen routes should exist', route));
8196
- return route;
8197
- }
8198
- seen[name] = true;
8199
- if (!route) {
8200
- // SAFETY: this is configured in `commonSetupRegistry` in the
8201
- // `@ember/application/lib` package.
8202
- let DefaultRoute = routeOwner.factoryFor('route:basic').class;
8203
- routeOwner.register(fullRouteName, DefaultRoute.extend());
8204
- route = routeOwner.lookup(fullRouteName);
8205
- if (isDevelopingApp()) {
8206
- if (router.namespace.LOG_ACTIVE_GENERATION) {
8207
- info(`generated -> ${fullRouteName}`, {
8208
- fullName: fullRouteName
8209
- });
8210
- }
8211
- }
8212
- }
8213
- route._setRouteName(routeName);
8214
- if (engineInfo && !hasDefaultSerialize(route)) {
8215
- throw new Error('Defining a custom serialize method on an Engine route is not supported.');
8216
- }
8217
- return route;
8218
- }
8219
- getSerializer(name) {
8220
- let engineInfo = router._engineInfoByRoute[name];
8221
-
8222
- // If this is not an Engine route, we fall back to the handler for serialization
8223
- if (!engineInfo) {
8224
- return;
8225
- }
8226
- return engineInfo.serializeMethod || defaultSerialize;
8227
- }
8228
- updateURL(path) {
8229
- once(() => {
8230
- location.setURL(path);
8231
- set(router, 'currentURL', path);
8232
- });
8233
- }
8234
-
8235
- // TODO: merge into routeDidChange
8236
- didTransition(infos) {
8237
- (isDevelopingApp() && !(router.didTransition === defaultDidTransition) && assert('You attempted to override the "didTransition" method which has been deprecated. Please inject the router service and listen to the "routeDidChange" event.', router.didTransition === defaultDidTransition));
8238
- router.didTransition(infos);
8239
- }
8240
-
8241
- // TODO: merge into routeWillChange
8242
- willTransition(oldInfos, newInfos) {
8243
- (isDevelopingApp() && !(router.willTransition === defaultWillTransition) && assert('You attempted to override the "willTransition" method which has been deprecated. Please inject the router service and listen to the "routeWillChange" event.', router.willTransition === defaultWillTransition));
8244
- router.willTransition(oldInfos, newInfos);
8245
- }
8246
- triggerEvent(routeInfos, ignoreFailure, name, args) {
8247
- return triggerEvent.bind(router)(routeInfos, ignoreFailure, name, args);
8248
- }
8249
- routeWillChange(transition) {
8250
- router.trigger('routeWillChange', transition);
8251
- if (isDevelopingApp()) {
8252
- freezeRouteInfo(transition);
8253
- }
8254
- router._routerService.trigger('routeWillChange', transition);
8255
-
8256
- // in case of intermediate transition we update the current route
8257
- // to make router.currentRoute.name consistent with router.currentRouteName
8258
- // see https://github.com/emberjs/ember.js/issues/19449
8259
- if (transition.isIntermediate) {
8260
- router.set('currentRoute', transition.to);
8261
- }
8262
- }
8263
- routeDidChange(transition) {
8264
- router.set('currentRoute', transition.to);
8265
- once(() => {
8266
- router.trigger('routeDidChange', transition);
8267
- if (isDevelopingApp()) {
8268
- freezeRouteInfo(transition);
8269
- }
8270
- router._routerService.trigger('routeDidChange', transition);
8271
- });
8272
- }
8273
- transitionDidError(error, transition) {
8274
- if (error.wasAborted || transition.isAborted) {
8275
- // If the error was a transition erorr or the transition aborted
8276
- // log the abort.
8277
- return logAbort(transition);
8278
- } else {
8279
- // Otherwise trigger the "error" event to attempt an intermediate
8280
- // transition into an error substate
8281
- transition.trigger(false, 'error', error.error, transition, error.route);
8282
- if (router._isErrorHandled(error.error)) {
8283
- // If we handled the error with a substate just roll the state back on
8284
- // the transition and send the "routeDidChange" event for landing on
8285
- // the error substate and return the error.
8286
- transition.rollback();
8287
- this.routeDidChange(transition);
8288
- return error.error;
8289
- } else {
8290
- // If it was not handled, abort the transition completely and return
8291
- // the error.
8292
- transition.abort();
8293
- return error.error;
8294
- }
8295
- }
8296
- }
8297
- replaceURL(url) {
8298
- if (location.replaceURL) {
8299
- let doReplaceURL = () => {
8300
- location.replaceURL(url);
8301
- set(router, 'currentURL', url);
8302
- };
8303
- once(doReplaceURL);
8304
- } else {
8305
- this.updateURL(url);
8306
- }
8307
- }
8308
- }
8309
- let routerMicrolib = this._routerMicrolib = new PrivateRouter();
8310
- let dslCallbacks = this.constructor.dslCallbacks || [K];
8311
- let dsl = this._buildDSL();
8312
- dsl.route('application', {
8313
- path: '/',
8314
- resetNamespace: true,
8315
- overrideNameAssertion: true
8316
- }, function () {
8317
- for (let i = 0; i < dslCallbacks.length; i++) {
8318
- dslCallbacks[i].call(this);
8319
- }
8320
- });
8321
- if (isDevelopingApp()) {
8322
- if (this.namespace.LOG_TRANSITIONS_INTERNAL) {
8323
- routerMicrolib.log = console.log.bind(console); // eslint-disable-line no-console
8324
- }
8325
- }
8326
- routerMicrolib.map(dsl.generate());
8327
- }
8328
- _buildDSL() {
8329
- let enableLoadingSubstates = this._hasModuleBasedResolver();
8330
- let router = this;
8331
- const owner = getOwner$1(this);
8332
- (isDevelopingApp() && !(owner) && assert('Router is unexpectedly missing an owner', owner));
8333
- let options = {
8334
- enableLoadingSubstates,
8335
- resolveRouteMap(name) {
8336
- return owner.factoryFor(`route-map:${name}`);
8337
- },
8338
- addRouteForEngine(name, engineInfo) {
8339
- if (!router._engineInfoByRoute[name]) {
8340
- router._engineInfoByRoute[name] = engineInfo;
8341
- }
8342
- }
8343
- };
8344
- return new DSLImpl(null, options);
8345
- }
8346
-
8347
- /*
8348
- Resets all pending query parameter changes.
8349
- Called after transitioning to a new route
8350
- based on query parameter changes.
8351
- */
8352
- _resetQueuedQueryParameterChanges() {
8353
- this._queuedQPChanges = {};
8354
- }
8355
- _hasModuleBasedResolver() {
8356
- let owner = getOwner$1(this);
8357
- (isDevelopingApp() && !(owner) && assert('Router is unexpectedly missing an owner', owner));
8358
- let resolver = get(owner, 'application.__registry__.resolver.moduleBasedResolver');
8359
- return Boolean(resolver);
8360
- }
8361
-
8362
- /**
8363
- Initializes the current router instance and sets up the change handling
8364
- event listeners used by the instances `location` implementation.
8365
- A property named `initialURL` will be used to determine the initial URL.
8366
- If no value is found `/` will be used.
8367
- @method startRouting
8368
- @private
8369
- */
8370
- startRouting() {
8371
- if (this.setupRouter()) {
8372
- let initialURL = get(this, 'initialURL');
8373
- if (initialURL === undefined) {
8374
- initialURL = get(this, 'location').getURL();
8375
- }
8376
- let initialTransition = this.handleURL(initialURL);
8377
- if (initialTransition && initialTransition.error) {
8378
- throw initialTransition.error;
8379
- }
8380
- }
8381
- }
8382
- setupRouter() {
8383
- if (this._didSetupRouter) {
8384
- return false;
8385
- }
8386
- this._didSetupRouter = true;
8387
- this._setupLocation();
8388
- let location = get(this, 'location');
8389
-
8390
- // Allow the Location class to cancel the router setup while it refreshes
8391
- // the page
8392
- if (get(location, 'cancelRouterSetup')) {
8393
- return false;
8394
- }
8395
- this._initRouterJs();
8396
- location.onUpdateURL(url => {
8397
- this.handleURL(url);
8398
- });
8399
- return true;
8400
- }
8401
- _setOutlets() {
8402
- // This is triggered async during Route#willDestroy.
8403
- // If the router is also being destroyed we do not want to
8404
- // to create another this._toplevelView (and leak the renderer)
8405
- if (this.isDestroying || this.isDestroyed) {
8406
- return;
8407
- }
8408
- let routeInfos = this._routerMicrolib.currentRouteInfos;
8409
- if (!routeInfos) {
8410
- return;
8411
- }
8412
- let root = null;
8413
- let parent = null;
8414
- for (let routeInfo of routeInfos) {
8415
- let route = routeInfo.route;
8416
- let render = getRenderState(route);
8417
- if (render) {
8418
- let state = {
8419
- render,
8420
- outlets: {
8421
- main: undefined
8422
- }
8423
- };
8424
- if (parent) {
8425
- parent.outlets.main = state;
8426
- } else {
8427
- root = state;
8428
- }
8429
- parent = state;
8430
- } else {
8431
- // It used to be that we would create a stub entry and keep traversing,
8432
- // but I don't think that is necessary anymore – if a parent route did
8433
- // not render, then the child routes have nowhere to render into these
8434
- // days. That wasn't always the case since in the past any route can
8435
- // render into any other route's outlets.
8436
- break;
8437
- }
8438
- }
8439
-
8440
- // when a transitionTo happens after the validation phase
8441
- // during the initial transition _setOutlets is called
8442
- // when no routes are active. However, it will get called
8443
- // again with the correct values during the next turn of
8444
- // the runloop
8445
- if (root === null) {
8446
- return;
8447
- }
8448
- if (!this._toplevelView) {
8449
- let owner = getOwner$1(this);
8450
- (isDevelopingApp() && !(owner) && assert('Router is unexpectedly missing an owner', owner)); // SAFETY: we don't presently have any type registries internally to make
8451
- // this safe, so in each of these cases we assume that nothing *else* is
8452
- // registered at this `FullName`, and simply check to make sure that
8453
- // *something* is.
8454
- let OutletView = owner.factoryFor('view:-outlet');
8455
- (isDevelopingApp() && !(OutletView !== undefined) && assert('[BUG] unexpectedly missing `view:-outlet`', OutletView !== undefined));
8456
- let application = owner.lookup('application:main');
8457
- (isDevelopingApp() && !(application !== undefined) && assert('[BUG] unexpectedly missing `application:-main`', application !== undefined));
8458
- let environment = owner.lookup('-environment:main');
8459
- (isDevelopingApp() && !(environment !== undefined) && assert('[BUG] unexpectedly missing `-environment:main`', environment !== undefined));
8460
- let template = owner.lookup('template:-outlet');
8461
- (isDevelopingApp() && !(template !== undefined) && assert('[BUG] unexpectedly missing `template:-outlet`', template !== undefined));
8462
- this._toplevelView = OutletView.create({
8463
- environment,
8464
- template,
8465
- application
8466
- });
8467
- this._toplevelView.setOutletState(root);
8468
-
8469
- // TODO(SAFETY): At least one test runs without this set correctly. At a
8470
- // later time, update the test to configure this correctly. The test ID:
8471
- // `Router Service - non application test: RouterService#transitionTo with basic route`
8472
- let instance = owner.lookup('-application-instance:main');
8473
- // let instance = owner.lookup('-application-instance:main') as ApplicationInstance | undefined;
8474
- // assert('[BUG] unexpectedly missing `-application-instance:main`', instance !== undefined);
8475
-
8476
- if (instance) {
8477
- // SAFETY: LOL. This is calling a deprecated API with a type that we
8478
- // cannot actually confirm at a type level *is* a `ViewMixin`. Seems:
8479
- // not great on multiple fronts!
8480
- instance.didCreateRootView(this._toplevelView);
8481
- }
8482
- } else {
8483
- this._toplevelView.setOutletState(root);
8484
- }
8485
- }
8486
- handleURL(url) {
8487
- // Until we have an ember-idiomatic way of accessing #hashes, we need to
8488
- // remove it because router.js doesn't know how to handle it.
8489
- let _url = url.split(/#(.+)?/)[0];
8490
- return this._doURLTransition('handleURL', _url);
8491
- }
8492
- _doURLTransition(routerJsMethod, url) {
8493
- this._initialTransitionStarted = true;
8494
- let transition = this._routerMicrolib[routerJsMethod](url || '/');
8495
- didBeginTransition(transition, this);
8496
- return transition;
8497
- }
8498
-
8499
- /**
8500
- Transition the application into another route. The route may
8501
- be either a single route or route path:
8502
- @method transitionTo
8503
- @param {String} [name] the name of the route or a URL
8504
- @param {...Object} models the model(s) or identifier(s) to be used while
8505
- transitioning to the route.
8506
- @param {Object} [options] optional hash with a queryParams property
8507
- containing a mapping of query parameters
8508
- @return {Transition} the transition object associated with this
8509
- attempted transition
8510
- @public
8511
- */
8512
- transitionTo(...args) {
8513
- if (resemblesURL(args[0])) {
8514
- (isDevelopingApp() && !(!this.isDestroying && !this.isDestroyed) && assert(`A transition was attempted from '${this.currentRouteName}' to '${args[0]}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed));
8515
- return this._doURLTransition('transitionTo', args[0]);
8516
- }
8517
- let {
8518
- routeName,
8519
- models,
8520
- queryParams
8521
- } = extractRouteArgs(args);
8522
- (isDevelopingApp() && !(!this.isDestroying && !this.isDestroyed) && assert(`A transition was attempted from '${this.currentRouteName}' to '${routeName}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed));
8523
- return this._doTransition(routeName, models, queryParams);
8524
- }
8525
- intermediateTransitionTo(name, ...args) {
8526
- this._routerMicrolib.intermediateTransitionTo(name, ...args);
8527
- updatePaths(this);
8528
- if (isDevelopingApp()) {
8529
- let infos = this._routerMicrolib.currentRouteInfos;
8530
- if (this.namespace.LOG_TRANSITIONS) {
8531
- (isDevelopingApp() && !(infos) && assert('expected infos to be set', infos)); // eslint-disable-next-line no-console
8532
- console.log(`Intermediate-transitioned into '${EmberRouter._routePath(infos)}'`);
8533
- }
8534
- }
8535
- }
8536
-
8537
- /**
8538
- Similar to `transitionTo`, but instead of adding the destination to the browser's URL history,
8539
- it replaces the entry for the current route.
8540
- When the user clicks the "back" button in the browser, there will be fewer steps.
8541
- This is most commonly used to manage redirects in a way that does not cause confusing additions
8542
- to the user's browsing history.
8543
- @method replaceWith
8544
- @param {String} [name] the name of the route or a URL
8545
- @param {...Object} models the model(s) or identifier(s) to be used while
8546
- transitioning to the route.
8547
- @param {Object} [options] optional hash with a queryParams property
8548
- containing a mapping of query parameters
8549
- @return {Transition} the transition object associated with this
8550
- attempted transition
8551
- @public
8552
- */
8553
- replaceWith(...args) {
8554
- return this.transitionTo(...args).method('replace');
8555
- }
8556
- generate(name, ...args) {
8557
- let url = this._routerMicrolib.generate(name, ...args);
8558
- (isDevelopingApp() && !(typeof this.location !== 'string') && assert('expected non-string location', typeof this.location !== 'string'));
8559
- return this.location.formatURL(url);
8560
- }
8561
-
8562
- /**
8563
- Determines if the supplied route is currently active.
8564
- @method isActive
8565
- @param routeName
8566
- @return {Boolean}
8567
- @private
8568
- */
8569
- isActive(routeName) {
8570
- return this._routerMicrolib.isActive(routeName);
8571
- }
8572
-
8573
- /**
8574
- An alternative form of `isActive` that doesn't require
8575
- manual concatenation of the arguments into a single
8576
- array.
8577
- @method isActiveIntent
8578
- @param routeName
8579
- @param models
8580
- @param queryParams
8581
- @return {Boolean}
8582
- @private
8583
- @since 1.7.0
8584
- */
8585
- isActiveIntent(routeName, models, queryParams) {
8586
- return this.currentState.isActiveIntent(routeName, models, queryParams);
8587
- }
8588
- send(name, ...args) {
8589
- /*name, context*/
8590
- this._routerMicrolib.trigger(name, ...args);
8591
- }
8592
-
8593
- /**
8594
- Does this router instance have the given route.
8595
- @method hasRoute
8596
- @return {Boolean}
8597
- @private
8598
- */
8599
- hasRoute(route) {
8600
- return this._routerMicrolib.hasRoute(route);
8601
- }
8602
-
8603
- /**
8604
- Resets the state of the router by clearing the current route
8605
- handlers and deactivating them.
8606
- @private
8607
- @method reset
8608
- */
8609
- reset() {
8610
- this._didSetupRouter = false;
8611
- this._initialTransitionStarted = false;
8612
- if (this._routerMicrolib) {
8613
- this._routerMicrolib.reset();
8614
- }
8615
- }
8616
- willDestroy() {
8617
- if (this._toplevelView) {
8618
- this._toplevelView.destroy();
8619
- this._toplevelView = null;
8620
- }
8621
- super.willDestroy();
8622
- this.reset();
8623
- let instances = this._engineInstances;
8624
- for (let name in instances) {
8625
- let instanceMap = instances[name];
8626
- (isDevelopingApp() && !(instanceMap) && assert('has instanceMap', instanceMap));
8627
- for (let id in instanceMap) {
8628
- let instance = instanceMap[id];
8629
- (isDevelopingApp() && !(instance) && assert('has instance', instance));
8630
- run(instance, 'destroy');
8631
- }
8632
- }
8633
- }
8634
-
8635
- /*
8636
- Called when an active route's query parameter has changed.
8637
- These changes are batched into a runloop run and trigger
8638
- a single transition.
8639
- */
8640
- _activeQPChanged(queryParameterName, newValue) {
8641
- this._queuedQPChanges[queryParameterName] = newValue;
8642
- once(this, this._fireQueryParamTransition);
8643
- }
8644
-
8645
- // The queryParameterName is QueryParam['urlKey']
8646
- _updatingQPChanged(queryParameterName) {
8647
- this._qpUpdates.add(queryParameterName);
8648
- }
8649
-
8650
- /*
8651
- Triggers a transition to a route based on query parameter changes.
8652
- This is called once per runloop, to batch changes.
8653
- e.g.
8654
- if these methods are called in succession:
8655
- this._activeQPChanged('foo', '10');
8656
- // results in _queuedQPChanges = { foo: '10' }
8657
- this._activeQPChanged('bar', false);
8658
- // results in _queuedQPChanges = { foo: '10', bar: false }
8659
- _queuedQPChanges will represent both of these changes
8660
- and the transition using `transitionTo` will be triggered
8661
- once.
8662
- */
8663
- _fireQueryParamTransition() {
8664
- this.transitionTo({
8665
- queryParams: this._queuedQPChanges
8666
- });
8667
- this._resetQueuedQueryParameterChanges();
8668
- }
8669
- _setupLocation() {
8670
- let location = this.location;
8671
- let rootURL = this.rootURL;
8672
- let owner = getOwner$1(this);
8673
- (isDevelopingApp() && !(owner) && assert('Router is unexpectedly missing an owner', owner));
8674
- if ('string' === typeof location) {
8675
- let resolvedLocation = owner.lookup(`location:${location}`);
8676
- (isDevelopingApp() && !(resolvedLocation) && assert(`Could not resolve a location class at 'location:${location}'`, resolvedLocation));
8677
- location = set(this, 'location', resolvedLocation);
8678
- }
8679
- if (location !== null && typeof location === 'object') {
8680
- if (rootURL) {
8681
- set(location, 'rootURL', rootURL);
8682
- }
8683
-
8684
- // ensure that initState is called AFTER the rootURL is set on
8685
- // the location instance
8686
- if (typeof location.initState === 'function') {
8687
- location.initState();
8688
- }
8689
- }
8690
- }
8691
-
8692
- /**
8693
- Serializes the given query params according to their QP meta information.
8694
- @private
8695
- @method _serializeQueryParams
8696
- @param {Arrray<RouteInfo>} routeInfos
8697
- @param {Object} queryParams
8698
- @return {Void}
8699
- */
8700
- _serializeQueryParams(routeInfos, queryParams) {
8701
- forEachQueryParam(this, routeInfos, queryParams, (key, value, qp) => {
8702
- if (qp) {
8703
- delete queryParams[key];
8704
- queryParams[qp.urlKey] = qp.route.serializeQueryParam(value, qp.urlKey, qp.type);
8705
- } else if (value === undefined) {
8706
- return; // We don't serialize undefined values
8707
- } else {
8708
- queryParams[key] = this._serializeQueryParam(value, typeOf(value));
8709
- }
8710
- });
8711
- }
8712
-
8713
- /**
8714
- Serializes the value of a query parameter based on a type
8715
- @private
8716
- @method _serializeQueryParam
8717
- @param {Object} value
8718
- @param {String} type
8719
- */
8720
- _serializeQueryParam(value, type) {
8721
- if (value === null || value === undefined) {
8722
- return value;
8723
- } else if (type === 'array') {
8724
- return JSON.stringify(value);
8725
- }
8726
- return `${value}`;
8727
- }
8728
-
8729
- /**
8730
- Deserializes the given query params according to their QP meta information.
8731
- @private
8732
- @method _deserializeQueryParams
8733
- @param {Array<RouteInfo>} routeInfos
8734
- @param {Object} queryParams
8735
- @return {Void}
8736
- */
8737
- _deserializeQueryParams(routeInfos, queryParams) {
8738
- forEachQueryParam(this, routeInfos, queryParams, (key, value, qp) => {
8739
- // If we don't have QP meta info for a given key, then we do nothing
8740
- // because all values will be treated as strings
8741
- if (qp) {
8742
- delete queryParams[key];
8743
- queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type);
8744
- }
8745
- });
8746
- }
8747
-
8748
- /**
8749
- Deserializes the value of a query parameter based on a default type
8750
- @private
8751
- @method _deserializeQueryParam
8752
- @param {Object} value
8753
- @param {String} defaultType
8754
- */
8755
- _deserializeQueryParam(value, defaultType) {
8756
- if (value === null || value === undefined) {
8757
- return value;
8758
- } else if (defaultType === 'boolean') {
8759
- return value === 'true';
8760
- } else if (defaultType === 'number') {
8761
- return Number(value).valueOf();
8762
- } else if (defaultType === 'array') {
8763
- return A(JSON.parse(value));
8764
- }
8765
- return value;
8766
- }
8767
-
8768
- /**
8769
- Removes (prunes) any query params with default values from the given QP
8770
- object. Default values are determined from the QP meta information per key.
8771
- @private
8772
- @method _pruneDefaultQueryParamValues
8773
- @param {Array<RouteInfo>} routeInfos
8774
- @param {Object} queryParams
8775
- @return {Void}
8776
- */
8777
- _pruneDefaultQueryParamValues(routeInfos, queryParams) {
8778
- let qps = this._queryParamsFor(routeInfos);
8779
- for (let key in queryParams) {
8780
- let qp = qps.map[key];
8781
- if (qp && qp.serializedDefaultValue === queryParams[key]) {
8782
- delete queryParams[key];
8783
- }
8784
- }
8785
- }
8786
- _doTransition(_targetRouteName, models, _queryParams, _fromRouterService) {
8787
- let targetRouteName = _targetRouteName || getActiveTargetName(this._routerMicrolib);
8788
- (isDevelopingApp() && !(Boolean(targetRouteName) && this._routerMicrolib.hasRoute(targetRouteName)) && assert(`The route ${targetRouteName} was not found`, Boolean(targetRouteName) && this._routerMicrolib.hasRoute(targetRouteName)));
8789
- this._initialTransitionStarted = true;
8790
- let queryParams = {};
8791
- this._processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams);
8792
- Object.assign(queryParams, _queryParams);
8793
- this._prepareQueryParams(targetRouteName, models, queryParams, Boolean(_fromRouterService));
8794
- let transition = this._routerMicrolib.transitionTo(targetRouteName, ...models, {
8795
- queryParams
8796
- });
8797
- didBeginTransition(transition, this);
8798
- return transition;
8799
- }
8800
- _processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams) {
8801
- // merge in any queryParams from the active transition which could include
8802
- // queryParams from the url on initial load.
8803
- if (!this._routerMicrolib.activeTransition) {
8804
- return;
8805
- }
8806
- let unchangedQPs = {};
8807
- let qpUpdates = this._qpUpdates;
8808
- let params = getFullQueryParams(this, this._routerMicrolib.activeTransition[STATE_SYMBOL]);
8809
- for (let key in params) {
8810
- if (!qpUpdates.has(key)) {
8811
- unchangedQPs[key] = params[key];
8812
- }
8813
- }
8814
-
8815
- // We need to fully scope queryParams so that we can create one object
8816
- // that represents both passed-in queryParams and ones that aren't changed
8817
- // from the active transition.
8818
- this._fullyScopeQueryParams(targetRouteName, models, _queryParams);
8819
- this._fullyScopeQueryParams(targetRouteName, models, unchangedQPs);
8820
- Object.assign(queryParams, unchangedQPs);
8821
- }
8822
-
8823
- /**
8824
- Prepares the query params for a URL or Transition. Restores any undefined QP
8825
- keys/values, serializes all values, and then prunes any default values.
8826
- @private
8827
- @method _prepareQueryParams
8828
- @param {String} targetRouteName
8829
- @param {Array<Object>} models
8830
- @param {Object} queryParams
8831
- @param {boolean} keepDefaultQueryParamValues
8832
- @return {Void}
8833
- */
8834
- _prepareQueryParams(targetRouteName, models, queryParams, _fromRouterService) {
8835
- let state = calculatePostTransitionState(this, targetRouteName, models);
8836
- this._hydrateUnsuppliedQueryParams(state, queryParams, Boolean(_fromRouterService));
8837
- this._serializeQueryParams(state.routeInfos, queryParams);
8838
- if (!_fromRouterService) {
8839
- this._pruneDefaultQueryParamValues(state.routeInfos, queryParams);
8840
- }
8841
- }
8842
-
8843
- /**
8844
- Returns the meta information for the query params of a given route. This
8845
- will be overridden to allow support for lazy routes.
8846
- @private
8847
- @method _getQPMeta
8848
- @param {RouteInfo} routeInfo
8849
- @return {Object}
8850
- */
8851
- _getQPMeta(routeInfo) {
8852
- let route = routeInfo.route;
8853
- return route && get(route, '_qp');
8854
- }
8855
-
8856
- /**
8857
- Returns a merged query params meta object for a given set of routeInfos.
8858
- Useful for knowing what query params are available for a given route hierarchy.
8859
- @private
8860
- @method _queryParamsFor
8861
- @param {Array<RouteInfo>} routeInfos
8862
- @return {Object}
8863
- */
8864
- _queryParamsFor(routeInfos) {
8865
- let routeInfoLength = routeInfos.length;
8866
- let leafRouteName = routeInfos[routeInfoLength - 1].name;
8867
- let cached = this._qpCache[leafRouteName];
8868
- if (cached !== undefined) {
8869
- return cached;
8870
- }
8871
- let shouldCache = true;
8872
- let map = {};
8873
- let qps = [];
8874
- let qpsByUrlKey = isDevelopingApp() ? {} : null;
8875
- let qpMeta;
8876
- let urlKey;
8877
- let qpOther;
8878
- for (let routeInfo of routeInfos) {
8879
- qpMeta = this._getQPMeta(routeInfo);
8880
- if (!qpMeta) {
8881
- shouldCache = false;
8882
- continue;
8883
- }
8884
-
8885
- // Loop over each QP to make sure we don't have any collisions by urlKey
8886
- for (let qp of qpMeta.qps) {
8887
- if (isDevelopingApp()) {
8888
- urlKey = qp.urlKey;
8889
- qpOther = qpsByUrlKey[urlKey];
8890
- if (qpOther && qpOther.controllerName !== qp.controllerName) {
8891
- (isDevelopingApp() && !(false) && assert(`You're not allowed to have more than one controller property map to the same query param key, but both \`${qpOther.scopedPropertyName}\` and \`${qp.scopedPropertyName}\` map to \`${urlKey}\`. You can fix this by mapping one of the controller properties to a different query param key via the \`as\` config option, e.g. \`${qpOther.prop}: { as: 'other-${qpOther.prop}' }\``, false));
8892
- }
8893
- qpsByUrlKey[urlKey] = qp;
8894
- }
8895
- qps.push(qp);
8896
- }
8897
- Object.assign(map, qpMeta.map);
8898
- }
8899
- let finalQPMeta = {
8900
- qps,
8901
- map
8902
- };
8903
- if (shouldCache) {
8904
- this._qpCache[leafRouteName] = finalQPMeta;
8905
- }
8906
- return finalQPMeta;
8907
- }
8908
-
8909
- /**
8910
- Maps all query param keys to their fully scoped property name of the form
8911
- `controllerName:propName`.
8912
- @private
8913
- @method _fullyScopeQueryParams
8914
- @param {String} leafRouteName
8915
- @param {Array<Object>} contexts
8916
- @param {Object} queryParams
8917
- @return {Void}
8918
- */
8919
- _fullyScopeQueryParams(leafRouteName, contexts, queryParams) {
8920
- let state = calculatePostTransitionState(this, leafRouteName, contexts);
8921
- let routeInfos = state.routeInfos;
8922
- let qpMeta;
8923
- for (let routeInfo of routeInfos) {
8924
- qpMeta = this._getQPMeta(routeInfo);
8925
- if (!qpMeta) {
8926
- continue;
8927
- }
8928
- for (let qp of qpMeta.qps) {
8929
- let presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName || qp.urlKey in queryParams && qp.urlKey;
8930
- if (presentProp) {
8931
- if (presentProp !== qp.scopedPropertyName) {
8932
- queryParams[qp.scopedPropertyName] = queryParams[presentProp];
8933
- delete queryParams[presentProp];
8934
- }
8935
- }
8936
- }
8937
- }
8938
- }
8939
-
8940
- /**
8941
- Hydrates (adds/restores) any query params that have pre-existing values into
8942
- the given queryParams hash. This is what allows query params to be "sticky"
8943
- and restore their last known values for their scope.
8944
- @private
8945
- @method _hydrateUnsuppliedQueryParams
8946
- @param {TransitionState} state
8947
- @param {Object} queryParams
8948
- @return {Void}
8949
- */
8950
- _hydrateUnsuppliedQueryParams(state, queryParams, _fromRouterService) {
8951
- let routeInfos = state.routeInfos;
8952
- let appCache = this._bucketCache;
8953
- let qpMeta;
8954
- let qp;
8955
- let presentProp;
8956
- for (let routeInfo of routeInfos) {
8957
- qpMeta = this._getQPMeta(routeInfo);
8958
- if (!qpMeta) {
8959
- continue;
8960
- }
8961
-
8962
- // Needs to stay for index loop to avoid throwIfClosureRequired
8963
- for (let j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) {
8964
- qp = qpMeta.qps[j];
8965
- (isDevelopingApp() && !(qp) && assert('expected qp', qp));
8966
- presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName || qp.urlKey in queryParams && qp.urlKey;
8967
- (isDevelopingApp() && !(function () {
8968
- if (qp.urlKey === presentProp || qp.scopedPropertyName === presentProp) {
8969
- return true;
8970
- }
8971
- if (_fromRouterService && presentProp !== false && qp.urlKey !== qp.prop) {
8972
- // assumptions (mainly from current transitionTo_test):
8973
- // - this is only supposed to be run when there is an alias to a query param and the alias is used to set the param
8974
- // - when there is no alias: qp.urlKey == qp.prop
8975
- return false;
8976
- }
8977
- return true;
8978
- }()) && assert(`You passed the \`${presentProp}\` query parameter during a transition into ${qp.route.routeName}, please update to ${qp.urlKey}`, function () {
8979
- if (qp.urlKey === presentProp || qp.scopedPropertyName === presentProp) {
8980
- return true;
8981
- }
8982
- if (_fromRouterService && presentProp !== false && qp.urlKey !== qp.prop) {
8983
- return false;
8984
- }
8985
- return true;
8986
- }()));
8987
- if (presentProp) {
8988
- if (presentProp !== qp.scopedPropertyName) {
8989
- queryParams[qp.scopedPropertyName] = queryParams[presentProp];
8990
- delete queryParams[presentProp];
8991
- }
8992
- } else {
8993
- let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, state.params);
8994
- (isDevelopingApp() && !(appCache) && assert('ROUTER BUG: expected appCache to be defined. This is an internal bug, please open an issue on Github if you see this message!', appCache));
8995
- queryParams[qp.scopedPropertyName] = appCache.lookup(cacheKey, qp.prop, qp.defaultValue);
8996
- }
8997
- }
8998
- }
8999
- }
9000
- _scheduleLoadingEvent(transition, originRoute) {
9001
- this._cancelSlowTransitionTimer();
9002
- this._slowTransitionTimer = scheduleOnce('routerTransitions', this, this._handleSlowTransition, transition, originRoute);
9003
- }
9004
- currentState = null;
9005
- targetState = null;
9006
- _handleSlowTransition(transition, originRoute) {
9007
- if (!this._routerMicrolib.activeTransition) {
9008
- // Don't fire an event if we've since moved on from
9009
- // the transition that put us in a loading state.
9010
- return;
9011
- }
9012
- let targetState = new RouterState(this, this._routerMicrolib, this._routerMicrolib.activeTransition[STATE_SYMBOL]);
9013
- this.set('targetState', targetState);
9014
- transition.trigger(true, 'loading', transition, originRoute);
9015
- }
9016
- _cancelSlowTransitionTimer() {
9017
- if (this._slowTransitionTimer) {
9018
- cancel(this._slowTransitionTimer);
9019
- }
9020
- this._slowTransitionTimer = null;
9021
- }
9022
-
9023
- // These three helper functions are used to ensure errors aren't
9024
- // re-raised if they're handled in a route's error action.
9025
- _markErrorAsHandled(error) {
9026
- this._handledErrors.add(error);
9027
- }
9028
- _isErrorHandled(error) {
9029
- return this._handledErrors.has(error);
9030
- }
9031
- _clearHandledError(error) {
9032
- this._handledErrors.delete(error);
9033
- }
9034
- _getEngineInstance({
9035
- name,
9036
- instanceId,
9037
- mountPoint
9038
- }) {
9039
- let engineInstances = this._engineInstances;
9040
- let namedInstances = engineInstances[name];
9041
- if (!namedInstances) {
9042
- namedInstances = Object.create(null);
9043
- engineInstances[name] = namedInstances;
9044
- }
9045
-
9046
- // We just set these!
9047
- (isDevelopingApp() && !(namedInstances) && assert('has namedInstances', namedInstances));
9048
- let engineInstance = namedInstances[instanceId];
9049
- if (!engineInstance) {
9050
- let owner = getOwner$1(this);
9051
- (isDevelopingApp() && !(owner instanceof EmberEngineInstance) && assert('Expected router to have EngineInstance as owner', owner instanceof EmberEngineInstance));
9052
- (isDevelopingApp() && !(owner.hasRegistration(`engine:${name}`)) && assert(`You attempted to mount the engine '${name}' in your router map, but the engine can not be found.`, owner.hasRegistration(`engine:${name}`)));
9053
- engineInstance = owner.buildChildEngineInstance(name, {
9054
- routable: true,
9055
- mountPoint
9056
- });
9057
- engineInstance.boot();
9058
- namedInstances[instanceId] = engineInstance;
9059
- }
9060
- return engineInstance;
9061
- }
9062
-
9063
- /**
9064
- Handles updating the paths and notifying any listeners of the URL
9065
- change.
9066
- Triggers the router level `didTransition` hook.
9067
- For example, to notify google analytics when the route changes,
9068
- you could use this hook. (Note: requires also including GA scripts, etc.)
9069
- ```javascript
9070
- import config from './config/environment';
9071
- import EmberRouter from '@ember/routing/router';
9072
- import { service } from '@ember/service';
9073
- let Router = EmberRouter.extend({
9074
- location: config.locationType,
9075
- router: service(),
9076
- didTransition: function() {
9077
- this._super(...arguments);
9078
- ga('send', 'pageview', {
9079
- page: this.router.currentURL,
9080
- title: this.router.currentRouteName,
9081
- });
9082
- }
9083
- });
9084
- ```
9085
- @method didTransition
9086
- @private
9087
- @since 1.2.0
9088
- */
9089
- // Set with reopen to allow overriding via extend
9090
-
9091
- /**
9092
- Handles notifying any listeners of an impending URL
9093
- change.
9094
- Triggers the router level `willTransition` hook.
9095
- @method willTransition
9096
- @private
9097
- @since 1.11.0
9098
- */
9099
- // Set with reopen to allow overriding via extend
9100
-
9101
- /**
9102
- Represents the current URL.
9103
- @property url
9104
- @type {String}
9105
- @private
9106
- */
9107
- // Set with reopen to allow overriding via extend
9108
- }
9109
-
9110
- /*
9111
- Helper function for iterating over routes in a set of routeInfos that are
9112
- at or above the given origin route. Example: if `originRoute` === 'foo.bar'
9113
- and the routeInfos given were for 'foo.bar.baz', then the given callback
9114
- will be invoked with the routes for 'foo.bar', 'foo', and 'application'
9115
- individually.
9116
-
9117
- If the callback returns anything other than `true`, then iteration will stop.
9118
-
9119
- @private
9120
- @param {Route} originRoute
9121
- @param {Array<RouteInfo>} routeInfos
9122
- @param {Function} callback
9123
- @return {Void}
9124
- */
9125
- function forEachRouteAbove(routeInfos, callback) {
9126
- for (let i = routeInfos.length - 1; i >= 0; --i) {
9127
- let routeInfo = routeInfos[i];
9128
- (isDevelopingApp() && !(routeInfo) && assert('has routeInfo', routeInfo));
9129
- let route = routeInfo.route;
9130
-
9131
- // routeInfo.handler being `undefined` generally means either:
9132
- //
9133
- // 1. an error occurred during creation of the route in question
9134
- // 2. the route is across an async boundary (e.g. within an engine)
9135
- //
9136
- // In both of these cases, we cannot invoke the callback on that specific
9137
- // route, because it just doesn't exist...
9138
- if (route === undefined) {
9139
- continue;
9140
- }
9141
- if (callback(route, routeInfo) !== true) {
9142
- return;
9143
- }
9144
- }
9145
- }
9146
-
9147
- // These get invoked when an action bubbles above ApplicationRoute
9148
- // and are not meant to be overridable.
9149
- let defaultActionHandlers = {
9150
- willResolveModel(_routeInfos, transition, originRoute) {
9151
- this._scheduleLoadingEvent(transition, originRoute);
9152
- },
9153
- // Attempt to find an appropriate error route or substate to enter.
9154
- error(routeInfos, error, transition) {
9155
- let router = this;
9156
- let routeInfoWithError = routeInfos[routeInfos.length - 1];
9157
- forEachRouteAbove(routeInfos, (route, routeInfo) => {
9158
- // We don't check the leaf most routeInfo since that would
9159
- // technically be below where we're at in the route hierarchy.
9160
- if (routeInfo !== routeInfoWithError) {
9161
- // Check for the existence of an 'error' route.
9162
- let errorRouteName = findRouteStateName(route, 'error');
9163
- if (errorRouteName) {
9164
- router._markErrorAsHandled(error);
9165
- router.intermediateTransitionTo(errorRouteName, error);
9166
- return false;
9167
- }
9168
- }
9169
-
9170
- // Check for an 'error' substate route
9171
- let errorSubstateName = findRouteSubstateName(route, 'error');
9172
- if (errorSubstateName) {
9173
- router._markErrorAsHandled(error);
9174
- router.intermediateTransitionTo(errorSubstateName, error);
9175
- return false;
9176
- }
9177
- return true;
9178
- });
9179
- logError(error, `Error while processing route: ${transition.targetName}`);
9180
- },
9181
- // Attempt to find an appropriate loading route or substate to enter.
9182
- loading(routeInfos, transition) {
9183
- let router = this;
9184
- let routeInfoWithSlowLoading = routeInfos[routeInfos.length - 1];
9185
- forEachRouteAbove(routeInfos, (route, routeInfo) => {
9186
- // We don't check the leaf most routeInfos since that would
9187
- // technically be below where we're at in the route hierarchy.
9188
- if (routeInfo !== routeInfoWithSlowLoading) {
9189
- // Check for the existence of a 'loading' route.
9190
- let loadingRouteName = findRouteStateName(route, 'loading');
9191
- if (loadingRouteName) {
9192
- router.intermediateTransitionTo(loadingRouteName);
9193
- return false;
9194
- }
9195
- }
9196
-
9197
- // Check for loading substate
9198
- let loadingSubstateName = findRouteSubstateName(route, 'loading');
9199
- if (loadingSubstateName) {
9200
- router.intermediateTransitionTo(loadingSubstateName);
9201
- return false;
9202
- }
9203
-
9204
- // Don't bubble above pivot route.
9205
- return transition.pivotHandler !== route;
9206
- });
9207
- }
9208
- };
9209
- function logError(_error, initialMessage) {
9210
- let errorArgs = [];
9211
- let error;
9212
- if (_error && typeof _error === 'object' && typeof _error.errorThrown === 'object') {
9213
- error = _error.errorThrown;
9214
- } else {
9215
- error = _error;
9216
- }
9217
- if (initialMessage) {
9218
- errorArgs.push(initialMessage);
9219
- }
9220
- if (error) {
9221
- if (error.message) {
9222
- errorArgs.push(error.message);
9223
- }
9224
- if (error.stack) {
9225
- errorArgs.push(error.stack);
9226
- }
9227
- if (typeof error === 'string') {
9228
- errorArgs.push(error);
9229
- }
9230
- }
9231
- console.error(...errorArgs); //eslint-disable-line no-console
9232
- }
9233
-
9234
- /**
9235
- Finds the name of the substate route if it exists for the given route. A
9236
- substate route is of the form `route_state`, such as `foo_loading`.
9237
-
9238
- @private
9239
- @param {Route} route
9240
- @param {String} state
9241
- @return {String}
9242
- */
9243
- function findRouteSubstateName(route, state) {
9244
- let owner = getOwner$1(route);
9245
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
9246
- let {
9247
- routeName,
9248
- fullRouteName,
9249
- _router: router
9250
- } = route;
9251
- let substateName = `${routeName}_${state}`;
9252
- let substateNameFull = `${fullRouteName}_${state}`;
9253
- return routeHasBeenDefined(owner, router, substateName, substateNameFull) ? substateNameFull : '';
9254
- }
9255
-
9256
- /**
9257
- Finds the name of the state route if it exists for the given route. A state
9258
- route is of the form `route.state`, such as `foo.loading`. Properly Handles
9259
- `application` named routes.
9260
-
9261
- @private
9262
- @param {Route} route
9263
- @param {String} state
9264
- @return {String}
9265
- */
9266
- function findRouteStateName(route, state) {
9267
- let owner = getOwner$1(route);
9268
- (isDevelopingApp() && !(owner) && assert('Route is unexpectedly missing an owner', owner));
9269
- let {
9270
- routeName,
9271
- fullRouteName,
9272
- _router: router
9273
- } = route;
9274
- let stateName = routeName === 'application' ? state : `${routeName}.${state}`;
9275
- let stateNameFull = fullRouteName === 'application' ? state : `${fullRouteName}.${state}`;
9276
- return routeHasBeenDefined(owner, router, stateName, stateNameFull) ? stateNameFull : '';
9277
- }
9278
-
9279
- /**
9280
- Determines whether or not a route has been defined by checking that the route
9281
- is in the Router's map and the owner has a registration for that route.
9282
-
9283
- @private
9284
- @param {Owner} owner
9285
- @param {Router} router
9286
- @param {String} localName
9287
- @param {String} fullName
9288
- @return {Boolean}
9289
- */
9290
- function routeHasBeenDefined(owner, router, localName, fullName) {
9291
- let routerHasRoute = router.hasRoute(fullName);
9292
- let ownerHasRoute = owner.factoryFor(`template:${localName}`) || owner.factoryFor(`route:${localName}`);
9293
- return routerHasRoute && ownerHasRoute;
9294
- }
9295
- function triggerEvent(routeInfos, ignoreFailure, name, args) {
9296
- if (!routeInfos) {
9297
- if (ignoreFailure) {
9298
- return;
9299
- }
9300
- // TODO: update?
9301
- throw new Error(`Can't trigger action '${name}' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call \`.send()\` on the \`Transition\` object passed to the \`model/beforeModel/afterModel\` hooks.`);
9302
- }
9303
- let eventWasHandled = false;
9304
- let routeInfo, handler, actionHandler;
9305
- for (let i = routeInfos.length - 1; i >= 0; i--) {
9306
- routeInfo = routeInfos[i];
9307
- (isDevelopingApp() && !(routeInfo) && assert('[BUG] Missing routeInfo', routeInfo));
9308
- handler = routeInfo.route;
9309
- actionHandler = handler && handler.actions && handler.actions[name];
9310
- if (actionHandler) {
9311
- if (actionHandler.apply(handler, args) === true) {
9312
- eventWasHandled = true;
9313
- } else {
9314
- // Should only hit here if a non-bubbling error action is triggered on a route.
9315
- if (name === 'error') {
9316
- (isDevelopingApp() && !(handler) && assert('[BUG] Missing handler', handler));
9317
- handler._router._markErrorAsHandled(args[0]);
9318
- }
9319
- return;
9320
- }
9321
- }
9322
- }
9323
- let defaultHandler = defaultActionHandlers[name];
9324
- if (defaultHandler) {
9325
- defaultHandler.call(this, routeInfos, ...args);
9326
- return;
9327
- }
9328
- if (!eventWasHandled && !ignoreFailure) {
9329
- throw new Error(`Nothing handled the action '${name}'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.`);
9330
- }
9331
- }
9332
- function calculatePostTransitionState(emberRouter, leafRouteName, contexts) {
9333
- let state = emberRouter._routerMicrolib.applyIntent(leafRouteName, contexts);
9334
- let {
9335
- routeInfos,
9336
- params
9337
- } = state;
9338
- for (let routeInfo of routeInfos) {
9339
- // If the routeInfo is not resolved, we serialize the context into params
9340
- if (!routeInfo.isResolved) {
9341
- params[routeInfo.name] = routeInfo.serialize(routeInfo.context);
9342
- } else {
9343
- params[routeInfo.name] = routeInfo.params;
9344
- }
9345
- }
9346
- return state;
9347
- }
9348
- function updatePaths(router) {
9349
- let infos = router._routerMicrolib.currentRouteInfos;
9350
- if (infos.length === 0) {
9351
- return;
9352
- }
9353
- let path = EmberRouter._routePath(infos);
9354
- let info = infos[infos.length - 1];
9355
- (isDevelopingApp() && !(info) && assert('expected info', info));
9356
- let currentRouteName = info.name;
9357
- let location = router.location;
9358
- (isDevelopingApp() && !(typeof location !== 'string') && assert('expected location to not be a string', typeof location !== 'string'));
9359
- let currentURL = location.getURL();
9360
- set(router, 'currentPath', path);
9361
- set(router, 'currentRouteName', currentRouteName);
9362
- set(router, 'currentURL', currentURL);
9363
- }
9364
- function didBeginTransition(transition, router) {
9365
- let routerState = new RouterState(router, router._routerMicrolib, transition[STATE_SYMBOL]);
9366
- if (!router.currentState) {
9367
- router.set('currentState', routerState);
9368
- }
9369
- router.set('targetState', routerState);
9370
- transition.promise = transition.catch(error => {
9371
- if (router._isErrorHandled(error)) {
9372
- router._clearHandledError(error);
9373
- } else {
9374
- throw error;
9375
- }
9376
- }, 'Transition Error');
9377
- }
9378
- function forEachQueryParam(router, routeInfos, queryParams, callback) {
9379
- let qpCache = router._queryParamsFor(routeInfos);
9380
- for (let key in queryParams) {
9381
- if (!Object.prototype.hasOwnProperty.call(queryParams, key)) {
9382
- continue;
9383
- }
9384
- let value = queryParams[key];
9385
- let qp = qpCache.map[key];
9386
- callback(key, value, qp);
9387
- }
9388
- }
9389
- EmberRouter.reopen({
9390
- didTransition: defaultDidTransition,
9391
- willTransition: defaultWillTransition,
9392
- rootURL: '/',
9393
- location: 'hash',
9394
- // FIXME: Does this need to be overrideable via extend?
9395
- url: computed(function () {
9396
- let location = get(this, 'location');
9397
- if (typeof location === 'string') {
9398
- return undefined;
9399
- }
9400
- return location.getURL();
9401
- })
9402
- });
9403
- const EmberRouter$1 = EmberRouter;
9404
-
9405
- /**
9406
- * @module @ember/routing/router-service
9407
- */
9408
- const ROUTER = Symbol('ROUTER');
9409
- function cleanURL(url, rootURL) {
9410
- if (rootURL === '/') {
9411
- return url;
9412
- }
9413
- return url.substring(rootURL.length);
9414
- }
9415
-
9416
- /**
9417
- The Router service is the public API that provides access to the router.
9418
-
9419
- The immediate benefit of the Router service is that you can inject it into components,
9420
- giving them a friendly way to initiate transitions and ask questions about the current
9421
- global router state.
9422
-
9423
- In this example, the Router service is injected into a component to initiate a transition
9424
- to a dedicated route:
9425
-
9426
- ```app/components/example.js
9427
- import Component from '@glimmer/component';
9428
- import { action } from '@ember/object';
9429
- import { service } from '@ember/service';
9430
-
9431
- export default class ExampleComponent extends Component {
9432
- @service router;
9433
-
9434
- @action
9435
- next() {
9436
- this.router.transitionTo('other.route');
9437
- }
9438
- }
9439
- ```
9440
-
9441
- Like any service, it can also be injected into helpers, routes, etc.
9442
-
9443
- @public
9444
- @extends Service
9445
- @class RouterService
9446
- */
9447
-
9448
- class RouterService extends Service.extend(Evented) {
9449
- [ROUTER];
9450
- get _router() {
9451
- let router = this[ROUTER];
9452
- if (router !== undefined) {
9453
- return router;
9454
- }
9455
- let owner = getOwner(this);
9456
- (isDevelopingApp() && !(owner) && assert('RouterService is unexpectedly missing an owner', owner));
9457
- let _router = owner.lookup('router:main');
9458
- (isDevelopingApp() && !(_router instanceof EmberRouter$1) && assert('ROUTER SERVICE BUG: Expected router to be an instance of EmberRouter', _router instanceof EmberRouter$1));
9459
- return this[ROUTER] = _router;
9460
- }
9461
- willDestroy() {
9462
- super.willDestroy();
9463
- this[ROUTER] = undefined;
9464
- }
9465
-
9466
- /**
9467
- Transition the application into another route. The route may
9468
- be either a single route or route path:
9469
- Calling `transitionTo` from the Router service will cause default query parameter values to be included in the URL.
9470
- This behavior is different from calling `transitionTo` on a route or `transitionToRoute` on a controller.
9471
- See the [Router Service RFC](https://github.com/emberjs/rfcs/blob/master/text/0095-router-service.md#query-parameter-semantics) for more info.
9472
- In the following example we use the Router service to navigate to a route with a
9473
- specific model from a Component in the first action, and in the second we trigger
9474
- a query-params only transition.
9475
- ```app/components/example.js
9476
- import Component from '@glimmer/component';
9477
- import { action } from '@ember/object';
9478
- import { service } from '@ember/service';
9479
- export default class extends Component {
9480
- @service router;
9481
- @action
9482
- goToComments(post) {
9483
- this.router.transitionTo('comments', post);
9484
- }
9485
- @action
9486
- fetchMoreComments(latestComment) {
9487
- this.router.transitionTo({
9488
- queryParams: { commentsAfter: latestComment }
9489
- });
9490
- }
9491
- }
9492
- ```
9493
- @method transitionTo
9494
- @param {String} [routeNameOrUrl] the name of the route or a URL
9495
- @param {...Object} [models] the model(s) or identifier(s) to be used while
9496
- transitioning to the route.
9497
- @param {Object} [options] optional hash with a queryParams property
9498
- containing a mapping of query parameters. May be supplied as the only
9499
- parameter to trigger a query-parameter-only transition.
9500
- @return {Transition} the transition object associated with this
9501
- attempted transition
9502
- @public
9503
- */
9504
- transitionTo(...args) {
9505
- if (resemblesURL(args[0])) {
9506
- // NOTE: this `args[0] as string` cast is safe and TS correctly infers it
9507
- // in 3.6+, so it can be removed when TS is upgraded.
9508
- return this._router._doURLTransition('transitionTo', args[0]);
9509
- }
9510
- let {
9511
- routeName,
9512
- models,
9513
- queryParams
9514
- } = extractRouteArgs(args);
9515
- let transition = this._router._doTransition(routeName, models, queryParams, true);
9516
- return transition;
9517
- }
9518
-
9519
- /**
9520
- Similar to `transitionTo`, but instead of adding the destination to the browser's URL history,
9521
- it replaces the entry for the current route.
9522
- When the user clicks the "back" button in the browser, there will be fewer steps.
9523
- This is most commonly used to manage redirects in a way that does not cause confusing additions
9524
- to the user's browsing history.
9525
- Calling `replaceWith` from the Router service will cause default query parameter values to be included in the URL.
9526
- This behavior is different from calling `replaceWith` on a route.
9527
- See the [Router Service RFC](https://github.com/emberjs/rfcs/blob/master/text/0095-router-service.md#query-parameter-semantics) for more info.
9528
- Usage example:
9529
- ```app/routes/application.js
9530
- import Route from '@ember/routing/route';
9531
- import { service } from '@ember/service';
9532
- export default class extends Route {
9533
- @service router;
9534
- beforeModel() {
9535
- if (!authorized()){
9536
- this.router.replaceWith('unauthorized');
9537
- }
9538
- }
9539
- });
9540
- ```
9541
- @method replaceWith
9542
- @param {String} routeNameOrUrl the name of the route or a URL of the desired destination
9543
- @param {...Object} models the model(s) or identifier(s) to be used while
9544
- transitioning to the route i.e. an object of params to pass to the destination route
9545
- @param {Object} [options] optional hash with a queryParams property
9546
- containing a mapping of query parameters
9547
- @return {Transition} the transition object associated with this
9548
- attempted transition
9549
- @public
9550
- */
9551
- replaceWith(...args) {
9552
- return this.transitionTo(...args).method('replace');
9553
- }
9554
-
9555
- /**
9556
- Generate a URL based on the supplied route name and optionally a model. The
9557
- URL is returned as a string that can be used for any purpose.
9558
- In this example, the URL for the `author.books` route for a given author
9559
- is copied to the clipboard.
9560
- ```app/templates/application.hbs
9561
- <CopyLink @author={{hash id="tomster" name="Tomster"}} />
9562
- ```
9563
- ```app/components/copy-link.js
9564
- import Component from '@glimmer/component';
9565
- import { service } from '@ember/service';
9566
- import { action } from '@ember/object';
9567
- export default class CopyLinkComponent extends Component {
9568
- @service router;
9569
- @service clipboard;
9570
- @action
9571
- copyBooksURL() {
9572
- if (this.author) {
9573
- const url = this.router.urlFor('author.books', this.args.author);
9574
- this.clipboard.set(url);
9575
- // Clipboard now has /author/tomster/books
9576
- }
9577
- }
9578
- }
9579
- ```
9580
- Just like with `transitionTo` and `replaceWith`, `urlFor` can also handle
9581
- query parameters.
9582
- ```app/templates/application.hbs
9583
- <CopyLink @author={{hash id="tomster" name="Tomster"}} />
9584
- ```
9585
- ```app/components/copy-link.js
9586
- import Component from '@glimmer/component';
9587
- import { service } from '@ember/service';
9588
- import { action } from '@ember/object';
9589
- export default class CopyLinkComponent extends Component {
9590
- @service router;
9591
- @service clipboard;
9592
- @action
9593
- copyOnlyEmberBooksURL() {
9594
- if (this.author) {
9595
- const url = this.router.urlFor('author.books', this.author, {
9596
- queryParams: { filter: 'emberjs' }
9597
- });
9598
- this.clipboard.set(url);
9599
- // Clipboard now has /author/tomster/books?filter=emberjs
9600
- }
9601
- }
9602
- }
9603
- ```
9604
- @method urlFor
9605
- @param {String} routeName the name of the route
9606
- @param {...Object} models the model(s) for the route.
9607
- @param {Object} [options] optional hash with a queryParams property
9608
- containing a mapping of query parameters
9609
- @return {String} the string representing the generated URL
9610
- @public
9611
- */
9612
- urlFor(routeName, ...args) {
9613
- this._router.setupRouter();
9614
- return this._router.generate(routeName, ...args);
9615
- }
9616
-
9617
- /**
9618
- Returns `true` if `routeName/models/queryParams` is the active route, where `models` and `queryParams` are optional.
9619
- See [model](api/ember/release/classes/Route/methods/model?anchor=model) and
9620
- [queryParams](/api/ember/3.7/classes/Route/properties/queryParams?anchor=queryParams) for more information about these arguments.
9621
- In the following example, `isActive` will return `true` if the current route is `/posts`.
9622
- ```app/components/posts.js
9623
- import Component from '@glimmer/component';
9624
- import { service } from '@ember/service';
9625
- export default class extends Component {
9626
- @service router;
9627
- displayComments() {
9628
- return this.router.isActive('posts');
9629
- }
9630
- });
9631
- ```
9632
- The next example includes a dynamic segment, and will return `true` if the current route is `/posts/1`,
9633
- assuming the post has an id of 1:
9634
- ```app/components/posts.js
9635
- import Component from '@glimmer/component';
9636
- import { service } from '@ember/service';
9637
- export default class extends Component {
9638
- @service router;
9639
- displayComments(post) {
9640
- return this.router.isActive('posts', post.id);
9641
- }
9642
- });
9643
- ```
9644
- Where `post.id` is the id of a specific post, which is represented in the route as /posts/[post.id].
9645
- If `post.id` is equal to 1, then isActive will return true if the current route is /posts/1, and false if the route is anything else.
9646
- @method isActive
9647
- @param {String} routeName the name of the route
9648
- @param {...Object} models the model(s) or identifier(s) to be used when determining the active route.
9649
- @param {Object} [options] optional hash with a queryParams property
9650
- containing a mapping of query parameters
9651
- @return {boolean} true if the provided routeName/models/queryParams are active
9652
- @public
9653
- */
9654
- isActive(...args) {
9655
- let {
9656
- routeName,
9657
- models,
9658
- queryParams
9659
- } = extractRouteArgs(args);
9660
- let routerMicrolib = this._router._routerMicrolib;
9661
-
9662
- // When using isActive() in a getter, we want to entagle with the auto-tracking system
9663
- // for example,
9664
- // in
9665
- // get isBarActive() {
9666
- // return isActive('foo.bar');
9667
- // }
9668
- //
9669
- // you'd expect isBarActive to be dirtied when the route changes.
9670
- //
9671
- // https://github.com/emberjs/ember.js/issues/19004
9672
- consumeTag(tagFor(this._router, 'currentURL'));
9673
-
9674
- // UNSAFE: casting `routeName as string` here encodes the existing
9675
- // assumption but may be wrong: `extractRouteArgs` correctly returns it as
9676
- // `string | undefined`. There may be bugs if `isActiveIntent` does
9677
- // not correctly account for `undefined` values for `routeName`. Spoilers:
9678
- // it *does not* account for this being `undefined`.
9679
- if (!routerMicrolib.isActiveIntent(routeName, models)) {
9680
- return false;
9681
- }
9682
- let hasQueryParams = Object.keys(queryParams).length > 0;
9683
- if (hasQueryParams) {
9684
- // UNSAFE: casting `routeName as string` here encodes the existing
9685
- // assumption but may be wrong: `extractRouteArgs` correctly returns it
9686
- // as `string | undefined`. There may be bugs if `_prepareQueryParams`
9687
- // does not correctly account for `undefined` values for `routeName`.
9688
- // Spoilers: under the hood this currently uses router.js APIs which
9689
- // *do not* account for this being `undefined`.
9690
- let targetRouteName = routeName;
9691
- queryParams = Object.assign({}, queryParams);
9692
- this._router._prepareQueryParams(targetRouteName, models, queryParams, true /* fromRouterService */);
9693
- let currentQueryParams = Object.assign({}, routerMicrolib.state.queryParams);
9694
- this._router._prepareQueryParams(targetRouteName, models, currentQueryParams, true /* fromRouterService */);
9695
- return shallowEqual(queryParams, currentQueryParams);
9696
- }
9697
- return true;
9698
- }
9699
-
9700
- /**
9701
- Takes a string URL and returns a `RouteInfo` for the leafmost route represented
9702
- by the URL. Returns `null` if the URL is not recognized. This method expects to
9703
- receive the actual URL as seen by the browser including the app's `rootURL`.
9704
- See [RouteInfo](/ember/release/classes/RouteInfo) for more info.
9705
- In the following example `recognize` is used to verify if a path belongs to our
9706
- application before transitioning to it.
9707
- ```
9708
- import Component from '@ember/component';
9709
- import { service } from '@ember/service';
9710
- export default class extends Component {
9711
- @service router;
9712
- path = '/';
9713
- click() {
9714
- if (this.router.recognize(this.path)) {
9715
- this.router.transitionTo(this.path);
9716
- }
9717
- }
9718
- }
9719
- ```
9720
- @method recognize
9721
- @param {String} url
9722
- @return {RouteInfo | null}
9723
- @public
9724
- */
9725
- recognize(url) {
9726
- (isDevelopingApp() && !(url.indexOf(this.rootURL) === 0) && assert(`You must pass a url that begins with the application's rootURL "${this.rootURL}"`, url.indexOf(this.rootURL) === 0));
9727
- this._router.setupRouter();
9728
- let internalURL = cleanURL(url, this.rootURL);
9729
- return this._router._routerMicrolib.recognize(internalURL);
9730
- }
9731
-
9732
- /**
9733
- Takes a string URL and returns a promise that resolves to a
9734
- `RouteInfoWithAttributes` for the leafmost route represented by the URL.
9735
- The promise rejects if the URL is not recognized or an unhandled exception
9736
- is encountered. This method expects to receive the actual URL as seen by
9737
- the browser including the app's `rootURL`.
9738
- @method recognizeAndLoad
9739
- @param {String} url
9740
- @return {RouteInfo}
9741
- @public
9742
- */
9743
- recognizeAndLoad(url) {
9744
- (isDevelopingApp() && !(url.indexOf(this.rootURL) === 0) && assert(`You must pass a url that begins with the application's rootURL "${this.rootURL}"`, url.indexOf(this.rootURL) === 0));
9745
- this._router.setupRouter();
9746
- let internalURL = cleanURL(url, this.rootURL);
9747
- return this._router._routerMicrolib.recognizeAndLoad(internalURL);
9748
- }
9749
-
9750
- /**
9751
- You can register a listener for events emitted by this service with `.on()`:
9752
- ```app/routes/contact-form.js
9753
- import Route from '@ember/routing';
9754
- import { service } from '@ember/service';
9755
- export default class extends Route {
9756
- @service router;
9757
- activate() {
9758
- this.router.on('routeWillChange', (transition) => {
9759
- if (!transition.to.find(route => route.name === this.routeName)) {
9760
- alert("Please save or cancel your changes.");
9761
- transition.abort();
9762
- }
9763
- })
9764
- }
9765
- }
9766
- ```
9767
- @method on
9768
- @param {String} eventName
9769
- @param {Function} callback
9770
- @public
9771
- */
9772
-
9773
- /**
9774
- You can unregister a listener for events emitted by this service with `.off()`:
9775
- ```app/routes/contact-form.js
9776
- import Route from '@ember/routing';
9777
- import { service } from '@ember/service';
9778
- export default class ContactFormRoute extends Route {
9779
- @service router;
9780
- callback = (transition) => {
9781
- if (!transition.to.find(route => route.name === this.routeName)) {
9782
- alert('Please save or cancel your changes.');
9783
- transition.abort();
9784
- }
9785
- };
9786
- activate() {
9787
- this.router.on('routeWillChange', this.callback);
9788
- }
9789
- deactivate() {
9790
- this.router.off('routeWillChange', this.callback);
9791
- }
9792
- }
9793
- ```
9794
- @method off
9795
- @param {String} eventName
9796
- @param {Function} callback
9797
- @public
9798
- */
9799
-
9800
- /**
9801
- The `routeWillChange` event is fired at the beginning of any
9802
- attempted transition with a `Transition` object as the sole
9803
- argument. This action can be used for aborting, redirecting,
9804
- or decorating the transition from the currently active routes.
9805
- A good example is preventing navigation when a form is
9806
- half-filled out:
9807
- ```app/routes/contact-form.js
9808
- import Route from '@ember/routing';
9809
- import { service } from '@ember/service';
9810
- export default class extends Route {
9811
- @service router;
9812
- activate() {
9813
- this.router.on('routeWillChange', (transition) => {
9814
- if (!transition.to.find(route => route.name === this.routeName)) {
9815
- alert("Please save or cancel your changes.");
9816
- transition.abort();
9817
- }
9818
- })
9819
- }
9820
- }
9821
- ```
9822
- The `routeWillChange` event fires whenever a new route is chosen as the desired target of a transition. This includes `transitionTo`, `replaceWith`, all redirection for any reason including error handling, and abort. Aborting implies changing the desired target back to where you already were. Once a transition has completed, `routeDidChange` fires.
9823
- @event routeWillChange
9824
- @param {Transition} transition
9825
- @public
9826
- */
9827
-
9828
- /**
9829
- The `routeDidChange` event only fires once a transition has settled.
9830
- This includes aborts and error substates. Like the `routeWillChange` event
9831
- it receives a Transition as the sole argument.
9832
- A good example is sending some analytics when the route has transitioned:
9833
- ```app/routes/contact-form.js
9834
- import Route from '@ember/routing';
9835
- import { service } from '@ember/service';
9836
- export default class extends Route {
9837
- @service router;
9838
- activate() {
9839
- this.router.on('routeDidChange', (transition) => {
9840
- ga.send('pageView', {
9841
- current: transition.to.name,
9842
- from: transition.from.name
9843
- });
9844
- })
9845
- }
9846
- }
9847
- ```
9848
- `routeDidChange` will be called after any `Route`'s
9849
- [didTransition](/ember/release/classes/Route/events/didTransition?anchor=didTransition)
9850
- action has been fired.
9851
- The updates of properties
9852
- [currentURL](/ember/release/classes/RouterService/properties/currentURL?anchor=currentURL),
9853
- [currentRouteName](/ember/release/classes/RouterService/properties/currentURL?anchor=currentRouteName)
9854
- and
9855
- [currentRoute](/ember/release/classes/RouterService/properties/currentURL?anchor=currentRoute)
9856
- are completed at the time `routeDidChange` is called.
9857
- @event routeDidChange
9858
- @param {Transition} transition
9859
- @public
9860
- */
9861
-
9862
- /**
9863
- * Refreshes all currently active routes, doing a full transition.
9864
- * If a route name is provided and refers to a currently active route,
9865
- * it will refresh only that route and its descendents.
9866
- * Returns a promise that will be resolved once the refresh is complete.
9867
- * All resetController, beforeModel, model, afterModel, redirect, and setupController
9868
- * hooks will be called again. You will get new data from the model hook.
9869
- *
9870
- * @method refresh
9871
- * @param {String} [routeName] the route to refresh (along with all child routes)
9872
- * @return Transition
9873
- * @public
9874
- */
9875
- refresh(pivotRouteName) {
9876
- if (!pivotRouteName) {
9877
- return this._router._routerMicrolib.refresh();
9878
- }
9879
- (isDevelopingApp() && !(this._router.hasRoute(pivotRouteName)) && assert(`The route "${pivotRouteName}" was not found`, this._router.hasRoute(pivotRouteName)));
9880
- (isDevelopingApp() && !(this.isActive(pivotRouteName)) && assert(`The route "${pivotRouteName}" is currently not active`, this.isActive(pivotRouteName)));
9881
- let owner = getOwner(this);
9882
- (isDevelopingApp() && !(owner) && assert('RouterService is unexpectedly missing an owner', owner));
9883
- let pivotRoute = owner.lookup(`route:${pivotRouteName}`);
9884
- return this._router._routerMicrolib.refresh(pivotRoute);
9885
- }
9886
-
9887
- /**
9888
- Name of the current route.
9889
- This property represents the logical name of the route,
9890
- which is dot separated.
9891
- For the following router:
9892
- ```app/router.js
9893
- Router.map(function() {
9894
- this.route('about');
9895
- this.route('blog', function () {
9896
- this.route('post', { path: ':post_id' });
9897
- });
9898
- });
9899
- ```
9900
- It will return:
9901
- * `index` when you visit `/`
9902
- * `about` when you visit `/about`
9903
- * `blog.index` when you visit `/blog`
9904
- * `blog.post` when you visit `/blog/some-post-id`
9905
- @property currentRouteName
9906
- @type {String | null}
9907
- @public
9908
- */
9909
- static {
9910
- decorateFieldV2(this.prototype, "currentRouteName", [readOnly('_router.currentRouteName')]);
9911
- }
9912
- #currentRouteName = (initializeDeferredDecorator(this, "currentRouteName"), void 0);
9913
- static {
9914
- decorateFieldV2(this.prototype, "currentURL", [readOnly('_router.currentURL')]);
9915
- }
9916
- #currentURL = (initializeDeferredDecorator(this, "currentURL"), void 0);
9917
- /**
9918
- Current URL for the application.
9919
- This property represents the URL path for this route.
9920
- For the following router:
9921
- ```app/router.js
9922
- Router.map(function() {
9923
- this.route('about');
9924
- this.route('blog', function () {
9925
- this.route('post', { path: ':post_id' });
9926
- });
9927
- });
9928
- ```
9929
- It will return:
9930
- * `/` when you visit `/`
9931
- * `/about` when you visit `/about`
9932
- * `/blog` when you visit `/blog`
9933
- * `/blog/some-post-id` when you visit `/blog/some-post-id`
9934
- @property currentURL
9935
- @type String
9936
- @public
9937
- */
9938
- static {
9939
- decorateFieldV2(this.prototype, "location", [readOnly('_router.location')]);
9940
- }
9941
- #location = (initializeDeferredDecorator(this, "location"), void 0);
9942
- /**
9943
- The `location` property returns what implementation of the `location` API
9944
- your application is using, which determines what type of URL is being used.
9945
- See [Location](/ember/release/classes/Location) for more information.
9946
- To force a particular `location` API implementation to be used in your
9947
- application you can set a location type on your `config/environment`.
9948
- For example, to set the `history` type:
9949
- ```config/environment.js
9950
- 'use strict';
9951
- module.exports = function(environment) {
9952
- let ENV = {
9953
- modulePrefix: 'router-service',
9954
- environment,
9955
- rootURL: '/',
9956
- locationType: 'history',
9957
- ...
9958
- }
9959
- }
9960
- ```
9961
- The following location types are available by default:
9962
- `hash`, `history`, `none`.
9963
- See [HashLocation](/ember/release/classes/HashLocation).
9964
- See [HistoryLocation](/ember/release/classes/HistoryLocation).
9965
- See [NoneLocation](/ember/release/classes/NoneLocation).
9966
- @property location
9967
- @default 'hash'
9968
- @see {Location}
9969
- @public
9970
- */
9971
- static {
9972
- decorateFieldV2(this.prototype, "rootURL", [readOnly('_router.rootURL')]);
9973
- }
9974
- #rootURL = (initializeDeferredDecorator(this, "rootURL"), void 0);
9975
- /**
9976
- The `rootURL` property represents the URL of the root of
9977
- the application, '/' by default.
9978
- This prefix is assumed on all routes defined on this app.
9979
- If you change the `rootURL` in your environment configuration
9980
- like so:
9981
- ```config/environment.js
9982
- 'use strict';
9983
- module.exports = function(environment) {
9984
- let ENV = {
9985
- modulePrefix: 'router-service',
9986
- environment,
9987
- rootURL: '/my-root',
9988
-
9989
- }
9990
- ]
9991
- ```
9992
- This property will return `/my-root`.
9993
- @property rootURL
9994
- @default '/'
9995
- @public
9996
- */
9997
- static {
9998
- decorateFieldV2(this.prototype, "currentRoute", [readOnly('_router.currentRoute')]);
9999
- }
10000
- #currentRoute = (initializeDeferredDecorator(this, "currentRoute"), void 0);
10001
- /**
10002
- The `currentRoute` property contains metadata about the current leaf route.
10003
- It returns a `RouteInfo` object that has information like the route name,
10004
- params, query params and more.
10005
- See [RouteInfo](/ember/release/classes/RouteInfo) for more info.
10006
- This property is guaranteed to change whenever a route transition
10007
- happens (even when that transition only changes parameters
10008
- and doesn't change the active route).
10009
- Usage example:
10010
- ```app/components/header.js
10011
- import Component from '@glimmer/component';
10012
- import { service } from '@ember/service';
10013
- import { notEmpty } from '@ember/object/computed';
10014
- export default class extends Component {
10015
- @service router;
10016
- @notEmpty('router.currentRoute.child') isChildRoute;
10017
- });
10018
- ```
10019
- @property currentRoute
10020
- @type RouteInfo
10021
- @public
10022
- */
10023
- }
10024
-
10025
- /**
10026
- @module ember
10027
- */
10028
-
10029
- class RoutingService extends Service {
10030
- [ROUTER];
10031
- get router() {
10032
- let router = this[ROUTER];
10033
- if (router !== undefined) {
10034
- return router;
10035
- }
10036
- let owner = getOwner(this);
10037
- (isDevelopingApp() && !(owner) && assert('RoutingService is unexpectedly missing an owner', owner));
10038
- let _router = owner.lookup('router:main');
10039
- (isDevelopingApp() && !(_router instanceof EmberRouter$1) && assert('ROUTING SERVICE BUG: Expected router to be an instance of EmberRouter', _router instanceof EmberRouter$1));
10040
- _router.setupRouter();
10041
- return this[ROUTER] = _router;
10042
- }
10043
- hasRoute(routeName) {
10044
- return this.router.hasRoute(routeName);
10045
- }
10046
- transitionTo(routeName, models, queryParams, shouldReplace) {
10047
- let transition = this.router._doTransition(routeName, models, queryParams);
10048
- if (shouldReplace) {
10049
- transition.method('replace');
10050
- }
10051
- return transition;
10052
- }
10053
- normalizeQueryParams(routeName, models, queryParams) {
10054
- this.router._prepareQueryParams(routeName, models, queryParams);
10055
- }
10056
- _generateURL(routeName, models, queryParams) {
10057
- let visibleQueryParams = {};
10058
- if (queryParams) {
10059
- Object.assign(visibleQueryParams, queryParams);
10060
- this.normalizeQueryParams(routeName, models, visibleQueryParams);
10061
- }
10062
- return this.router.generate(routeName, ...models, {
10063
- queryParams: visibleQueryParams
10064
- });
10065
- }
10066
- generateURL(routeName, models, queryParams) {
10067
- if (this.router._initialTransitionStarted) {
10068
- return this._generateURL(routeName, models, queryParams);
10069
- } else {
10070
- // Swallow error when transition has not started.
10071
- // When rendering in tests without visit(), we cannot infer the route context which <LinkTo/> needs be aware of
10072
- try {
10073
- return this._generateURL(routeName, models, queryParams);
10074
- } catch (_e) {
10075
- return;
10076
- }
10077
- }
10078
- }
10079
- isActiveForRoute(contexts, queryParams, routeName, routerState) {
10080
- let handlers = this.router._routerMicrolib.recognizer.handlersFor(routeName);
10081
- let leafName = handlers[handlers.length - 1].handler;
10082
- let maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers);
10083
-
10084
- // NOTE: any ugliness in the calculation of activeness is largely
10085
- // due to the fact that we support automatic normalizing of
10086
- // `resource` -> `resource.index`, even though there might be
10087
- // dynamic segments / query params defined on `resource.index`
10088
- // which complicates (and makes somewhat ambiguous) the calculation
10089
- // of activeness for links that link to `resource` instead of
10090
- // directly to `resource.index`.
10091
-
10092
- // if we don't have enough contexts revert back to full route name
10093
- // this is because the leaf route will use one of the contexts
10094
- if (contexts.length > maximumContexts) {
10095
- routeName = leafName;
10096
- }
10097
- return routerState.isActiveIntent(routeName, contexts, queryParams);
10098
- }
10099
- }
10100
- RoutingService.reopen({
10101
- targetState: readOnly('router.targetState'),
10102
- currentState: readOnly('router.currentState'),
10103
- currentRouteName: readOnly('router.currentRouteName'),
10104
- currentPath: readOnly('router.currentPath')
10105
- });
10106
- function numberOfContextsAcceptedByHandler(handlerName, handlerInfos) {
10107
- let req = 0;
10108
- for (let i = 0; i < handlerInfos.length; i++) {
10109
- req += handlerInfos[i].names.length;
10110
- if (handlerInfos[i].handler === handlerName) {
10111
- break;
10112
- }
10113
- }
10114
- return req;
10115
- }
10116
-
10117
- export { getRenderState as A, getFullQueryParams as B, Component as C, defaultSerialize as D, Engine as E, hasDefaultSerialize as F, triggerEvent as G, Helper as H, Input as I, ROUTER as J, LinkTo as L, OutletView as O, RouterState as R, SafeString as S, Textarea as T, _resetRenderers as _, RoutingService as a, RootTemplate as b, htmlSafe as c, Renderer as d, escapeExpression as e, setupApplicationRegistry as f, buildInitializerMethod as g, helper$1 as h, isHTMLSafe as i, EmberRouter$1 as j, Route as k, RouterService as l, EmberEngineInstance as m, setModifierManager as n, on as o, prefixRouteNameArg as p, extractRouteArgs as q, renderSettled as r, setupEngineRegistry as s, getActiveTargetName as t, uniqueId$1 as u, stashParamNames as v, calculateCacheKey as w, normalizeControllerQueryParams as x, resemblesURL as y, shallowEqual as z };
5497
+ export { Component as C, Helper as H, Input as I, LinkTo as L, OutletView as O, RootTemplate as R, SafeString as S, Textarea as T, _resetRenderers as _, htmlSafe as a, Renderer as b, OutletTemplate as c, escapeExpression as e, helper$1 as h, isHTMLSafe as i, renderSettled as r, uniqueId$1 as u };