ember-source 4.8.0-alpha.5 → 4.8.0-beta.2

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 (244) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/blueprints/helper/files/__root__/{__collection__ → helpers}/__name__.ts +0 -0
  3. package/blueprints/helper/index.js +0 -15
  4. package/blueprints/helper-test/index.js +0 -3
  5. package/blueprints/helper-test/mocha-0.12-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  6. package/blueprints/helper-test/mocha-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  7. package/blueprints/helper-test/mocha-rfc-232-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.ts +0 -0
  8. package/blueprints/helper-test/qunit-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  9. package/blueprints/helper-test/qunit-rfc-232-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.ts +0 -0
  10. package/blueprints-js/helper/files/__root__/{__collection__ → helpers}/__name__.js +0 -0
  11. package/blueprints-js/helper-test/mocha-0.12-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  12. package/blueprints-js/helper-test/mocha-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  13. package/blueprints-js/helper-test/mocha-rfc-232-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  14. package/blueprints-js/helper-test/qunit-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  15. package/blueprints-js/helper-test/qunit-rfc-232-files/__root__/__testType__/{__collection__ → helpers}/__name__-test.js +0 -0
  16. package/build-metadata.json +3 -3
  17. package/dist/dependencies/router_js.js +1 -1
  18. package/dist/ember-template-compiler.js +675 -18
  19. package/dist/ember-template-compiler.map +1 -1
  20. package/dist/ember-testing.js +11 -11
  21. package/dist/ember-testing.map +1 -1
  22. package/dist/ember.debug.js +19576 -20510
  23. package/dist/ember.debug.map +1 -1
  24. package/dist/header/license.js +1 -1
  25. package/dist/packages/@ember/-internals/glimmer/index.js +4 -2
  26. package/dist/packages/@ember/-internals/metal/index.js +214 -1094
  27. package/dist/packages/@ember/-internals/routing/index.js +1 -17
  28. package/dist/packages/@ember/-internals/runtime/index.js +3 -16
  29. package/dist/packages/@ember/-internals/runtime/lib/mixins/-proxy.js +2 -1
  30. package/dist/packages/@ember/-internals/runtime/lib/mixins/action_handler.js +4 -3
  31. package/dist/packages/@ember/-internals/runtime/lib/mixins/comparable.js +1 -1
  32. package/dist/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js +1 -1
  33. package/dist/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js +1 -8
  34. package/dist/packages/@ember/-internals/runtime/lib/mixins/target_action_support.js +2 -1
  35. package/dist/packages/@ember/-internals/utils/index.js +3 -3
  36. package/dist/packages/@ember/-internals/views/lib/component_lookup.js +1 -1
  37. package/dist/packages/@ember/-internals/views/lib/mixins/action_support.js +2 -1
  38. package/dist/packages/@ember/-internals/views/lib/mixins/child_views_support.js +2 -1
  39. package/dist/packages/@ember/-internals/views/lib/mixins/class_names_support.js +2 -1
  40. package/dist/packages/@ember/-internals/views/lib/mixins/view_state_support.js +1 -1
  41. package/dist/packages/@ember/-internals/views/lib/mixins/view_support.js +2 -1
  42. package/dist/packages/@ember/-internals/views/lib/system/event_dispatcher.js +1 -1
  43. package/dist/packages/@ember/-internals/views/lib/views/core_view.js +3 -1
  44. package/dist/packages/@ember/application/index.js +876 -2
  45. package/dist/packages/@ember/application/instance.js +2 -2
  46. package/dist/packages/@ember/application/namespace.js +70 -1
  47. package/dist/packages/@ember/array/index.js +1503 -2
  48. package/dist/packages/@ember/array/mutable.js +1 -1
  49. package/dist/packages/@ember/array/proxy.js +307 -1
  50. package/dist/packages/@ember/canary-features/index.js +2 -2
  51. package/dist/packages/@ember/controller/index.js +260 -3
  52. package/dist/packages/@ember/debug/container-debug-adapter.js +99 -1
  53. package/dist/packages/@ember/debug/data-adapter.js +574 -1
  54. package/dist/packages/@ember/engine/index.js +5 -5
  55. package/dist/packages/@ember/engine/instance.js +4 -4
  56. package/dist/packages/@ember/enumerable/index.js +3 -1
  57. package/dist/packages/@ember/enumerable/mutable.js +4 -0
  58. package/dist/packages/@ember/{-internals/runtime/lib/system/object.js → object/-internals.js} +4 -17
  59. package/dist/packages/@ember/object/core.js +731 -1
  60. package/dist/packages/@ember/object/evented.js +93 -2
  61. package/dist/packages/@ember/object/index.js +76 -4
  62. package/dist/packages/@ember/object/internals.js +3 -2
  63. package/dist/packages/@ember/object/lib/computed/computed_macros.js +3 -1
  64. package/dist/packages/@ember/object/lib/computed/reduce_computed_macros.js +4 -3
  65. package/dist/packages/@ember/object/mixin.js +659 -1
  66. package/dist/packages/@ember/object/observable.js +341 -1
  67. package/dist/packages/@ember/object/promise-proxy-mixin.js +150 -1
  68. package/dist/packages/@ember/object/proxy.js +10 -1
  69. package/dist/packages/@ember/routing/-internals.js +7 -0
  70. package/dist/packages/@ember/routing/auto-location.js +249 -1
  71. package/dist/packages/@ember/routing/hash-location.js +169 -1
  72. package/dist/packages/@ember/routing/history-location.js +289 -1
  73. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/cache.js +0 -0
  74. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/controller_for.js +0 -0
  75. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/dsl.js +0 -0
  76. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/engines.js +0 -0
  77. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/generate_controller.js +0 -0
  78. package/dist/packages/@ember/{-internals/routing/lib/location/util.js → routing/lib/location-utils.js} +0 -0
  79. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/query_params.js +0 -0
  80. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/route-info.js +0 -0
  81. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/router_state.js +1 -1
  82. package/dist/packages/@ember/{-internals/routing/lib/services/routing.js → routing/lib/routing-service.js} +2 -2
  83. package/dist/packages/@ember/{-internals/routing/lib/system → routing/lib}/transition.js +0 -0
  84. package/dist/packages/@ember/{-internals/routing → routing}/lib/utils.js +0 -0
  85. package/dist/packages/@ember/routing/location.js +104 -1
  86. package/dist/packages/@ember/routing/none-location.js +123 -1
  87. package/dist/packages/@ember/routing/route.js +1700 -1
  88. package/dist/packages/@ember/routing/router-service.js +510 -1
  89. package/dist/packages/@ember/routing/router.js +1666 -1
  90. package/dist/packages/@ember/service/index.js +1 -1
  91. package/dist/packages/@ember/utils/index.js +7 -2
  92. package/dist/packages/@ember/{-internals/runtime → utils}/lib/compare.js +2 -2
  93. package/dist/packages/@ember/{-internals/runtime → utils}/lib/is-equal.js +0 -0
  94. package/dist/packages/@ember/utils/lib/is_blank.js +35 -0
  95. package/dist/packages/@ember/utils/lib/is_empty.js +68 -0
  96. package/dist/packages/@ember/utils/lib/is_none.js +27 -0
  97. package/dist/packages/@ember/utils/lib/is_present.js +38 -0
  98. package/dist/packages/@ember/{-internals/runtime → utils}/lib/type-of.js +2 -2
  99. package/dist/packages/ember/index.js +47 -28
  100. package/dist/packages/ember/version.js +1 -1
  101. package/dist/packages/ember-testing/lib/adapters/adapter.js +1 -1
  102. package/dist/packages/ember-testing/lib/helpers/current_path.js +2 -2
  103. package/dist/packages/ember-testing/lib/helpers/current_route_name.js +2 -2
  104. package/dist/packages/ember-testing/lib/helpers/current_url.js +1 -1
  105. package/docs/data.json +9428 -9189
  106. package/package.json +23 -8
  107. package/types/preview/@ember/-internals/resolver.d.ts +35 -0
  108. package/types/preview/@ember/application/-private/event-dispatcher.d.ts +18 -0
  109. package/types/preview/@ember/application/-private/registry.d.ts +15 -0
  110. package/types/preview/@ember/application/deprecations.d.ts +24 -0
  111. package/types/preview/@ember/application/index.d.ts +153 -0
  112. package/types/preview/@ember/application/instance.d.ts +9 -0
  113. package/types/preview/@ember/application/tsconfig.json +3 -0
  114. package/types/preview/@ember/application/types.d.ts +29 -0
  115. package/types/preview/@ember/array/-private/enumerable.d.ts +13 -0
  116. package/types/preview/@ember/array/-private/mutable-enumerable.d.ts +13 -0
  117. package/types/preview/@ember/array/-private/native-array.d.ts +23 -0
  118. package/types/preview/@ember/array/index.d.ts +243 -0
  119. package/types/preview/@ember/array/mutable.d.ts +94 -0
  120. package/types/preview/@ember/array/proxy.d.ts +29 -0
  121. package/types/preview/@ember/array/tsconfig.json +3 -0
  122. package/types/preview/@ember/component/-private/class-names-support.d.ts +27 -0
  123. package/types/preview/@ember/component/-private/core-view.d.ts +14 -0
  124. package/types/preview/@ember/component/-private/glimmer-interfaces.d.ts +45 -0
  125. package/types/preview/@ember/component/-private/signature-utils.d.ts +107 -0
  126. package/types/preview/@ember/component/-private/view-mixin.d.ts +59 -0
  127. package/types/preview/@ember/component/helper.d.ts +122 -0
  128. package/types/preview/@ember/component/index.d.ts +132 -0
  129. package/types/preview/@ember/component/template-only.d.ts +47 -0
  130. package/types/preview/@ember/component/tsconfig.json +3 -0
  131. package/types/preview/@ember/controller/index.d.ts +48 -0
  132. package/types/preview/@ember/controller/tsconfig.json +3 -0
  133. package/types/preview/@ember/debug/container-debug-adapter.d.ts +13 -0
  134. package/types/preview/@ember/debug/data-adapter.d.ts +64 -0
  135. package/types/preview/@ember/debug/index.d.ts +98 -0
  136. package/types/preview/@ember/debug/tsconfig.json +3 -0
  137. package/types/preview/@ember/destroyable/index.d.ts +23 -0
  138. package/types/preview/@ember/destroyable/tsconfig.json +3 -0
  139. package/types/preview/@ember/engine/-private/container-proxy-mixin.d.ts +17 -0
  140. package/types/preview/@ember/engine/-private/registry-proxy-mixin.d.ts +54 -0
  141. package/types/preview/@ember/engine/-private/types/initializer.d.ts +8 -0
  142. package/types/preview/@ember/engine/index.d.ts +45 -0
  143. package/types/preview/@ember/engine/instance.d.ts +24 -0
  144. package/types/preview/@ember/engine/tsconfig.json +3 -0
  145. package/types/preview/@ember/error/index.d.ts +6 -0
  146. package/types/preview/@ember/error/tsconfig.json +3 -0
  147. package/types/preview/@ember/helper/index.d.ts +49 -0
  148. package/types/preview/@ember/helper/tsconfig.json +3 -0
  149. package/types/preview/@ember/modifier/index.d.ts +33 -0
  150. package/types/preview/@ember/modifier/tsconfig.json +3 -0
  151. package/types/preview/@ember/object/-private/action-handler.d.ts +31 -0
  152. package/types/preview/@ember/object/-private/types.d.ts +63 -0
  153. package/types/preview/@ember/object/compat.d.ts +9 -0
  154. package/types/preview/@ember/object/computed.d.ts +263 -0
  155. package/types/preview/@ember/object/core.d.ts +89 -0
  156. package/types/preview/@ember/object/evented.d.ts +45 -0
  157. package/types/preview/@ember/object/events.d.ts +47 -0
  158. package/types/preview/@ember/object/index.d.ts +126 -0
  159. package/types/preview/@ember/object/internals.d.ts +17 -0
  160. package/types/preview/@ember/object/mixin.d.ts +19 -0
  161. package/types/preview/@ember/object/observable.d.ts +89 -0
  162. package/types/preview/@ember/object/observers.d.ts +34 -0
  163. package/types/preview/@ember/object/promise-proxy-mixin.d.ts +37 -0
  164. package/types/preview/@ember/object/proxy.d.ts +27 -0
  165. package/types/preview/@ember/object/tsconfig.json +3 -0
  166. package/types/preview/@ember/owner/index.d.ts +102 -0
  167. package/types/preview/@ember/owner/tsconfig.json +3 -0
  168. package/types/preview/@ember/polyfills/index.d.ts +23 -0
  169. package/types/preview/@ember/polyfills/tsconfig.json +3 -0
  170. package/types/preview/@ember/polyfills/types.d.ts +6 -0
  171. package/types/preview/@ember/routing/-private/router-dsl.d.ts +20 -0
  172. package/types/preview/@ember/routing/auto-location.d.ts +8 -0
  173. package/types/preview/@ember/routing/hash-location.d.ts +10 -0
  174. package/types/preview/@ember/routing/history-location.d.ts +9 -0
  175. package/types/preview/@ember/routing/index.d.ts +20 -0
  176. package/types/preview/@ember/routing/none-location.d.ts +11 -0
  177. package/types/preview/@ember/routing/route-info.d.ts +74 -0
  178. package/types/preview/@ember/routing/route.d.ts +533 -0
  179. package/types/preview/@ember/routing/router-service.d.ts +351 -0
  180. package/types/preview/@ember/routing/router.d.ts +49 -0
  181. package/types/preview/@ember/routing/transition.d.ts +126 -0
  182. package/types/preview/@ember/routing/tsconfig.json +3 -0
  183. package/types/preview/@ember/routing/types.d.ts +15 -0
  184. package/types/preview/@ember/runloop/-private/backburner.d.ts +43 -0
  185. package/types/preview/@ember/runloop/-private/types.d.ts +9 -0
  186. package/types/preview/@ember/runloop/index.d.ts +175 -0
  187. package/types/preview/@ember/runloop/tsconfig.json +3 -0
  188. package/types/preview/@ember/runloop/types.d.ts +5 -0
  189. package/types/preview/@ember/service/index.d.ts +25 -0
  190. package/types/preview/@ember/service/tsconfig.json +3 -0
  191. package/types/preview/@ember/string/index.d.ts +9 -0
  192. package/types/preview/@ember/string/tsconfig.json +3 -0
  193. package/types/preview/@ember/template/-private/handlebars.d.ts +7 -0
  194. package/types/preview/@ember/template/index.d.ts +5 -0
  195. package/types/preview/@ember/template/tsconfig.json +3 -0
  196. package/types/preview/@ember/test/adapter.d.ts +22 -0
  197. package/types/preview/@ember/test/index.d.ts +49 -0
  198. package/types/preview/@ember/test/tsconfig.json +3 -0
  199. package/types/preview/@ember/utils/-private/types.d.ts +39 -0
  200. package/types/preview/@ember/utils/index.d.ts +42 -0
  201. package/types/preview/@ember/utils/tsconfig.json +3 -0
  202. package/types/preview/ember/-private/type-utils.d.ts +54 -0
  203. package/types/preview/ember/index.d.ts +381 -0
  204. package/types/preview/ember/tsconfig.json +3 -0
  205. package/types/preview/index.d.ts +120 -0
  206. package/types/preview/tsconfig.json +6 -0
  207. package/blueprints/helper/mu-files/__root__/__collection__/__name__.js +0 -7
  208. package/blueprints-js/helper/mu-files/__root__/__collection__/__name__.js +0 -7
  209. package/dist/packages/@ember/-internals/extension-support/index.js +0 -2
  210. package/dist/packages/@ember/-internals/extension-support/lib/container_debug_adapter.js +0 -96
  211. package/dist/packages/@ember/-internals/extension-support/lib/data_adapter.js +0 -576
  212. package/dist/packages/@ember/-internals/routing/lib/ext/controller.js +0 -224
  213. package/dist/packages/@ember/-internals/routing/lib/location/api.js +0 -104
  214. package/dist/packages/@ember/-internals/routing/lib/location/auto_location.js +0 -250
  215. package/dist/packages/@ember/-internals/routing/lib/location/hash_location.js +0 -170
  216. package/dist/packages/@ember/-internals/routing/lib/location/history_location.js +0 -290
  217. package/dist/packages/@ember/-internals/routing/lib/location/none_location.js +0 -124
  218. package/dist/packages/@ember/-internals/routing/lib/services/router.js +0 -506
  219. package/dist/packages/@ember/-internals/routing/lib/system/route.js +0 -1696
  220. package/dist/packages/@ember/-internals/routing/lib/system/router.js +0 -1662
  221. package/dist/packages/@ember/-internals/runtime/lib/mixins/array.js +0 -1501
  222. package/dist/packages/@ember/-internals/runtime/lib/mixins/enumerable.js +0 -3
  223. package/dist/packages/@ember/-internals/runtime/lib/mixins/evented.js +0 -91
  224. package/dist/packages/@ember/-internals/runtime/lib/mixins/mutable_enumerable.js +0 -4
  225. package/dist/packages/@ember/-internals/runtime/lib/mixins/observable.js +0 -339
  226. package/dist/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.js +0 -149
  227. package/dist/packages/@ember/-internals/runtime/lib/system/array_proxy.js +0 -305
  228. package/dist/packages/@ember/-internals/runtime/lib/system/core_object.js +0 -730
  229. package/dist/packages/@ember/-internals/runtime/lib/system/namespace.js +0 -69
  230. package/dist/packages/@ember/-internals/runtime/lib/system/object_proxy.js +0 -7
  231. package/dist/packages/@ember/application/lib/application.js +0 -870
  232. package/dist/packages/@ember/controller/lib/controller_mixin.js +0 -42
  233. package/dist/packages/@ember/runloop/type-tests.ts/begin-end.test.js +0 -5
  234. package/dist/packages/@ember/runloop/type-tests.ts/bind.test.js +0 -59
  235. package/dist/packages/@ember/runloop/type-tests.ts/cancel.test.js +0 -5
  236. package/dist/packages/@ember/runloop/type-tests.ts/debounce.test.js +0 -77
  237. package/dist/packages/@ember/runloop/type-tests.ts/join.test.js +0 -38
  238. package/dist/packages/@ember/runloop/type-tests.ts/later.test.js +0 -38
  239. package/dist/packages/@ember/runloop/type-tests.ts/next.test.js +0 -38
  240. package/dist/packages/@ember/runloop/type-tests.ts/once.test.js +0 -38
  241. package/dist/packages/@ember/runloop/type-tests.ts/run.test.js +0 -38
  242. package/dist/packages/@ember/runloop/type-tests.ts/schedule-once.test.js +0 -39
  243. package/dist/packages/@ember/runloop/type-tests.ts/schedule.test.js +0 -39
  244. package/dist/packages/@ember/runloop/type-tests.ts/throttle.test.js +0 -77
@@ -1 +1,1666 @@
1
- export { Router as default } from '@ember/-internals/routing';
1
+ import { privatize as P } from '@ember/-internals/container';
2
+ import { computed, get, set } from '@ember/object';
3
+ import { getOwner } from '@ember/-internals/owner';
4
+ import { BucketCache, DSL, RouterState } from '@ember/routing/-internals';
5
+ import { calculateCacheKey, extractRouteArgs, getActiveTargetName, resemblesURL } from './lib/utils';
6
+ import EmberLocation from '@ember/routing/location';
7
+ import EmberObject from '@ember/object';
8
+ import { A as emberA } from '@ember/array';
9
+ import { typeOf } from '@ember/utils';
10
+ import Evented from '@ember/object/evented';
11
+ import { assert, deprecate, info } from '@ember/debug';
12
+ import EmberError from '@ember/error';
13
+ import { cancel, once, run, scheduleOnce } from '@ember/runloop';
14
+ import { DEBUG } from '@glimmer/env';
15
+ import { defaultSerialize, getFullQueryParams, hasDefaultSerialize, ROUTE_CONNECTIONS } from '@ember/routing/route';
16
+ import Router, { logAbort, STATE_SYMBOL } from 'router_js';
17
+ import EngineInstance from '@ember/engine/instance';
18
+ /**
19
+ @module @ember/routing/router
20
+ */
21
+
22
+ function defaultDidTransition(infos) {
23
+ updatePaths(this);
24
+
25
+ this._cancelSlowTransitionTimer();
26
+
27
+ this.notifyPropertyChange('url');
28
+ this.set('currentState', this.targetState);
29
+
30
+ if (DEBUG) {
31
+ // @ts-expect-error namespace isn't public
32
+ if (this.namespace.LOG_TRANSITIONS) {
33
+ // eslint-disable-next-line no-console
34
+ console.log(`Transitioned into '${EmberRouter._routePath(infos)}'`);
35
+ }
36
+ }
37
+ }
38
+
39
+ function defaultWillTransition(oldInfos, newInfos) {
40
+ if (DEBUG) {
41
+ // @ts-expect-error namespace isn't public
42
+ if (this.namespace.LOG_TRANSITIONS) {
43
+ // eslint-disable-next-line no-console
44
+ console.log(`Preparing to transition from '${EmberRouter._routePath(oldInfos)}' to '${EmberRouter._routePath(newInfos)}'`);
45
+ }
46
+ }
47
+ }
48
+
49
+ let freezeRouteInfo;
50
+
51
+ if (DEBUG) {
52
+ freezeRouteInfo = transition => {
53
+ if (transition.from !== null && !Object.isFrozen(transition.from)) {
54
+ Object.freeze(transition.from);
55
+ }
56
+
57
+ if (transition.to !== null && !Object.isFrozen(transition.to)) {
58
+ Object.freeze(transition.to);
59
+ }
60
+ };
61
+ }
62
+
63
+ function K() {
64
+ return this;
65
+ }
66
+
67
+ const {
68
+ slice
69
+ } = Array.prototype;
70
+ /**
71
+ The `EmberRouter` class manages the application state and URLs. Refer to
72
+ the [routing guide](https://guides.emberjs.com/release/routing/) for documentation.
73
+
74
+ @class EmberRouter
75
+ @extends EmberObject
76
+ @uses Evented
77
+ @public
78
+ */
79
+
80
+ class EmberRouter extends EmberObject.extend(Evented) {
81
+ // Note that owner is actually required in this scenario, but since it is strictly
82
+ // optional in other contexts trying to make it required here confuses TS.
83
+ constructor(owner) {
84
+ super(owner);
85
+ this._didSetupRouter = false;
86
+ this._initialTransitionStarted = false;
87
+ this.currentURL = null;
88
+ this.currentRouteName = null;
89
+ this.currentPath = null;
90
+ this.currentRoute = null;
91
+ this._qpCache = Object.create(null); // Set of QueryParam['urlKey']
92
+
93
+ this._qpUpdates = new Set();
94
+ this._queuedQPChanges = {};
95
+ this._toplevelView = null;
96
+ this._handledErrors = new Set();
97
+ this._engineInstances = Object.create(null);
98
+ this._engineInfoByRoute = Object.create(null);
99
+ this._slowTransitionTimer = null;
100
+ this.currentState = null;
101
+ this.targetState = null;
102
+ assert('BUG: Missing owner', owner);
103
+
104
+ this._resetQueuedQueryParameterChanges();
105
+
106
+ this.namespace = owner.lookup('application:main');
107
+ let bucketCache = owner.lookup(P`-bucket-cache:main`);
108
+ assert('BUG: BucketCache should always be present', bucketCache instanceof BucketCache);
109
+ this._bucketCache = bucketCache;
110
+ let routerService = owner.lookup('service:router');
111
+ assert('BUG: RouterService should always be present', routerService !== undefined);
112
+ this._routerService = routerService;
113
+ }
114
+ /**
115
+ The `Router.map` function allows you to define mappings from URLs to routes
116
+ in your application. These mappings are defined within the
117
+ supplied callback function using `this.route`.
118
+ The first parameter is the name of the route which is used by default as the
119
+ path name as well.
120
+ The second parameter is the optional options hash. Available options are:
121
+ * `path`: allows you to provide your own path as well as mark dynamic
122
+ segments.
123
+ * `resetNamespace`: false by default; when nesting routes, ember will
124
+ combine the route names to form the fully-qualified route name, which is
125
+ used with `{{link-to}}` or manually transitioning to routes. Setting
126
+ `resetNamespace: true` will cause the route not to inherit from its
127
+ parent route's names. This is handy for preventing extremely long route names.
128
+ Keep in mind that the actual URL path behavior is still retained.
129
+ The third parameter is a function, which can be used to nest routes.
130
+ Nested routes, by default, will have the parent route tree's route name and
131
+ path prepended to it's own.
132
+ ```app/router.js
133
+ Router.map(function(){
134
+ this.route('post', { path: '/post/:post_id' }, function() {
135
+ this.route('edit');
136
+ this.route('comments', { resetNamespace: true }, function() {
137
+ this.route('new');
138
+ });
139
+ });
140
+ });
141
+ ```
142
+ @method map
143
+ @param callback
144
+ @public
145
+ */
146
+
147
+
148
+ static map(callback) {
149
+ if (!this.dslCallbacks) {
150
+ this.dslCallbacks = []; // FIXME: Can we remove this?
151
+
152
+ this.reopenClass({
153
+ dslCallbacks: this.dslCallbacks
154
+ });
155
+ }
156
+
157
+ this.dslCallbacks.push(callback);
158
+ return this;
159
+ }
160
+
161
+ static _routePath(routeInfos) {
162
+ let path = []; // We have to handle coalescing resource names that
163
+ // are prefixed with their parent's names, e.g.
164
+ // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz'
165
+
166
+ function intersectionMatches(a1, a2) {
167
+ for (let i = 0; i < a1.length; ++i) {
168
+ if (a1[i] !== a2[i]) {
169
+ return false;
170
+ }
171
+ }
172
+
173
+ return true;
174
+ }
175
+
176
+ let name, nameParts, oldNameParts;
177
+
178
+ for (let i = 1; i < routeInfos.length; i++) {
179
+ let routeInfo = routeInfos[i];
180
+ assert('has routeInfo', routeInfo);
181
+ name = routeInfo.name;
182
+ nameParts = name.split('.');
183
+ oldNameParts = slice.call(path);
184
+
185
+ while (oldNameParts.length) {
186
+ if (intersectionMatches(oldNameParts, nameParts)) {
187
+ break;
188
+ }
189
+
190
+ oldNameParts.shift();
191
+ }
192
+
193
+ path.push(...nameParts.slice(oldNameParts.length));
194
+ }
195
+
196
+ return path.join('.');
197
+ }
198
+
199
+ _initRouterJs() {
200
+ let location = get(this, 'location');
201
+ let router = this;
202
+ const owner = getOwner(this);
203
+ assert('Router is unexpectedly missing an owner', owner);
204
+ let seen = Object.create(null);
205
+
206
+ class PrivateRouter extends Router {
207
+ getRoute(name) {
208
+ let routeName = name;
209
+ let routeOwner = owner;
210
+ let engineInfo = router._engineInfoByRoute[routeName];
211
+
212
+ if (engineInfo) {
213
+ let engineInstance = router._getEngineInstance(engineInfo);
214
+
215
+ routeOwner = engineInstance;
216
+ routeName = engineInfo.localFullName;
217
+ }
218
+
219
+ let fullRouteName = `route:${routeName}`;
220
+ assert('Route is unexpectedly missing an owner', routeOwner);
221
+ let route = routeOwner.lookup(fullRouteName);
222
+
223
+ if (seen[name]) {
224
+ assert('seen routes should exist', route);
225
+ return route;
226
+ }
227
+
228
+ seen[name] = true;
229
+
230
+ if (!route) {
231
+ // SAFETY: this is configured in `commonSetupRegistry` in the
232
+ // `@ember/application/lib` package.
233
+ let DefaultRoute = routeOwner.factoryFor('route:basic').class;
234
+ routeOwner.register(fullRouteName, DefaultRoute.extend());
235
+ route = routeOwner.lookup(fullRouteName);
236
+
237
+ if (DEBUG) {
238
+ if (router.namespace.LOG_ACTIVE_GENERATION) {
239
+ info(`generated -> ${fullRouteName}`, {
240
+ fullName: fullRouteName
241
+ });
242
+ }
243
+ }
244
+ }
245
+
246
+ route._setRouteName(routeName);
247
+
248
+ if (engineInfo && !hasDefaultSerialize(route)) {
249
+ throw new Error('Defining a custom serialize method on an Engine route is not supported.');
250
+ }
251
+
252
+ return route;
253
+ }
254
+
255
+ getSerializer(name) {
256
+ let engineInfo = router._engineInfoByRoute[name]; // If this is not an Engine route, we fall back to the handler for serialization
257
+
258
+ if (!engineInfo) {
259
+ return;
260
+ }
261
+
262
+ return engineInfo.serializeMethod || defaultSerialize;
263
+ }
264
+
265
+ updateURL(path) {
266
+ once(() => {
267
+ location.setURL(path);
268
+ set(router, 'currentURL', path);
269
+ });
270
+ } // TODO: merge into routeDidChange
271
+
272
+
273
+ didTransition(infos) {
274
+ 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);
275
+ router.didTransition(infos);
276
+ } // TODO: merge into routeWillChange
277
+
278
+
279
+ willTransition(oldInfos, newInfos) {
280
+ 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);
281
+ router.willTransition(oldInfos, newInfos);
282
+ }
283
+
284
+ triggerEvent(routeInfos, ignoreFailure, name, args) {
285
+ return triggerEvent.bind(router)(routeInfos, ignoreFailure, name, args);
286
+ }
287
+
288
+ routeWillChange(transition) {
289
+ router.trigger('routeWillChange', transition);
290
+
291
+ if (DEBUG) {
292
+ freezeRouteInfo(transition);
293
+ }
294
+
295
+ router._routerService.trigger('routeWillChange', transition); // in case of intermediate transition we update the current route
296
+ // to make router.currentRoute.name consistent with router.currentRouteName
297
+ // see https://github.com/emberjs/ember.js/issues/19449
298
+
299
+
300
+ if (transition.isIntermediate) {
301
+ router.set('currentRoute', transition.to);
302
+ }
303
+ }
304
+
305
+ routeDidChange(transition) {
306
+ router.set('currentRoute', transition.to);
307
+ once(() => {
308
+ router.trigger('routeDidChange', transition);
309
+
310
+ if (DEBUG) {
311
+ freezeRouteInfo(transition);
312
+ }
313
+
314
+ router._routerService.trigger('routeDidChange', transition);
315
+ });
316
+ }
317
+
318
+ transitionDidError(error, transition) {
319
+ if (error.wasAborted || transition.isAborted) {
320
+ // If the error was a transition erorr or the transition aborted
321
+ // log the abort.
322
+ return logAbort(transition);
323
+ } else {
324
+ // Otherwise trigger the "error" event to attempt an intermediate
325
+ // transition into an error substate
326
+ transition.trigger(false, 'error', error.error, transition, error.route);
327
+
328
+ if (router._isErrorHandled(error.error)) {
329
+ // If we handled the error with a substate just roll the state back on
330
+ // the transition and send the "routeDidChange" event for landing on
331
+ // the error substate and return the error.
332
+ transition.rollback();
333
+ this.routeDidChange(transition);
334
+ return error.error;
335
+ } else {
336
+ // If it was not handled, abort the transition completely and return
337
+ // the error.
338
+ transition.abort();
339
+ return error.error;
340
+ }
341
+ }
342
+ }
343
+
344
+ replaceURL(url) {
345
+ if (location.replaceURL) {
346
+ let doReplaceURL = () => {
347
+ location.replaceURL(url);
348
+ set(router, 'currentURL', url);
349
+ };
350
+
351
+ once(doReplaceURL);
352
+ } else {
353
+ this.updateURL(url);
354
+ }
355
+ }
356
+
357
+ }
358
+
359
+ let routerMicrolib = this._routerMicrolib = new PrivateRouter();
360
+ let dslCallbacks = this.constructor.dslCallbacks || [K];
361
+
362
+ let dsl = this._buildDSL();
363
+
364
+ dsl.route('application', {
365
+ path: '/',
366
+ resetNamespace: true,
367
+ overrideNameAssertion: true
368
+ }, function () {
369
+ for (let i = 0; i < dslCallbacks.length; i++) {
370
+ dslCallbacks[i].call(this);
371
+ }
372
+ });
373
+
374
+ if (DEBUG) {
375
+ if (this.namespace.LOG_TRANSITIONS_INTERNAL) {
376
+ routerMicrolib.log = console.log.bind(console); // eslint-disable-line no-console
377
+ }
378
+ }
379
+
380
+ routerMicrolib.map(dsl.generate());
381
+ }
382
+
383
+ _buildDSL() {
384
+ let enableLoadingSubstates = this._hasModuleBasedResolver();
385
+
386
+ let router = this;
387
+ const owner = getOwner(this);
388
+ assert('Router is unexpectedly missing an owner', owner);
389
+ let options = {
390
+ enableLoadingSubstates,
391
+
392
+ resolveRouteMap(name) {
393
+ return owner.factoryFor(`route-map:${name}`);
394
+ },
395
+
396
+ addRouteForEngine(name, engineInfo) {
397
+ if (!router._engineInfoByRoute[name]) {
398
+ router._engineInfoByRoute[name] = engineInfo;
399
+ }
400
+ }
401
+
402
+ };
403
+ return new DSL(null, options);
404
+ }
405
+ /*
406
+ Resets all pending query parameter changes.
407
+ Called after transitioning to a new route
408
+ based on query parameter changes.
409
+ */
410
+
411
+
412
+ _resetQueuedQueryParameterChanges() {
413
+ this._queuedQPChanges = {};
414
+ }
415
+
416
+ _hasModuleBasedResolver() {
417
+ let owner = getOwner(this);
418
+ assert('Router is unexpectedly missing an owner', owner);
419
+ let resolver = get(owner, 'application.__registry__.resolver.moduleBasedResolver');
420
+ return Boolean(resolver);
421
+ }
422
+ /**
423
+ Initializes the current router instance and sets up the change handling
424
+ event listeners used by the instances `location` implementation.
425
+ A property named `initialURL` will be used to determine the initial URL.
426
+ If no value is found `/` will be used.
427
+ @method startRouting
428
+ @private
429
+ */
430
+
431
+
432
+ startRouting() {
433
+ if (this.setupRouter()) {
434
+ let initialURL = get(this, 'initialURL');
435
+
436
+ if (initialURL === undefined) {
437
+ initialURL = get(this, 'location').getURL();
438
+ }
439
+
440
+ let initialTransition = this.handleURL(initialURL);
441
+
442
+ if (initialTransition && initialTransition.error) {
443
+ throw initialTransition.error;
444
+ }
445
+ }
446
+ }
447
+
448
+ setupRouter() {
449
+ if (this._didSetupRouter) {
450
+ return false;
451
+ }
452
+
453
+ this._didSetupRouter = true;
454
+
455
+ this._setupLocation();
456
+
457
+ let location = get(this, 'location'); // Allow the Location class to cancel the router setup while it refreshes
458
+ // the page
459
+
460
+ if (get(location, 'cancelRouterSetup')) {
461
+ return false;
462
+ }
463
+
464
+ this._initRouterJs();
465
+
466
+ location.onUpdateURL(url => {
467
+ this.handleURL(url);
468
+ });
469
+ return true;
470
+ }
471
+
472
+ _setOutlets() {
473
+ // This is triggered async during Route#willDestroy.
474
+ // If the router is also being destroyed we do not want to
475
+ // to create another this._toplevelView (and leak the renderer)
476
+ if (this.isDestroying || this.isDestroyed) {
477
+ return;
478
+ }
479
+
480
+ let routeInfos = this._routerMicrolib.currentRouteInfos;
481
+
482
+ if (!routeInfos) {
483
+ return;
484
+ }
485
+
486
+ let defaultParentState;
487
+ let liveRoutes = null;
488
+
489
+ for (let routeInfo of routeInfos) {
490
+ let route = routeInfo.route;
491
+ let connections = ROUTE_CONNECTIONS.get(route);
492
+ let ownState;
493
+
494
+ if (connections.length === 0) {
495
+ ownState = representEmptyRoute(liveRoutes, defaultParentState, route);
496
+ } else {
497
+ for (let j = 0; j < connections.length; j++) {
498
+ let appended = appendLiveRoute(liveRoutes, defaultParentState, connections[j]);
499
+ liveRoutes = appended.liveRoutes;
500
+ let {
501
+ name,
502
+ outlet
503
+ } = appended.ownState.render;
504
+
505
+ if (name === route.routeName || outlet === 'main') {
506
+ ownState = appended.ownState;
507
+ }
508
+ }
509
+ }
510
+
511
+ defaultParentState = ownState;
512
+ } // when a transitionTo happens after the validation phase
513
+ // during the initial transition _setOutlets is called
514
+ // when no routes are active. However, it will get called
515
+ // again with the correct values during the next turn of
516
+ // the runloop
517
+
518
+
519
+ if (!liveRoutes) {
520
+ return;
521
+ }
522
+
523
+ if (!this._toplevelView) {
524
+ let owner = getOwner(this);
525
+ assert('Router is unexpectedly missing an owner', owner);
526
+ let OutletView = owner.factoryFor('view:-outlet');
527
+ let application = owner.lookup('application:main');
528
+ let environment = owner.lookup('-environment:main');
529
+ let template = owner.lookup('template:-outlet');
530
+ this._toplevelView = OutletView.create({
531
+ environment,
532
+ template,
533
+ application
534
+ });
535
+
536
+ this._toplevelView.setOutletState(liveRoutes);
537
+
538
+ let instance = owner.lookup('-application-instance:main');
539
+
540
+ if (instance) {
541
+ instance.didCreateRootView(this._toplevelView);
542
+ }
543
+ } else {
544
+ this._toplevelView.setOutletState(liveRoutes);
545
+ }
546
+ }
547
+
548
+ handleURL(url) {
549
+ // Until we have an ember-idiomatic way of accessing #hashes, we need to
550
+ // remove it because router.js doesn't know how to handle it.
551
+ let _url = url.split(/#(.+)?/)[0];
552
+ return this._doURLTransition('handleURL', _url);
553
+ }
554
+
555
+ _doURLTransition(routerJsMethod, url) {
556
+ this._initialTransitionStarted = true;
557
+
558
+ let transition = this._routerMicrolib[routerJsMethod](url || '/');
559
+
560
+ didBeginTransition(transition, this);
561
+ return transition;
562
+ }
563
+ /**
564
+ Transition the application into another route. The route may
565
+ be either a single route or route path:
566
+ @method transitionTo
567
+ @param {String} [name] the name of the route or a URL
568
+ @param {...Object} models the model(s) or identifier(s) to be used while
569
+ transitioning to the route.
570
+ @param {Object} [options] optional hash with a queryParams property
571
+ containing a mapping of query parameters
572
+ @return {Transition} the transition object associated with this
573
+ attempted transition
574
+ @public
575
+ */
576
+
577
+
578
+ transitionTo(...args) {
579
+ if (resemblesURL(args[0])) {
580
+ assert(`A transition was attempted from '${this.currentRouteName}' to '${args[0]}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed);
581
+ return this._doURLTransition('transitionTo', args[0]);
582
+ }
583
+
584
+ let {
585
+ routeName,
586
+ models,
587
+ queryParams
588
+ } = extractRouteArgs(args);
589
+ assert(`A transition was attempted from '${this.currentRouteName}' to '${routeName}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed);
590
+ return this._doTransition(routeName, models, queryParams);
591
+ }
592
+
593
+ intermediateTransitionTo(name, ...args) {
594
+ this._routerMicrolib.intermediateTransitionTo(name, ...args);
595
+
596
+ updatePaths(this);
597
+
598
+ if (DEBUG) {
599
+ let infos = this._routerMicrolib.currentRouteInfos;
600
+
601
+ if (this.namespace.LOG_TRANSITIONS) {
602
+ assert('expected infos to be set', infos); // eslint-disable-next-line no-console
603
+
604
+ console.log(`Intermediate-transitioned into '${EmberRouter._routePath(infos)}'`);
605
+ }
606
+ }
607
+ }
608
+ /**
609
+ Similar to `transitionTo`, but instead of adding the destination to the browser's URL history,
610
+ it replaces the entry for the current route.
611
+ When the user clicks the "back" button in the browser, there will be fewer steps.
612
+ This is most commonly used to manage redirects in a way that does not cause confusing additions
613
+ to the user's browsing history.
614
+ @method replaceWith
615
+ @param {String} [name] the name of the route or a URL
616
+ @param {...Object} models the model(s) or identifier(s) to be used while
617
+ transitioning to the route.
618
+ @param {Object} [options] optional hash with a queryParams property
619
+ containing a mapping of query parameters
620
+ @return {Transition} the transition object associated with this
621
+ attempted transition
622
+ @public
623
+ */
624
+
625
+
626
+ replaceWith(...args) {
627
+ return this.transitionTo(...args).method('replace');
628
+ }
629
+
630
+ generate(name, ...args) {
631
+ let url = this._routerMicrolib.generate(name, ...args);
632
+
633
+ assert('expected non-string location', typeof this.location !== 'string');
634
+ return this.location.formatURL(url);
635
+ }
636
+ /**
637
+ Determines if the supplied route is currently active.
638
+ @method isActive
639
+ @param routeName
640
+ @return {Boolean}
641
+ @private
642
+ */
643
+
644
+
645
+ isActive(routeName) {
646
+ return this._routerMicrolib.isActive(routeName);
647
+ }
648
+ /**
649
+ An alternative form of `isActive` that doesn't require
650
+ manual concatenation of the arguments into a single
651
+ array.
652
+ @method isActiveIntent
653
+ @param routeName
654
+ @param models
655
+ @param queryParams
656
+ @return {Boolean}
657
+ @private
658
+ @since 1.7.0
659
+ */
660
+
661
+
662
+ isActiveIntent(routeName, models, queryParams) {
663
+ return this.currentState.isActiveIntent(routeName, models, queryParams);
664
+ }
665
+
666
+ send(name, ...args) {
667
+ /*name, context*/
668
+ this._routerMicrolib.trigger(name, ...args);
669
+ }
670
+ /**
671
+ Does this router instance have the given route.
672
+ @method hasRoute
673
+ @return {Boolean}
674
+ @private
675
+ */
676
+
677
+
678
+ hasRoute(route) {
679
+ return this._routerMicrolib.hasRoute(route);
680
+ }
681
+ /**
682
+ Resets the state of the router by clearing the current route
683
+ handlers and deactivating them.
684
+ @private
685
+ @method reset
686
+ */
687
+
688
+
689
+ reset() {
690
+ this._didSetupRouter = false;
691
+ this._initialTransitionStarted = false;
692
+
693
+ if (this._routerMicrolib) {
694
+ this._routerMicrolib.reset();
695
+ }
696
+ }
697
+
698
+ willDestroy() {
699
+ if (this._toplevelView) {
700
+ this._toplevelView.destroy();
701
+
702
+ this._toplevelView = null;
703
+ }
704
+
705
+ super.willDestroy();
706
+ this.reset();
707
+ let instances = this._engineInstances;
708
+
709
+ for (let name in instances) {
710
+ let instanceMap = instances[name];
711
+ assert('has instanceMap', instanceMap);
712
+
713
+ for (let id in instanceMap) {
714
+ let instance = instanceMap[id];
715
+ assert('has instance', instance);
716
+ run(instance, 'destroy');
717
+ }
718
+ }
719
+ }
720
+ /*
721
+ Called when an active route's query parameter has changed.
722
+ These changes are batched into a runloop run and trigger
723
+ a single transition.
724
+ */
725
+
726
+
727
+ _activeQPChanged(queryParameterName, newValue) {
728
+ this._queuedQPChanges[queryParameterName] = newValue;
729
+ once(this, this._fireQueryParamTransition);
730
+ } // The queryParameterName is QueryParam['urlKey']
731
+
732
+
733
+ _updatingQPChanged(queryParameterName) {
734
+ this._qpUpdates.add(queryParameterName);
735
+ }
736
+ /*
737
+ Triggers a transition to a route based on query parameter changes.
738
+ This is called once per runloop, to batch changes.
739
+ e.g.
740
+ if these methods are called in succession:
741
+ this._activeQPChanged('foo', '10');
742
+ // results in _queuedQPChanges = { foo: '10' }
743
+ this._activeQPChanged('bar', false);
744
+ // results in _queuedQPChanges = { foo: '10', bar: false }
745
+ _queuedQPChanges will represent both of these changes
746
+ and the transition using `transitionTo` will be triggered
747
+ once.
748
+ */
749
+
750
+
751
+ _fireQueryParamTransition() {
752
+ this.transitionTo({
753
+ queryParams: this._queuedQPChanges
754
+ });
755
+
756
+ this._resetQueuedQueryParameterChanges();
757
+ }
758
+
759
+ _setupLocation() {
760
+ let location = this.location;
761
+ let rootURL = this.rootURL;
762
+ let owner = getOwner(this);
763
+ assert('Router is unexpectedly missing an owner', owner);
764
+
765
+ if ('string' === typeof location) {
766
+ let resolvedLocation = owner.lookup(`location:${location}`);
767
+
768
+ if (location === 'auto') {
769
+ deprecate("Router location 'auto' is deprecated. Most users will want to set `locationType` to 'history' in config/environment.js for no change in behavior. See deprecation docs for details.", false, {
770
+ id: 'deprecate-auto-location',
771
+ until: '5.0.0',
772
+ url: 'https://emberjs.com/deprecations/v4.x#toc_deprecate-auto-location',
773
+ for: 'ember-source',
774
+ since: {
775
+ available: '4.1.0',
776
+ enabled: '4.1.0'
777
+ }
778
+ });
779
+ }
780
+
781
+ if (resolvedLocation !== undefined) {
782
+ location = set(this, 'location', resolvedLocation);
783
+ } else {
784
+ // Allow for deprecated registration of custom location API's
785
+ let options = {
786
+ implementation: location
787
+ };
788
+ location = set(this, 'location', EmberLocation.create(options));
789
+ }
790
+ }
791
+
792
+ if (location !== null && typeof location === 'object') {
793
+ if (rootURL) {
794
+ set(location, 'rootURL', rootURL);
795
+ } // Allow the location to do any feature detection, such as AutoLocation
796
+ // detecting history support. This gives it a chance to set its
797
+ // `cancelRouterSetup` property which aborts routing.
798
+
799
+
800
+ if (typeof location.detect === 'function') {
801
+ if (this.location !== 'auto') {
802
+ deprecate('The `detect` method on the Location object is deprecated. If you need detection you can run your detection code in app.js, before setting the location type.', false, {
803
+ id: 'deprecate-auto-location',
804
+ until: '5.0.0',
805
+ url: 'https://emberjs.com/deprecations/v4.x#toc_deprecate-auto-location',
806
+ for: 'ember-source',
807
+ since: {
808
+ available: '4.1.0',
809
+ enabled: '4.1.0'
810
+ }
811
+ });
812
+ }
813
+
814
+ location.detect();
815
+ } // ensure that initState is called AFTER the rootURL is set on
816
+ // the location instance
817
+
818
+
819
+ if (typeof location.initState === 'function') {
820
+ location.initState();
821
+ }
822
+ }
823
+ }
824
+ /**
825
+ Serializes the given query params according to their QP meta information.
826
+ @private
827
+ @method _serializeQueryParams
828
+ @param {Arrray<RouteInfo>} routeInfos
829
+ @param {Object} queryParams
830
+ @return {Void}
831
+ */
832
+
833
+
834
+ _serializeQueryParams(routeInfos, queryParams) {
835
+ forEachQueryParam(this, routeInfos, queryParams, (key, value, qp) => {
836
+ if (qp) {
837
+ delete queryParams[key];
838
+ queryParams[qp.urlKey] = qp.route.serializeQueryParam(value, qp.urlKey, qp.type);
839
+ } else if (value === undefined) {
840
+ return; // We don't serialize undefined values
841
+ } else {
842
+ queryParams[key] = this._serializeQueryParam(value, typeOf(value));
843
+ }
844
+ });
845
+ }
846
+ /**
847
+ Serializes the value of a query parameter based on a type
848
+ @private
849
+ @method _serializeQueryParam
850
+ @param {Object} value
851
+ @param {String} type
852
+ */
853
+
854
+
855
+ _serializeQueryParam(value, type) {
856
+ if (value === null || value === undefined) {
857
+ return value;
858
+ } else if (type === 'array') {
859
+ return JSON.stringify(value);
860
+ }
861
+
862
+ return `${value}`;
863
+ }
864
+ /**
865
+ Deserializes the given query params according to their QP meta information.
866
+ @private
867
+ @method _deserializeQueryParams
868
+ @param {Array<RouteInfo>} routeInfos
869
+ @param {Object} queryParams
870
+ @return {Void}
871
+ */
872
+
873
+
874
+ _deserializeQueryParams(routeInfos, queryParams) {
875
+ forEachQueryParam(this, routeInfos, queryParams, (key, value, qp) => {
876
+ // If we don't have QP meta info for a given key, then we do nothing
877
+ // because all values will be treated as strings
878
+ if (qp) {
879
+ delete queryParams[key];
880
+ queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type);
881
+ }
882
+ });
883
+ }
884
+ /**
885
+ Deserializes the value of a query parameter based on a default type
886
+ @private
887
+ @method _deserializeQueryParam
888
+ @param {Object} value
889
+ @param {String} defaultType
890
+ */
891
+
892
+
893
+ _deserializeQueryParam(value, defaultType) {
894
+ if (value === null || value === undefined) {
895
+ return value;
896
+ } else if (defaultType === 'boolean') {
897
+ return value === 'true';
898
+ } else if (defaultType === 'number') {
899
+ return Number(value).valueOf();
900
+ } else if (defaultType === 'array') {
901
+ return emberA(JSON.parse(value));
902
+ }
903
+
904
+ return value;
905
+ }
906
+ /**
907
+ Removes (prunes) any query params with default values from the given QP
908
+ object. Default values are determined from the QP meta information per key.
909
+ @private
910
+ @method _pruneDefaultQueryParamValues
911
+ @param {Array<RouteInfo>} routeInfos
912
+ @param {Object} queryParams
913
+ @return {Void}
914
+ */
915
+
916
+
917
+ _pruneDefaultQueryParamValues(routeInfos, queryParams) {
918
+ let qps = this._queryParamsFor(routeInfos);
919
+
920
+ for (let key in queryParams) {
921
+ let qp = qps.map[key];
922
+
923
+ if (qp && qp.serializedDefaultValue === queryParams[key]) {
924
+ delete queryParams[key];
925
+ }
926
+ }
927
+ }
928
+
929
+ _doTransition(_targetRouteName, models, _queryParams, _fromRouterService) {
930
+ let targetRouteName = _targetRouteName || getActiveTargetName(this._routerMicrolib);
931
+
932
+ assert(`The route ${targetRouteName} was not found`, Boolean(targetRouteName) && this._routerMicrolib.hasRoute(targetRouteName));
933
+ this._initialTransitionStarted = true;
934
+ let queryParams = {};
935
+
936
+ this._processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams);
937
+
938
+ Object.assign(queryParams, _queryParams);
939
+
940
+ this._prepareQueryParams(targetRouteName, models, queryParams, Boolean(_fromRouterService));
941
+
942
+ let transition = this._routerMicrolib.transitionTo(targetRouteName, ...models, {
943
+ queryParams
944
+ });
945
+
946
+ didBeginTransition(transition, this);
947
+ return transition;
948
+ }
949
+
950
+ _processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams) {
951
+ // merge in any queryParams from the active transition which could include
952
+ // queryParams from the url on initial load.
953
+ if (!this._routerMicrolib.activeTransition) {
954
+ return;
955
+ }
956
+
957
+ let unchangedQPs = {};
958
+ let qpUpdates = this._qpUpdates;
959
+ let params = getFullQueryParams(this, this._routerMicrolib.activeTransition[STATE_SYMBOL]);
960
+
961
+ for (let key in params) {
962
+ if (!qpUpdates.has(key)) {
963
+ unchangedQPs[key] = params[key];
964
+ }
965
+ } // We need to fully scope queryParams so that we can create one object
966
+ // that represents both passed-in queryParams and ones that aren't changed
967
+ // from the active transition.
968
+
969
+
970
+ this._fullyScopeQueryParams(targetRouteName, models, _queryParams);
971
+
972
+ this._fullyScopeQueryParams(targetRouteName, models, unchangedQPs);
973
+
974
+ Object.assign(queryParams, unchangedQPs);
975
+ }
976
+ /**
977
+ Prepares the query params for a URL or Transition. Restores any undefined QP
978
+ keys/values, serializes all values, and then prunes any default values.
979
+ @private
980
+ @method _prepareQueryParams
981
+ @param {String} targetRouteName
982
+ @param {Array<Object>} models
983
+ @param {Object} queryParams
984
+ @param {boolean} keepDefaultQueryParamValues
985
+ @return {Void}
986
+ */
987
+
988
+
989
+ _prepareQueryParams(targetRouteName, models, queryParams, _fromRouterService) {
990
+ let state = calculatePostTransitionState(this, targetRouteName, models);
991
+
992
+ this._hydrateUnsuppliedQueryParams(state, queryParams, Boolean(_fromRouterService));
993
+
994
+ this._serializeQueryParams(state.routeInfos, queryParams);
995
+
996
+ if (!_fromRouterService) {
997
+ this._pruneDefaultQueryParamValues(state.routeInfos, queryParams);
998
+ }
999
+ }
1000
+ /**
1001
+ Returns the meta information for the query params of a given route. This
1002
+ will be overridden to allow support for lazy routes.
1003
+ @private
1004
+ @method _getQPMeta
1005
+ @param {RouteInfo} routeInfo
1006
+ @return {Object}
1007
+ */
1008
+
1009
+
1010
+ _getQPMeta(routeInfo) {
1011
+ let route = routeInfo.route;
1012
+ return route && get(route, '_qp');
1013
+ }
1014
+ /**
1015
+ Returns a merged query params meta object for a given set of routeInfos.
1016
+ Useful for knowing what query params are available for a given route hierarchy.
1017
+ @private
1018
+ @method _queryParamsFor
1019
+ @param {Array<RouteInfo>} routeInfos
1020
+ @return {Object}
1021
+ */
1022
+
1023
+
1024
+ _queryParamsFor(routeInfos) {
1025
+ let routeInfoLength = routeInfos.length;
1026
+ let leafRouteName = routeInfos[routeInfoLength - 1].name;
1027
+ let cached = this._qpCache[leafRouteName];
1028
+
1029
+ if (cached !== undefined) {
1030
+ return cached;
1031
+ }
1032
+
1033
+ let shouldCache = true;
1034
+ let map = {};
1035
+ let qps = [];
1036
+ let qpsByUrlKey = DEBUG ? {} : null;
1037
+ let qpMeta;
1038
+ let urlKey;
1039
+ let qpOther;
1040
+
1041
+ for (let routeInfo of routeInfos) {
1042
+ qpMeta = this._getQPMeta(routeInfo);
1043
+
1044
+ if (!qpMeta) {
1045
+ shouldCache = false;
1046
+ continue;
1047
+ } // Loop over each QP to make sure we don't have any collisions by urlKey
1048
+
1049
+
1050
+ for (let qp of qpMeta.qps) {
1051
+ if (DEBUG) {
1052
+ urlKey = qp.urlKey;
1053
+ qpOther = qpsByUrlKey[urlKey];
1054
+
1055
+ if (qpOther && qpOther.controllerName !== qp.controllerName) {
1056
+ 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);
1057
+ }
1058
+
1059
+ qpsByUrlKey[urlKey] = qp;
1060
+ }
1061
+
1062
+ qps.push(qp);
1063
+ }
1064
+
1065
+ Object.assign(map, qpMeta.map);
1066
+ }
1067
+
1068
+ let finalQPMeta = {
1069
+ qps,
1070
+ map
1071
+ };
1072
+
1073
+ if (shouldCache) {
1074
+ this._qpCache[leafRouteName] = finalQPMeta;
1075
+ }
1076
+
1077
+ return finalQPMeta;
1078
+ }
1079
+ /**
1080
+ Maps all query param keys to their fully scoped property name of the form
1081
+ `controllerName:propName`.
1082
+ @private
1083
+ @method _fullyScopeQueryParams
1084
+ @param {String} leafRouteName
1085
+ @param {Array<Object>} contexts
1086
+ @param {Object} queryParams
1087
+ @return {Void}
1088
+ */
1089
+
1090
+
1091
+ _fullyScopeQueryParams(leafRouteName, contexts, queryParams) {
1092
+ let state = calculatePostTransitionState(this, leafRouteName, contexts);
1093
+ let routeInfos = state.routeInfos;
1094
+ let qpMeta;
1095
+
1096
+ for (let routeInfo of routeInfos) {
1097
+ qpMeta = this._getQPMeta(routeInfo);
1098
+
1099
+ if (!qpMeta) {
1100
+ continue;
1101
+ }
1102
+
1103
+ for (let qp of qpMeta.qps) {
1104
+ let presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName || qp.urlKey in queryParams && qp.urlKey;
1105
+
1106
+ if (presentProp) {
1107
+ if (presentProp !== qp.scopedPropertyName) {
1108
+ queryParams[qp.scopedPropertyName] = queryParams[presentProp];
1109
+ delete queryParams[presentProp];
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1114
+ }
1115
+ /**
1116
+ Hydrates (adds/restores) any query params that have pre-existing values into
1117
+ the given queryParams hash. This is what allows query params to be "sticky"
1118
+ and restore their last known values for their scope.
1119
+ @private
1120
+ @method _hydrateUnsuppliedQueryParams
1121
+ @param {TransitionState} state
1122
+ @param {Object} queryParams
1123
+ @return {Void}
1124
+ */
1125
+
1126
+
1127
+ _hydrateUnsuppliedQueryParams(state, queryParams, _fromRouterService) {
1128
+ let routeInfos = state.routeInfos;
1129
+ let appCache = this._bucketCache;
1130
+ let qpMeta;
1131
+ let qp;
1132
+ let presentProp;
1133
+
1134
+ for (let routeInfo of routeInfos) {
1135
+ qpMeta = this._getQPMeta(routeInfo);
1136
+
1137
+ if (!qpMeta) {
1138
+ continue;
1139
+ } // Needs to stay for index loop to avoid throwIfClosureRequired
1140
+
1141
+
1142
+ for (let j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) {
1143
+ qp = qpMeta.qps[j];
1144
+ assert('expected qp', qp);
1145
+ presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName || qp.urlKey in queryParams && qp.urlKey;
1146
+ assert(`You passed the \`${presentProp}\` query parameter during a transition into ${qp.route.routeName}, please update to ${qp.urlKey}`, function () {
1147
+ if (qp.urlKey === presentProp || qp.scopedPropertyName === presentProp) {
1148
+ return true;
1149
+ }
1150
+
1151
+ if (_fromRouterService && presentProp !== false && qp.urlKey !== qp.prop) {
1152
+ // assumptions (mainly from current transitionTo_test):
1153
+ // - 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
1154
+ // - when there is no alias: qp.urlKey == qp.prop
1155
+ return false;
1156
+ }
1157
+
1158
+ return true;
1159
+ }());
1160
+
1161
+ if (presentProp) {
1162
+ if (presentProp !== qp.scopedPropertyName) {
1163
+ queryParams[qp.scopedPropertyName] = queryParams[presentProp];
1164
+ delete queryParams[presentProp];
1165
+ }
1166
+ } else {
1167
+ let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, state.params);
1168
+ 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);
1169
+ queryParams[qp.scopedPropertyName] = appCache.lookup(cacheKey, qp.prop, qp.defaultValue);
1170
+ }
1171
+ }
1172
+ }
1173
+ }
1174
+
1175
+ _scheduleLoadingEvent(transition, originRoute) {
1176
+ this._cancelSlowTransitionTimer();
1177
+
1178
+ this._slowTransitionTimer = scheduleOnce('routerTransitions', this, this._handleSlowTransition, transition, originRoute);
1179
+ }
1180
+
1181
+ _handleSlowTransition(transition, originRoute) {
1182
+ if (!this._routerMicrolib.activeTransition) {
1183
+ // Don't fire an event if we've since moved on from
1184
+ // the transition that put us in a loading state.
1185
+ return;
1186
+ }
1187
+
1188
+ let targetState = new RouterState(this, this._routerMicrolib, this._routerMicrolib.activeTransition[STATE_SYMBOL]);
1189
+ this.set('targetState', targetState);
1190
+ transition.trigger(true, 'loading', transition, originRoute);
1191
+ }
1192
+
1193
+ _cancelSlowTransitionTimer() {
1194
+ if (this._slowTransitionTimer) {
1195
+ cancel(this._slowTransitionTimer);
1196
+ }
1197
+
1198
+ this._slowTransitionTimer = null;
1199
+ } // These three helper functions are used to ensure errors aren't
1200
+ // re-raised if they're handled in a route's error action.
1201
+
1202
+
1203
+ _markErrorAsHandled(error) {
1204
+ this._handledErrors.add(error);
1205
+ }
1206
+
1207
+ _isErrorHandled(error) {
1208
+ return this._handledErrors.has(error);
1209
+ }
1210
+
1211
+ _clearHandledError(error) {
1212
+ this._handledErrors.delete(error);
1213
+ }
1214
+
1215
+ _getEngineInstance({
1216
+ name,
1217
+ instanceId,
1218
+ mountPoint
1219
+ }) {
1220
+ let engineInstances = this._engineInstances;
1221
+ let namedInstances = engineInstances[name];
1222
+
1223
+ if (!namedInstances) {
1224
+ namedInstances = Object.create(null);
1225
+ engineInstances[name] = namedInstances;
1226
+ } // We just set these!
1227
+
1228
+
1229
+ assert('has namedInstances', namedInstances);
1230
+ let engineInstance = namedInstances[instanceId];
1231
+
1232
+ if (!engineInstance) {
1233
+ let owner = getOwner(this);
1234
+ assert('Expected router to have EngineInstance as owner', owner instanceof EngineInstance);
1235
+ assert(`You attempted to mount the engine '${name}' in your router map, but the engine can not be found.`, owner.hasRegistration(`engine:${name}`));
1236
+ engineInstance = owner.buildChildEngineInstance(name, {
1237
+ routable: true,
1238
+ mountPoint
1239
+ });
1240
+ engineInstance.boot();
1241
+ namedInstances[instanceId] = engineInstance;
1242
+ }
1243
+
1244
+ return engineInstance;
1245
+ }
1246
+
1247
+ }
1248
+ /*
1249
+ Helper function for iterating over routes in a set of routeInfos that are
1250
+ at or above the given origin route. Example: if `originRoute` === 'foo.bar'
1251
+ and the routeInfos given were for 'foo.bar.baz', then the given callback
1252
+ will be invoked with the routes for 'foo.bar', 'foo', and 'application'
1253
+ individually.
1254
+
1255
+ If the callback returns anything other than `true`, then iteration will stop.
1256
+
1257
+ @private
1258
+ @param {Route} originRoute
1259
+ @param {Array<RouteInfo>} routeInfos
1260
+ @param {Function} callback
1261
+ @return {Void}
1262
+ */
1263
+
1264
+
1265
+ function forEachRouteAbove(routeInfos, callback) {
1266
+ for (let i = routeInfos.length - 1; i >= 0; --i) {
1267
+ let routeInfo = routeInfos[i];
1268
+ assert('has routeInfo', routeInfo);
1269
+ let route = routeInfo.route; // routeInfo.handler being `undefined` generally means either:
1270
+ //
1271
+ // 1. an error occurred during creation of the route in question
1272
+ // 2. the route is across an async boundary (e.g. within an engine)
1273
+ //
1274
+ // In both of these cases, we cannot invoke the callback on that specific
1275
+ // route, because it just doesn't exist...
1276
+
1277
+ if (route === undefined) {
1278
+ continue;
1279
+ }
1280
+
1281
+ if (callback(route, routeInfo) !== true) {
1282
+ return;
1283
+ }
1284
+ }
1285
+ } // These get invoked when an action bubbles above ApplicationRoute
1286
+ // and are not meant to be overridable.
1287
+
1288
+
1289
+ let defaultActionHandlers = {
1290
+ willResolveModel(_routeInfos, transition, originRoute) {
1291
+ this._scheduleLoadingEvent(transition, originRoute);
1292
+ },
1293
+
1294
+ // Attempt to find an appropriate error route or substate to enter.
1295
+ error(routeInfos, error, transition) {
1296
+ let router = this;
1297
+ let routeInfoWithError = routeInfos[routeInfos.length - 1];
1298
+ forEachRouteAbove(routeInfos, (route, routeInfo) => {
1299
+ // We don't check the leaf most routeInfo since that would
1300
+ // technically be below where we're at in the route hierarchy.
1301
+ if (routeInfo !== routeInfoWithError) {
1302
+ // Check for the existence of an 'error' route.
1303
+ let errorRouteName = findRouteStateName(route, 'error');
1304
+
1305
+ if (errorRouteName) {
1306
+ router._markErrorAsHandled(error);
1307
+
1308
+ router.intermediateTransitionTo(errorRouteName, error);
1309
+ return false;
1310
+ }
1311
+ } // Check for an 'error' substate route
1312
+
1313
+
1314
+ let errorSubstateName = findRouteSubstateName(route, 'error');
1315
+
1316
+ if (errorSubstateName) {
1317
+ router._markErrorAsHandled(error);
1318
+
1319
+ router.intermediateTransitionTo(errorSubstateName, error);
1320
+ return false;
1321
+ }
1322
+
1323
+ return true;
1324
+ });
1325
+ logError(error, `Error while processing route: ${transition.targetName}`);
1326
+ },
1327
+
1328
+ // Attempt to find an appropriate loading route or substate to enter.
1329
+ loading(routeInfos, transition) {
1330
+ let router = this;
1331
+ let routeInfoWithSlowLoading = routeInfos[routeInfos.length - 1];
1332
+ forEachRouteAbove(routeInfos, (route, routeInfo) => {
1333
+ // We don't check the leaf most routeInfos since that would
1334
+ // technically be below where we're at in the route hierarchy.
1335
+ if (routeInfo !== routeInfoWithSlowLoading) {
1336
+ // Check for the existence of a 'loading' route.
1337
+ let loadingRouteName = findRouteStateName(route, 'loading');
1338
+
1339
+ if (loadingRouteName) {
1340
+ router.intermediateTransitionTo(loadingRouteName);
1341
+ return false;
1342
+ }
1343
+ } // Check for loading substate
1344
+
1345
+
1346
+ let loadingSubstateName = findRouteSubstateName(route, 'loading');
1347
+
1348
+ if (loadingSubstateName) {
1349
+ router.intermediateTransitionTo(loadingSubstateName);
1350
+ return false;
1351
+ } // Don't bubble above pivot route.
1352
+
1353
+
1354
+ return transition.pivotHandler !== route;
1355
+ });
1356
+ }
1357
+
1358
+ };
1359
+
1360
+ function logError(_error, initialMessage) {
1361
+ let errorArgs = [];
1362
+ let error;
1363
+
1364
+ if (_error && typeof _error === 'object' && typeof _error.errorThrown === 'object') {
1365
+ error = _error.errorThrown;
1366
+ } else {
1367
+ error = _error;
1368
+ }
1369
+
1370
+ if (initialMessage) {
1371
+ errorArgs.push(initialMessage);
1372
+ }
1373
+
1374
+ if (error) {
1375
+ if (error.message) {
1376
+ errorArgs.push(error.message);
1377
+ }
1378
+
1379
+ if (error.stack) {
1380
+ errorArgs.push(error.stack);
1381
+ }
1382
+
1383
+ if (typeof error === 'string') {
1384
+ errorArgs.push(error);
1385
+ }
1386
+ }
1387
+
1388
+ console.error(...errorArgs); //eslint-disable-line no-console
1389
+ }
1390
+ /**
1391
+ Finds the name of the substate route if it exists for the given route. A
1392
+ substate route is of the form `route_state`, such as `foo_loading`.
1393
+
1394
+ @private
1395
+ @param {Route} route
1396
+ @param {String} state
1397
+ @return {String}
1398
+ */
1399
+
1400
+
1401
+ function findRouteSubstateName(route, state) {
1402
+ let owner = getOwner(route);
1403
+ assert('Route is unexpectedly missing an owner', owner);
1404
+ let {
1405
+ routeName,
1406
+ fullRouteName,
1407
+ _router: router
1408
+ } = route;
1409
+ let substateName = `${routeName}_${state}`;
1410
+ let substateNameFull = `${fullRouteName}_${state}`;
1411
+ return routeHasBeenDefined(owner, router, substateName, substateNameFull) ? substateNameFull : '';
1412
+ }
1413
+ /**
1414
+ Finds the name of the state route if it exists for the given route. A state
1415
+ route is of the form `route.state`, such as `foo.loading`. Properly Handles
1416
+ `application` named routes.
1417
+
1418
+ @private
1419
+ @param {Route} route
1420
+ @param {String} state
1421
+ @return {String}
1422
+ */
1423
+
1424
+
1425
+ function findRouteStateName(route, state) {
1426
+ let owner = getOwner(route);
1427
+ assert('Route is unexpectedly missing an owner', owner);
1428
+ let {
1429
+ routeName,
1430
+ fullRouteName,
1431
+ _router: router
1432
+ } = route;
1433
+ let stateName = routeName === 'application' ? state : `${routeName}.${state}`;
1434
+ let stateNameFull = fullRouteName === 'application' ? state : `${fullRouteName}.${state}`;
1435
+ return routeHasBeenDefined(owner, router, stateName, stateNameFull) ? stateNameFull : '';
1436
+ }
1437
+ /**
1438
+ Determines whether or not a route has been defined by checking that the route
1439
+ is in the Router's map and the owner has a registration for that route.
1440
+
1441
+ @private
1442
+ @param {Owner} owner
1443
+ @param {Router} router
1444
+ @param {String} localName
1445
+ @param {String} fullName
1446
+ @return {Boolean}
1447
+ */
1448
+
1449
+
1450
+ function routeHasBeenDefined(owner, router, localName, fullName) {
1451
+ let routerHasRoute = router.hasRoute(fullName);
1452
+ let ownerHasRoute = owner.hasRegistration(`template:${localName}`) || owner.hasRegistration(`route:${localName}`);
1453
+ return routerHasRoute && ownerHasRoute;
1454
+ }
1455
+
1456
+ export function triggerEvent(routeInfos, ignoreFailure, name, args) {
1457
+ if (!routeInfos) {
1458
+ if (ignoreFailure) {
1459
+ return;
1460
+ } // TODO: update?
1461
+
1462
+
1463
+ throw new EmberError(`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.`);
1464
+ }
1465
+
1466
+ let eventWasHandled = false;
1467
+ let routeInfo, handler, actionHandler;
1468
+
1469
+ for (let i = routeInfos.length - 1; i >= 0; i--) {
1470
+ routeInfo = routeInfos[i];
1471
+ assert('[BUG] Missing routeInfo', routeInfo);
1472
+ handler = routeInfo.route;
1473
+ actionHandler = handler && handler.actions && handler.actions[name];
1474
+
1475
+ if (actionHandler) {
1476
+ if (actionHandler.apply(handler, args) === true) {
1477
+ eventWasHandled = true;
1478
+ } else {
1479
+ // Should only hit here if a non-bubbling error action is triggered on a route.
1480
+ if (name === 'error') {
1481
+ assert('[BUG] Missing handler', handler);
1482
+
1483
+ handler._router._markErrorAsHandled(args[0]);
1484
+ }
1485
+
1486
+ return;
1487
+ }
1488
+ }
1489
+ }
1490
+
1491
+ let defaultHandler = defaultActionHandlers[name];
1492
+
1493
+ if (defaultHandler) {
1494
+ defaultHandler.call(this, routeInfos, ...args);
1495
+ return;
1496
+ }
1497
+
1498
+ if (!eventWasHandled && !ignoreFailure) {
1499
+ throw new EmberError(`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.`);
1500
+ }
1501
+ }
1502
+
1503
+ function calculatePostTransitionState(emberRouter, leafRouteName, contexts) {
1504
+ let state = emberRouter._routerMicrolib.applyIntent(leafRouteName, contexts);
1505
+
1506
+ let {
1507
+ routeInfos,
1508
+ params
1509
+ } = state;
1510
+
1511
+ for (let routeInfo of routeInfos) {
1512
+ // If the routeInfo is not resolved, we serialize the context into params
1513
+ if (!routeInfo.isResolved) {
1514
+ params[routeInfo.name] = routeInfo.serialize(routeInfo.context);
1515
+ } else {
1516
+ params[routeInfo.name] = routeInfo.params;
1517
+ }
1518
+ }
1519
+
1520
+ return state;
1521
+ }
1522
+
1523
+ function updatePaths(router) {
1524
+ let infos = router._routerMicrolib.currentRouteInfos;
1525
+
1526
+ if (infos.length === 0) {
1527
+ return;
1528
+ }
1529
+
1530
+ let path = EmberRouter._routePath(infos);
1531
+
1532
+ let info = infos[infos.length - 1];
1533
+ assert('expected info', info);
1534
+ let currentRouteName = info.name;
1535
+ let location = router.location;
1536
+ assert('expected location to not be a string', typeof location !== 'string');
1537
+ let currentURL = location.getURL();
1538
+ set(router, 'currentPath', path);
1539
+ set(router, 'currentRouteName', currentRouteName);
1540
+ set(router, 'currentURL', currentURL);
1541
+ }
1542
+
1543
+ function didBeginTransition(transition, router) {
1544
+ let routerState = new RouterState(router, router._routerMicrolib, transition[STATE_SYMBOL]);
1545
+
1546
+ if (!router.currentState) {
1547
+ router.set('currentState', routerState);
1548
+ }
1549
+
1550
+ router.set('targetState', routerState);
1551
+ transition.promise = transition.catch(error => {
1552
+ if (router._isErrorHandled(error)) {
1553
+ router._clearHandledError(error);
1554
+ } else {
1555
+ throw error;
1556
+ }
1557
+ }, 'Transition Error');
1558
+ }
1559
+
1560
+ function forEachQueryParam(router, routeInfos, queryParams, callback) {
1561
+ let qpCache = router._queryParamsFor(routeInfos);
1562
+
1563
+ for (let key in queryParams) {
1564
+ if (!Object.prototype.hasOwnProperty.call(queryParams, key)) {
1565
+ continue;
1566
+ }
1567
+
1568
+ let value = queryParams[key];
1569
+ let qp = qpCache.map[key];
1570
+ callback(key, value, qp);
1571
+ }
1572
+ }
1573
+
1574
+ function findLiveRoute(liveRoutes, name) {
1575
+ if (!liveRoutes) {
1576
+ return;
1577
+ }
1578
+
1579
+ let stack = [liveRoutes];
1580
+
1581
+ while (stack.length > 0) {
1582
+ let test = stack.shift();
1583
+
1584
+ if (test.render.name === name) {
1585
+ return test;
1586
+ }
1587
+
1588
+ let outlets = test.outlets;
1589
+
1590
+ for (let outletName in outlets) {
1591
+ stack.push(outlets[outletName]);
1592
+ }
1593
+ }
1594
+
1595
+ return;
1596
+ }
1597
+
1598
+ function appendLiveRoute(liveRoutes, defaultParentState, renderOptions) {
1599
+ let ownState = {
1600
+ render: renderOptions,
1601
+ outlets: Object.create(null),
1602
+ wasUsed: false
1603
+ };
1604
+ let target;
1605
+
1606
+ if (renderOptions.into) {
1607
+ target = findLiveRoute(liveRoutes, renderOptions.into);
1608
+ } else {
1609
+ target = defaultParentState;
1610
+ }
1611
+
1612
+ if (target) {
1613
+ set(target.outlets, renderOptions.outlet, ownState);
1614
+ } else {
1615
+ liveRoutes = ownState;
1616
+ }
1617
+
1618
+ return {
1619
+ liveRoutes,
1620
+ ownState
1621
+ };
1622
+ }
1623
+
1624
+ function representEmptyRoute(liveRoutes, defaultParentState, {
1625
+ routeName
1626
+ }) {
1627
+ // the route didn't render anything
1628
+ let alreadyAppended = findLiveRoute(liveRoutes, routeName);
1629
+
1630
+ if (alreadyAppended) {
1631
+ // But some other route has already rendered our default
1632
+ // template, so that becomes the default target for any
1633
+ // children we may have.
1634
+ return alreadyAppended;
1635
+ } else {
1636
+ // Create an entry to represent our default template name,
1637
+ // just so other routes can target it and inherit its place
1638
+ // in the outlet hierarchy.
1639
+ defaultParentState.outlets['main'] = {
1640
+ render: {
1641
+ name: routeName,
1642
+ outlet: 'main'
1643
+ },
1644
+ outlets: {}
1645
+ };
1646
+ return defaultParentState;
1647
+ }
1648
+ }
1649
+
1650
+ EmberRouter.reopen({
1651
+ didTransition: defaultDidTransition,
1652
+ willTransition: defaultWillTransition,
1653
+ rootURL: '/',
1654
+ location: 'hash',
1655
+ // FIXME: Does this need to be overrideable via extend?
1656
+ url: computed(function () {
1657
+ let location = get(this, 'location');
1658
+
1659
+ if (typeof location === 'string') {
1660
+ return undefined;
1661
+ }
1662
+
1663
+ return location.getURL();
1664
+ })
1665
+ });
1666
+ export default EmberRouter;