kms 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/kms/application.js +1 -0
  3. data/app/assets/javascripts/kms/application/controllers/assets_controller.coffee.erb +14 -4
  4. data/app/assets/javascripts/kms/application/controllers/pages_controller.coffee.erb +12 -2
  5. data/app/assets/javascripts/kms/application/controllers/snippets_controller.coffee.erb +13 -3
  6. data/app/assets/javascripts/kms/application/controllers/templates_controller.coffee.erb +13 -3
  7. data/app/assets/javascripts/kms/application/controllers/users_controller.coffee +5 -5
  8. data/app/assets/javascripts/kms/application/module.coffee +6 -2
  9. data/app/assets/javascripts/kms/application/routes.coffee.erb +10 -0
  10. data/app/assets/javascripts/templates/assets/edit.html.slim +2 -1
  11. data/app/assets/javascripts/templates/assets/form.html.slim +1 -1
  12. data/app/assets/javascripts/templates/pages/edit.html.slim +1 -0
  13. data/app/assets/javascripts/templates/shared/hotkey_notification.html.slim +6 -0
  14. data/app/assets/javascripts/templates/snippets/edit.html.slim +1 -0
  15. data/app/assets/javascripts/templates/templates/edit.html.slim +1 -0
  16. data/app/assets/javascripts/templates/users/edit.html.slim +5 -0
  17. data/app/assets/javascripts/templates/users/form.html.slim +3 -2
  18. data/app/assets/javascripts/templates/users/index.html.slim +2 -1
  19. data/app/assets/stylesheets/kms/custom.css.scss +10 -0
  20. data/app/controllers/kms/assets_controller.rb +6 -3
  21. data/app/controllers/kms/users_controller.rb +14 -0
  22. data/app/services/kms/resource_service.rb +3 -1
  23. data/app/views/layouts/kms/kms.html.erb +1 -1
  24. data/config/initializers/devise.rb +9 -0
  25. data/config/locales/en.yml +12 -0
  26. data/config/locales/ru.yml +12 -0
  27. data/config/routes.rb +1 -1
  28. data/lib/kms/engine.rb +1 -1
  29. data/lib/kms/version.rb +1 -1
  30. data/spec/controllers/kms/assets_controller_spec.rb +28 -10
  31. data/spec/controllers/kms/users_controller_spec.rb +23 -0
  32. data/spec/internal/config/routes.rb +1 -1
  33. data/spec/internal/log/test.log +0 -105823
  34. data/vendor/assets/bower.json +5 -4
  35. data/vendor/assets/bower_components/angular-cookies/angular-cookies.js +22 -18
  36. data/vendor/assets/bower_components/angular-cookies/angular-cookies.min.js +4 -4
  37. data/vendor/assets/bower_components/angular-cookies/angular-cookies.min.js.map +2 -2
  38. data/vendor/assets/bower_components/angular-cookies/bower.json +2 -2
  39. data/vendor/assets/bower_components/angular-cookies/package.json +1 -1
  40. data/vendor/assets/bower_components/angular-hotkeys/Gruntfile.js +118 -0
  41. data/vendor/assets/bower_components/angular-hotkeys/LICENSE +20 -0
  42. data/vendor/assets/bower_components/angular-hotkeys/README.md +248 -0
  43. data/vendor/assets/bower_components/angular-hotkeys/bower.json +19 -0
  44. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.css +110 -0
  45. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.js +1661 -0
  46. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.min.css +1 -0
  47. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.min.js +7 -0
  48. data/vendor/assets/bower_components/angular-hotkeys/package.json +45 -0
  49. data/vendor/assets/bower_components/angular-hotkeys/src/hotkeys.css +104 -0
  50. data/vendor/assets/bower_components/angular-hotkeys/src/hotkeys.js +633 -0
  51. data/vendor/assets/bower_components/angular-loading-bar/CHANGELOG.md +33 -0
  52. data/vendor/assets/bower_components/angular-loading-bar/CONTRIBUTING.md +17 -0
  53. data/vendor/assets/bower_components/angular-loading-bar/Gruntfile.js +9 -1
  54. data/vendor/assets/bower_components/angular-loading-bar/ISSUE_TEMPLATE.md +14 -0
  55. data/vendor/assets/bower_components/angular-loading-bar/PULL_REQUEST_TEMPLATE.md +13 -0
  56. data/vendor/assets/bower_components/angular-loading-bar/README.md +30 -3
  57. data/vendor/assets/bower_components/angular-loading-bar/bower.json +11 -6
  58. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.css +5 -5
  59. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.js +39 -12
  60. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.min.css +1 -8
  61. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.min.js +3 -3
  62. data/vendor/assets/bower_components/angular-loading-bar/index.js +2 -0
  63. data/vendor/assets/bower_components/angular-loading-bar/package.json +12 -15
  64. data/vendor/assets/bower_components/angular-loading-bar/src/loading-bar.css +3 -3
  65. data/vendor/assets/bower_components/angular-loading-bar/src/loading-bar.js +37 -10
  66. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.js +504 -386
  67. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.min.js +13 -12
  68. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.min.js.map +3 -3
  69. data/vendor/assets/bower_components/angular-sanitize/bower.json +2 -2
  70. data/vendor/assets/bower_components/angular-sanitize/package.json +1 -1
  71. data/vendor/assets/bower_components/angular-ui-router/CHANGELOG.md +1410 -0
  72. data/vendor/assets/bower_components/angular-ui-router/CONTRIBUTING.md +64 -16
  73. data/vendor/assets/bower_components/angular-ui-router/DOCS.md +48 -0
  74. data/vendor/assets/bower_components/angular-ui-router/ISSUE_TEMPLATE.md +53 -0
  75. data/vendor/assets/bower_components/angular-ui-router/LICENSE +1 -1
  76. data/vendor/assets/bower_components/angular-ui-router/README.md +24 -211
  77. data/vendor/assets/bower_components/angular-ui-router/artifacts.json +8 -0
  78. data/vendor/assets/bower_components/angular-ui-router/bower.json +1 -23
  79. data/vendor/assets/bower_components/angular-ui-router/karma.conf.js +105 -0
  80. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.js +9744 -3901
  81. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.js.map +192 -0
  82. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.min.js +9 -4
  83. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.min.js.map +1679 -0
  84. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.js +83 -0
  85. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.js.map +19 -0
  86. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.min.js +8 -0
  87. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.min.js.map +47 -0
  88. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.js +294 -0
  89. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.js.map +17 -0
  90. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.min.js +8 -0
  91. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.min.js.map +102 -0
  92. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.js +2014 -0
  93. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.js.map +70 -0
  94. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.min.js +9 -0
  95. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.min.js.map +541 -0
  96. data/vendor/assets/bower_components/angular-ui-router/rollup.config.js +116 -0
  97. data/vendor/assets/bower_components/angular-ui-router/tslint.json +60 -0
  98. data/vendor/assets/bower_components/angular-ui-router/yarn.lock +4146 -0
  99. data/vendor/assets/bower_components/angular-ui-tree/yarn.lock +4945 -0
  100. data/vendor/assets/bower_components/angular/angular.js +4019 -2449
  101. data/vendor/assets/bower_components/angular/angular.min.js +331 -319
  102. data/vendor/assets/bower_components/angular/angular.min.js.gzip +0 -0
  103. data/vendor/assets/bower_components/angular/angular.min.js.map +3 -3
  104. data/vendor/assets/bower_components/angular/bower.json +1 -1
  105. data/vendor/assets/bower_components/angular/package.json +1 -1
  106. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/LICENSE +21 -0
  107. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/README.md +14 -14
  108. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/bower.json +25 -12
  109. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/development_index.html +59 -52
  110. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/dist/angularjs-dropdown-multiselect.min.js +1 -1
  111. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/index.html +73 -0
  112. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/package.json +19 -7
  113. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/javascripts/pages/home/ExampleCtrl.js +126 -3
  114. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/javascripts/pages/home/home.html +1262 -852
  115. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/stylesheets/stylesheet.css +10 -5
  116. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/src/angularjs-dropdown-multiselect.js +612 -287
  117. metadata +66 -169
  118. data/spec/internal/config/database.yml +0 -7
  119. data/spec/internal/public/uploads/kms/asset/file/1/avatar.jpg +0 -0
  120. data/spec/internal/public/uploads/kms/asset/file/2/avatar.jpg +0 -0
  121. data/spec/internal/public/uploads/kms/asset/file/2/style.css +0 -1
  122. data/spec/internal/public/uploads/kms/asset/file/3/style.css +0 -1
  123. data/spec/internal/public/uploads/kms/asset/file/4/style.css +0 -1
  124. data/spec/internal/public/uploads/tmp/1500976987-41025-0002-0883/style.css +0 -1
  125. data/spec/internal/public/uploads/tmp/1500977082-41195-0002-6495/style.css +0 -1
  126. data/spec/internal/public/uploads/tmp/1500977109-41364-0002-4518/style.css +0 -1
  127. data/spec/internal/public/uploads/tmp/1500977152-41405-0002-2345/style.css +0 -1
  128. data/spec/internal/public/uploads/tmp/1500977327-41694-0002-5448/style.css +0 -1
  129. data/spec/internal/public/uploads/tmp/1500977376-41732-0002-7916/style.css +0 -1
  130. data/spec/internal/public/uploads/tmp/1500977392-41759-0002-7593/style.css +0 -1
  131. data/spec/internal/public/uploads/tmp/1500977410-42259-0002-7527/style.css +0 -1
  132. data/spec/internal/public/uploads/tmp/1500977429-42306-0002-5937/style.css +0 -1
  133. data/spec/internal/public/uploads/tmp/1500977437-42324-0002-5880/style.css +0 -1
  134. data/spec/internal/public/uploads/tmp/1500983228-53594-0002-4559/style.css +0 -1
  135. data/spec/internal/public/uploads/tmp/1500983284-53632-0002-6590/style.css +0 -1
  136. data/spec/internal/public/uploads/tmp/1500983360-53784-0002-7289/style.css +0 -1
  137. data/spec/internal/public/uploads/tmp/1500983469-54321-0002-0386/avatar.jpg +0 -0
  138. data/spec/internal/public/uploads/tmp/1500983469-54321-0004-5691/style.css +0 -1
  139. data/spec/internal/public/uploads/tmp/1500983511-54352-0002-5720/avatar.jpg +0 -0
  140. data/spec/internal/public/uploads/tmp/1500983511-54352-0004-1399/style.css +0 -1
  141. data/spec/internal/public/uploads/tmp/1500983610-54507-0002-4280/avatar.jpg +0 -0
  142. data/spec/internal/public/uploads/tmp/1500983610-54507-0004-9758/style.css +0 -1
  143. data/spec/internal/public/uploads/tmp/1500984466-57012-0002-4146/avatar.jpg +0 -0
  144. data/spec/internal/public/uploads/tmp/1500984466-57012-0004-5895/style.css +0 -1
  145. data/spec/internal/public/uploads/tmp/1500984509-57158-0002-9657/avatar.jpg +0 -0
  146. data/spec/internal/public/uploads/tmp/1500984509-57158-0004-5003/style.css +0 -1
  147. data/spec/internal/public/uploads/tmp/1500984616-57697-0002-7201/avatar.jpg +0 -0
  148. data/spec/internal/public/uploads/tmp/1500984616-57697-0004-6255/style.css +0 -1
  149. data/spec/internal/public/uploads/tmp/1500985257-58947-0002-3629/avatar.jpg +0 -0
  150. data/spec/internal/public/uploads/tmp/1500985257-58947-0004-5338/style.css +0 -1
  151. data/spec/internal/public/uploads/tmp/1500985407-58947-0006-5929/style.css +0 -1
  152. data/spec/internal/public/uploads/tmp/1500985473-59264-0002-0397/avatar.jpg +0 -0
  153. data/spec/internal/public/uploads/tmp/1500985473-59264-0004-6493/style.css +0 -1
  154. data/spec/internal/public/uploads/tmp/1500985475-59264-0007-8674/style.css +0 -1
  155. data/spec/internal/public/uploads/tmp/1500985538-59468-0002-9206/avatar.jpg +0 -0
  156. data/spec/internal/public/uploads/tmp/1500985538-59468-0004-2586/style.css +0 -1
  157. data/spec/internal/public/uploads/tmp/1500985538-59468-0007-6200/style.css +0 -1
  158. data/spec/internal/public/uploads/tmp/1500988358-65877-0002-4528/avatar.jpg +0 -0
  159. data/spec/internal/public/uploads/tmp/1500988358-65877-0004-5904/style.css +0 -1
  160. data/spec/internal/public/uploads/tmp/1500988358-65877-0007-7320/style.css +0 -1
  161. data/spec/internal/public/uploads/tmp/1500988407-65916-0002-3138/avatar.jpg +0 -0
  162. data/spec/internal/public/uploads/tmp/1500988407-65916-0004-5400/style.css +0 -1
  163. data/spec/internal/public/uploads/tmp/1500988407-65916-0007-1655/style.css +0 -1
  164. data/spec/internal/public/uploads/tmp/1500988421-65950-0002-9415/avatar.jpg +0 -0
  165. data/spec/internal/public/uploads/tmp/1500988421-65950-0004-7130/style.css +0 -1
  166. data/spec/internal/public/uploads/tmp/1500988421-65950-0007-9886/style.css +0 -1
  167. data/spec/internal/public/uploads/tmp/1500988435-65981-0002-3228/avatar.jpg +0 -0
  168. data/spec/internal/public/uploads/tmp/1500988435-65981-0004-3682/style.css +0 -1
  169. data/spec/internal/public/uploads/tmp/1500988435-65981-0007-1582/style.css +0 -1
  170. data/spec/internal/public/uploads/tmp/1500988475-66122-0002-9516/avatar.jpg +0 -0
  171. data/spec/internal/public/uploads/tmp/1500988475-66122-0004-5634/style.css +0 -1
  172. data/spec/internal/public/uploads/tmp/1500988530-66122-0007-2272/style.css +0 -1
  173. data/spec/internal/public/uploads/tmp/1500988554-66315-0002-6262/avatar.jpg +0 -0
  174. data/spec/internal/public/uploads/tmp/1500988554-66315-0004-6099/style.css +0 -1
  175. data/spec/internal/public/uploads/tmp/1500988554-66315-0007-1632/style.css +0 -1
  176. data/spec/internal/public/uploads/tmp/1500991751-73722-0002-9937/avatar.jpg +0 -0
  177. data/spec/internal/public/uploads/tmp/1500991751-73722-0004-8034/style.css +0 -1
  178. data/spec/internal/public/uploads/tmp/1500991751-73722-0007-7763/style.css +0 -1
  179. data/spec/internal/public/uploads/tmp/1501233238-34385-0002-3210/avatar.jpg +0 -0
  180. data/spec/internal/public/uploads/tmp/1501233238-34385-0004-5881/style.css +0 -1
  181. data/spec/internal/public/uploads/tmp/1501233238-34385-0007-6280/style.css +0 -1
  182. data/spec/internal/tmp/cache/assets/test/sprockets/v3.0/1XyAFYlYI0pK7WAgjR4PgXV6BgU6huJSviWmHetdCRs.cache +0 -1
  183. data/vendor/assets/bower_components/angular-ui-router/api/angular-ui-router.d.ts +0 -126
  184. data/vendor/assets/bower_components/angular-ui-router/src/common.js +0 -292
  185. data/vendor/assets/bower_components/angular-ui-router/src/resolve.js +0 -252
  186. data/vendor/assets/bower_components/angular-ui-router/src/state.js +0 -1373
  187. data/vendor/assets/bower_components/angular-ui-router/src/stateDirectives.js +0 -268
  188. data/vendor/assets/bower_components/angular-ui-router/src/stateFilters.js +0 -39
  189. data/vendor/assets/bower_components/angular-ui-router/src/templateFactory.js +0 -110
  190. data/vendor/assets/bower_components/angular-ui-router/src/urlMatcherFactory.js +0 -1036
  191. data/vendor/assets/bower_components/angular-ui-router/src/urlRouter.js +0 -413
  192. data/vendor/assets/bower_components/angular-ui-router/src/view.js +0 -71
  193. data/vendor/assets/bower_components/angular-ui-router/src/viewDirective.js +0 -302
  194. data/vendor/assets/bower_components/angular-ui-router/src/viewScroll.js +0 -52
  195. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/index.html +0 -67
  196. data/vendor/assets/bower_components/bootstrap/Gemfile.lock +0 -43
@@ -1,252 +0,0 @@
1
- /**
2
- * @ngdoc object
3
- * @name ui.router.util.$resolve
4
- *
5
- * @requires $q
6
- * @requires $injector
7
- *
8
- * @description
9
- * Manages resolution of (acyclic) graphs of promises.
10
- */
11
- $Resolve.$inject = ['$q', '$injector'];
12
- function $Resolve( $q, $injector) {
13
-
14
- var VISIT_IN_PROGRESS = 1,
15
- VISIT_DONE = 2,
16
- NOTHING = {},
17
- NO_DEPENDENCIES = [],
18
- NO_LOCALS = NOTHING,
19
- NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
20
-
21
-
22
- /**
23
- * @ngdoc function
24
- * @name ui.router.util.$resolve#study
25
- * @methodOf ui.router.util.$resolve
26
- *
27
- * @description
28
- * Studies a set of invocables that are likely to be used multiple times.
29
- * <pre>
30
- * $resolve.study(invocables)(locals, parent, self)
31
- * </pre>
32
- * is equivalent to
33
- * <pre>
34
- * $resolve.resolve(invocables, locals, parent, self)
35
- * </pre>
36
- * but the former is more efficient (in fact `resolve` just calls `study`
37
- * internally).
38
- *
39
- * @param {object} invocables Invocable objects
40
- * @return {function} a function to pass in locals, parent and self
41
- */
42
- this.study = function (invocables) {
43
- if (!isObject(invocables)) throw new Error("'invocables' must be an object");
44
- var invocableKeys = objectKeys(invocables || {});
45
-
46
- // Perform a topological sort of invocables to build an ordered plan
47
- var plan = [], cycle = [], visited = {};
48
- function visit(value, key) {
49
- if (visited[key] === VISIT_DONE) return;
50
-
51
- cycle.push(key);
52
- if (visited[key] === VISIT_IN_PROGRESS) {
53
- cycle.splice(0, indexOf(cycle, key));
54
- throw new Error("Cyclic dependency: " + cycle.join(" -> "));
55
- }
56
- visited[key] = VISIT_IN_PROGRESS;
57
-
58
- if (isString(value)) {
59
- plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
60
- } else {
61
- var params = $injector.annotate(value);
62
- forEach(params, function (param) {
63
- if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
64
- });
65
- plan.push(key, value, params);
66
- }
67
-
68
- cycle.pop();
69
- visited[key] = VISIT_DONE;
70
- }
71
- forEach(invocables, visit);
72
- invocables = cycle = visited = null; // plan is all that's required
73
-
74
- function isResolve(value) {
75
- return isObject(value) && value.then && value.$$promises;
76
- }
77
-
78
- return function (locals, parent, self) {
79
- if (isResolve(locals) && self === undefined) {
80
- self = parent; parent = locals; locals = null;
81
- }
82
- if (!locals) locals = NO_LOCALS;
83
- else if (!isObject(locals)) {
84
- throw new Error("'locals' must be an object");
85
- }
86
- if (!parent) parent = NO_PARENT;
87
- else if (!isResolve(parent)) {
88
- throw new Error("'parent' must be a promise returned by $resolve.resolve()");
89
- }
90
-
91
- // To complete the overall resolution, we have to wait for the parent
92
- // promise and for the promise for each invokable in our plan.
93
- var resolution = $q.defer(),
94
- result = resolution.promise,
95
- promises = result.$$promises = {},
96
- values = extend({}, locals),
97
- wait = 1 + plan.length/3,
98
- merged = false;
99
-
100
- function done() {
101
- // Merge parent values we haven't got yet and publish our own $$values
102
- if (!--wait) {
103
- if (!merged) merge(values, parent.$$values);
104
- result.$$values = values;
105
- result.$$promises = result.$$promises || true; // keep for isResolve()
106
- delete result.$$inheritedValues;
107
- resolution.resolve(values);
108
- }
109
- }
110
-
111
- function fail(reason) {
112
- result.$$failure = reason;
113
- resolution.reject(reason);
114
- }
115
-
116
- // Short-circuit if parent has already failed
117
- if (isDefined(parent.$$failure)) {
118
- fail(parent.$$failure);
119
- return result;
120
- }
121
-
122
- if (parent.$$inheritedValues) {
123
- merge(values, omit(parent.$$inheritedValues, invocableKeys));
124
- }
125
-
126
- // Merge parent values if the parent has already resolved, or merge
127
- // parent promises and wait if the parent resolve is still in progress.
128
- extend(promises, parent.$$promises);
129
- if (parent.$$values) {
130
- merged = merge(values, omit(parent.$$values, invocableKeys));
131
- result.$$inheritedValues = omit(parent.$$values, invocableKeys);
132
- done();
133
- } else {
134
- if (parent.$$inheritedValues) {
135
- result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);
136
- }
137
- parent.then(done, fail);
138
- }
139
-
140
- // Process each invocable in the plan, but ignore any where a local of the same name exists.
141
- for (var i=0, ii=plan.length; i<ii; i+=3) {
142
- if (locals.hasOwnProperty(plan[i])) done();
143
- else invoke(plan[i], plan[i+1], plan[i+2]);
144
- }
145
-
146
- function invoke(key, invocable, params) {
147
- // Create a deferred for this invocation. Failures will propagate to the resolution as well.
148
- var invocation = $q.defer(), waitParams = 0;
149
- function onfailure(reason) {
150
- invocation.reject(reason);
151
- fail(reason);
152
- }
153
- // Wait for any parameter that we have a promise for (either from parent or from this
154
- // resolve; in that case study() will have made sure it's ordered before us in the plan).
155
- forEach(params, function (dep) {
156
- if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
157
- waitParams++;
158
- promises[dep].then(function (result) {
159
- values[dep] = result;
160
- if (!(--waitParams)) proceed();
161
- }, onfailure);
162
- }
163
- });
164
- if (!waitParams) proceed();
165
- function proceed() {
166
- if (isDefined(result.$$failure)) return;
167
- try {
168
- invocation.resolve($injector.invoke(invocable, self, values));
169
- invocation.promise.then(function (result) {
170
- values[key] = result;
171
- done();
172
- }, onfailure);
173
- } catch (e) {
174
- onfailure(e);
175
- }
176
- }
177
- // Publish promise synchronously; invocations further down in the plan may depend on it.
178
- promises[key] = invocation.promise;
179
- }
180
-
181
- return result;
182
- };
183
- };
184
-
185
- /**
186
- * @ngdoc function
187
- * @name ui.router.util.$resolve#resolve
188
- * @methodOf ui.router.util.$resolve
189
- *
190
- * @description
191
- * Resolves a set of invocables. An invocable is a function to be invoked via
192
- * `$injector.invoke()`, and can have an arbitrary number of dependencies.
193
- * An invocable can either return a value directly,
194
- * or a `$q` promise. If a promise is returned it will be resolved and the
195
- * resulting value will be used instead. Dependencies of invocables are resolved
196
- * (in this order of precedence)
197
- *
198
- * - from the specified `locals`
199
- * - from another invocable that is part of this `$resolve` call
200
- * - from an invocable that is inherited from a `parent` call to `$resolve`
201
- * (or recursively
202
- * - from any ancestor `$resolve` of that parent).
203
- *
204
- * The return value of `$resolve` is a promise for an object that contains
205
- * (in this order of precedence)
206
- *
207
- * - any `locals` (if specified)
208
- * - the resolved return values of all injectables
209
- * - any values inherited from a `parent` call to `$resolve` (if specified)
210
- *
211
- * The promise will resolve after the `parent` promise (if any) and all promises
212
- * returned by injectables have been resolved. If any invocable
213
- * (or `$injector.invoke`) throws an exception, or if a promise returned by an
214
- * invocable is rejected, the `$resolve` promise is immediately rejected with the
215
- * same error. A rejection of a `parent` promise (if specified) will likewise be
216
- * propagated immediately. Once the `$resolve` promise has been rejected, no
217
- * further invocables will be called.
218
- *
219
- * Cyclic dependencies between invocables are not permitted and will caues `$resolve`
220
- * to throw an error. As a special case, an injectable can depend on a parameter
221
- * with the same name as the injectable, which will be fulfilled from the `parent`
222
- * injectable of the same name. This allows inherited values to be decorated.
223
- * Note that in this case any other injectable in the same `$resolve` with the same
224
- * dependency would see the decorated value, not the inherited value.
225
- *
226
- * Note that missing dependencies -- unlike cyclic dependencies -- will cause an
227
- * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous)
228
- * exception.
229
- *
230
- * Invocables are invoked eagerly as soon as all dependencies are available.
231
- * This is true even for dependencies inherited from a `parent` call to `$resolve`.
232
- *
233
- * As a special case, an invocable can be a string, in which case it is taken to
234
- * be a service name to be passed to `$injector.get()`. This is supported primarily
235
- * for backwards-compatibility with the `resolve` property of `$routeProvider`
236
- * routes.
237
- *
238
- * @param {object} invocables functions to invoke or
239
- * `$injector` services to fetch.
240
- * @param {object} locals values to make available to the injectables
241
- * @param {object} parent a promise returned by another call to `$resolve`.
242
- * @param {object} self the `this` for the invoked methods
243
- * @return {object} Promise for an object that contains the resolved return value
244
- * of all invocables, as well as any inherited and local values.
245
- */
246
- this.resolve = function (invocables, locals, parent, self) {
247
- return this.study(invocables)(locals, parent, self);
248
- };
249
- }
250
-
251
- angular.module('ui.router.util').service('$resolve', $Resolve);
252
-
@@ -1,1373 +0,0 @@
1
- /**
2
- * @ngdoc object
3
- * @name ui.router.state.$stateProvider
4
- *
5
- * @requires ui.router.router.$urlRouterProvider
6
- * @requires ui.router.util.$urlMatcherFactoryProvider
7
- *
8
- * @description
9
- * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
10
- * on state.
11
- *
12
- * A state corresponds to a "place" in the application in terms of the overall UI and
13
- * navigation. A state describes (via the controller / template / view properties) what
14
- * the UI looks like and does at that place.
15
- *
16
- * States often have things in common, and the primary way of factoring out these
17
- * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
18
- * nested states.
19
- *
20
- * The `$stateProvider` provides interfaces to declare these states for your app.
21
- */
22
- $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
23
- function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
24
-
25
- var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
26
-
27
- // Builds state properties from definition passed to registerState()
28
- var stateBuilder = {
29
-
30
- // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
31
- // state.children = [];
32
- // if (parent) parent.children.push(state);
33
- parent: function(state) {
34
- if (isDefined(state.parent) && state.parent) return findState(state.parent);
35
- // regex matches any valid composite state name
36
- // would match "contact.list" but not "contacts"
37
- var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
38
- return compositeName ? findState(compositeName[1]) : root;
39
- },
40
-
41
- // inherit 'data' from parent and override by own values (if any)
42
- data: function(state) {
43
- if (state.parent && state.parent.data) {
44
- state.data = state.self.data = extend({}, state.parent.data, state.data);
45
- }
46
- return state.data;
47
- },
48
-
49
- // Build a URLMatcher if necessary, either via a relative or absolute URL
50
- url: function(state) {
51
- var url = state.url, config = { params: state.params || {} };
52
-
53
- if (isString(url)) {
54
- if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
55
- return (state.parent.navigable || root).url.concat(url, config);
56
- }
57
-
58
- if (!url || $urlMatcherFactory.isMatcher(url)) return url;
59
- throw new Error("Invalid url '" + url + "' in state '" + state + "'");
60
- },
61
-
62
- // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
63
- navigable: function(state) {
64
- return state.url ? state : (state.parent ? state.parent.navigable : null);
65
- },
66
-
67
- // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params
68
- ownParams: function(state) {
69
- var params = state.url && state.url.params || new $$UMFP.ParamSet();
70
- forEach(state.params || {}, function(config, id) {
71
- if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
72
- });
73
- return params;
74
- },
75
-
76
- // Derive parameters for this state and ensure they're a super-set of parent's parameters
77
- params: function(state) {
78
- return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet();
79
- },
80
-
81
- // If there is no explicit multi-view configuration, make one up so we don't have
82
- // to handle both cases in the view directive later. Note that having an explicit
83
- // 'views' property will mean the default unnamed view properties are ignored. This
84
- // is also a good time to resolve view names to absolute names, so everything is a
85
- // straight lookup at link time.
86
- views: function(state) {
87
- var views = {};
88
-
89
- forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
90
- if (name.indexOf('@') < 0) name += '@' + state.parent.name;
91
- views[name] = view;
92
- });
93
- return views;
94
- },
95
-
96
- // Keep a full path from the root down to this state as this is needed for state activation.
97
- path: function(state) {
98
- return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
99
- },
100
-
101
- // Speed up $state.contains() as it's used a lot
102
- includes: function(state) {
103
- var includes = state.parent ? extend({}, state.parent.includes) : {};
104
- includes[state.name] = true;
105
- return includes;
106
- },
107
-
108
- $delegates: {}
109
- };
110
-
111
- function isRelative(stateName) {
112
- return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
113
- }
114
-
115
- function findState(stateOrName, base) {
116
- if (!stateOrName) return undefined;
117
-
118
- var isStr = isString(stateOrName),
119
- name = isStr ? stateOrName : stateOrName.name,
120
- path = isRelative(name);
121
-
122
- if (path) {
123
- if (!base) throw new Error("No reference point given for path '" + name + "'");
124
- base = findState(base);
125
-
126
- var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
127
-
128
- for (; i < pathLength; i++) {
129
- if (rel[i] === "" && i === 0) {
130
- current = base;
131
- continue;
132
- }
133
- if (rel[i] === "^") {
134
- if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
135
- current = current.parent;
136
- continue;
137
- }
138
- break;
139
- }
140
- rel = rel.slice(i).join(".");
141
- name = current.name + (current.name && rel ? "." : "") + rel;
142
- }
143
- var state = states[name];
144
-
145
- if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
146
- return state;
147
- }
148
- return undefined;
149
- }
150
-
151
- function queueState(parentName, state) {
152
- if (!queue[parentName]) {
153
- queue[parentName] = [];
154
- }
155
- queue[parentName].push(state);
156
- }
157
-
158
- function flushQueuedChildren(parentName) {
159
- var queued = queue[parentName] || [];
160
- while(queued.length) {
161
- registerState(queued.shift());
162
- }
163
- }
164
-
165
- function registerState(state) {
166
- // Wrap a new object around the state so we can store our private details easily.
167
- state = inherit(state, {
168
- self: state,
169
- resolve: state.resolve || {},
170
- toString: function() { return this.name; }
171
- });
172
-
173
- var name = state.name;
174
- if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
175
- if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined");
176
-
177
- // Get parent name
178
- var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
179
- : (isString(state.parent)) ? state.parent
180
- : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name
181
- : '';
182
-
183
- // If parent is not registered yet, add state to queue and register later
184
- if (parentName && !states[parentName]) {
185
- return queueState(parentName, state.self);
186
- }
187
-
188
- for (var key in stateBuilder) {
189
- if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
190
- }
191
- states[name] = state;
192
-
193
- // Register the state in the global state list and with $urlRouter if necessary.
194
- if (!state[abstractKey] && state.url) {
195
- $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
196
- if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
197
- $state.transitionTo(state, $match, { inherit: true, location: false });
198
- }
199
- }]);
200
- }
201
-
202
- // Register any queued children
203
- flushQueuedChildren(name);
204
-
205
- return state;
206
- }
207
-
208
- // Checks text to see if it looks like a glob.
209
- function isGlob (text) {
210
- return text.indexOf('*') > -1;
211
- }
212
-
213
- // Returns true if glob matches current $state name.
214
- function doesStateMatchGlob (glob) {
215
- var globSegments = glob.split('.'),
216
- segments = $state.$current.name.split('.');
217
-
218
- //match greedy starts
219
- if (globSegments[0] === '**') {
220
- segments = segments.slice(indexOf(segments, globSegments[1]));
221
- segments.unshift('**');
222
- }
223
- //match greedy ends
224
- if (globSegments[globSegments.length - 1] === '**') {
225
- segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
226
- segments.push('**');
227
- }
228
-
229
- if (globSegments.length != segments.length) {
230
- return false;
231
- }
232
-
233
- //match single stars
234
- for (var i = 0, l = globSegments.length; i < l; i++) {
235
- if (globSegments[i] === '*') {
236
- segments[i] = '*';
237
- }
238
- }
239
-
240
- return segments.join('') === globSegments.join('');
241
- }
242
-
243
-
244
- // Implicit root state that is always active
245
- root = registerState({
246
- name: '',
247
- url: '^',
248
- views: null,
249
- 'abstract': true
250
- });
251
- root.navigable = null;
252
-
253
-
254
- /**
255
- * @ngdoc function
256
- * @name ui.router.state.$stateProvider#decorator
257
- * @methodOf ui.router.state.$stateProvider
258
- *
259
- * @description
260
- * Allows you to extend (carefully) or override (at your own peril) the
261
- * `stateBuilder` object used internally by `$stateProvider`. This can be used
262
- * to add custom functionality to ui-router, for example inferring templateUrl
263
- * based on the state name.
264
- *
265
- * When passing only a name, it returns the current (original or decorated) builder
266
- * function that matches `name`.
267
- *
268
- * The builder functions that can be decorated are listed below. Though not all
269
- * necessarily have a good use case for decoration, that is up to you to decide.
270
- *
271
- * In addition, users can attach custom decorators, which will generate new
272
- * properties within the state's internal definition. There is currently no clear
273
- * use-case for this beyond accessing internal states (i.e. $state.$current),
274
- * however, expect this to become increasingly relevant as we introduce additional
275
- * meta-programming features.
276
- *
277
- * **Warning**: Decorators should not be interdependent because the order of
278
- * execution of the builder functions in non-deterministic. Builder functions
279
- * should only be dependent on the state definition object and super function.
280
- *
281
- *
282
- * Existing builder functions and current return values:
283
- *
284
- * - **parent** `{object}` - returns the parent state object.
285
- * - **data** `{object}` - returns state data, including any inherited data that is not
286
- * overridden by own values (if any).
287
- * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
288
- * or `null`.
289
- * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is
290
- * navigable).
291
- * - **params** `{object}` - returns an array of state params that are ensured to
292
- * be a super-set of parent's params.
293
- * - **views** `{object}` - returns a views object where each key is an absolute view
294
- * name (i.e. "viewName@stateName") and each value is the config object
295
- * (template, controller) for the view. Even when you don't use the views object
296
- * explicitly on a state config, one is still created for you internally.
297
- * So by decorating this builder function you have access to decorating template
298
- * and controller properties.
299
- * - **ownParams** `{object}` - returns an array of params that belong to the state,
300
- * not including any params defined by ancestor states.
301
- * - **path** `{string}` - returns the full path from the root down to this state.
302
- * Needed for state activation.
303
- * - **includes** `{object}` - returns an object that includes every state that
304
- * would pass a `$state.includes()` test.
305
- *
306
- * @example
307
- * <pre>
308
- * // Override the internal 'views' builder with a function that takes the state
309
- * // definition, and a reference to the internal function being overridden:
310
- * $stateProvider.decorator('views', function (state, parent) {
311
- * var result = {},
312
- * views = parent(state);
313
- *
314
- * angular.forEach(views, function (config, name) {
315
- * var autoName = (state.name + '.' + name).replace('.', '/');
316
- * config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
317
- * result[name] = config;
318
- * });
319
- * return result;
320
- * });
321
- *
322
- * $stateProvider.state('home', {
323
- * views: {
324
- * 'contact.list': { controller: 'ListController' },
325
- * 'contact.item': { controller: 'ItemController' }
326
- * }
327
- * });
328
- *
329
- * // ...
330
- *
331
- * $state.go('home');
332
- * // Auto-populates list and item views with /partials/home/contact/list.html,
333
- * // and /partials/home/contact/item.html, respectively.
334
- * </pre>
335
- *
336
- * @param {string} name The name of the builder function to decorate.
337
- * @param {object} func A function that is responsible for decorating the original
338
- * builder function. The function receives two parameters:
339
- *
340
- * - `{object}` - state - The state config object.
341
- * - `{object}` - super - The original builder function.
342
- *
343
- * @return {object} $stateProvider - $stateProvider instance
344
- */
345
- this.decorator = decorator;
346
- function decorator(name, func) {
347
- /*jshint validthis: true */
348
- if (isString(name) && !isDefined(func)) {
349
- return stateBuilder[name];
350
- }
351
- if (!isFunction(func) || !isString(name)) {
352
- return this;
353
- }
354
- if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
355
- stateBuilder.$delegates[name] = stateBuilder[name];
356
- }
357
- stateBuilder[name] = func;
358
- return this;
359
- }
360
-
361
- /**
362
- * @ngdoc function
363
- * @name ui.router.state.$stateProvider#state
364
- * @methodOf ui.router.state.$stateProvider
365
- *
366
- * @description
367
- * Registers a state configuration under a given state name. The stateConfig object
368
- * has the following acceptable properties.
369
- *
370
- * @param {string} name A unique state name, e.g. "home", "about", "contacts".
371
- * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
372
- * @param {object} stateConfig State configuration object.
373
- * @param {string|function=} stateConfig.template
374
- * <a id='template'></a>
375
- * html template as a string or a function that returns
376
- * an html template as a string which should be used by the uiView directives. This property
377
- * takes precedence over templateUrl.
378
- *
379
- * If `template` is a function, it will be called with the following parameters:
380
- *
381
- * - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
382
- * applying the current state
383
- *
384
- * <pre>template:
385
- * "<h1>inline template definition</h1>" +
386
- * "<div ui-view></div>"</pre>
387
- * <pre>template: function(params) {
388
- * return "<h1>generated template</h1>"; }</pre>
389
- * </div>
390
- *
391
- * @param {string|function=} stateConfig.templateUrl
392
- * <a id='templateUrl'></a>
393
- *
394
- * path or function that returns a path to an html
395
- * template that should be used by uiView.
396
- *
397
- * If `templateUrl` is a function, it will be called with the following parameters:
398
- *
399
- * - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
400
- * applying the current state
401
- *
402
- * <pre>templateUrl: "home.html"</pre>
403
- * <pre>templateUrl: function(params) {
404
- * return myTemplates[params.pageId]; }</pre>
405
- *
406
- * @param {function=} stateConfig.templateProvider
407
- * <a id='templateProvider'></a>
408
- * Provider function that returns HTML content string.
409
- * <pre> templateProvider:
410
- * function(MyTemplateService, params) {
411
- * return MyTemplateService.getTemplate(params.pageId);
412
- * }</pre>
413
- *
414
- * @param {string|function=} stateConfig.controller
415
- * <a id='controller'></a>
416
- *
417
- * Controller fn that should be associated with newly
418
- * related scope or the name of a registered controller if passed as a string.
419
- * Optionally, the ControllerAs may be declared here.
420
- * <pre>controller: "MyRegisteredController"</pre>
421
- * <pre>controller:
422
- * "MyRegisteredController as fooCtrl"}</pre>
423
- * <pre>controller: function($scope, MyService) {
424
- * $scope.data = MyService.getData(); }</pre>
425
- *
426
- * @param {function=} stateConfig.controllerProvider
427
- * <a id='controllerProvider'></a>
428
- *
429
- * Injectable provider function that returns the actual controller or string.
430
- * <pre>controllerProvider:
431
- * function(MyResolveData) {
432
- * if (MyResolveData.foo)
433
- * return "FooCtrl"
434
- * else if (MyResolveData.bar)
435
- * return "BarCtrl";
436
- * else return function($scope) {
437
- * $scope.baz = "Qux";
438
- * }
439
- * }</pre>
440
- *
441
- * @param {string=} stateConfig.controllerAs
442
- * <a id='controllerAs'></a>
443
- *
444
- * A controller alias name. If present the controller will be
445
- * published to scope under the controllerAs name.
446
- * <pre>controllerAs: "myCtrl"</pre>
447
- *
448
- * @param {object=} stateConfig.resolve
449
- * <a id='resolve'></a>
450
- *
451
- * An optional map&lt;string, function&gt; of dependencies which
452
- * should be injected into the controller. If any of these dependencies are promises,
453
- * the router will wait for them all to be resolved before the controller is instantiated.
454
- * If all the promises are resolved successfully, the $stateChangeSuccess event is fired
455
- * and the values of the resolved promises are injected into any controllers that reference them.
456
- * If any of the promises are rejected the $stateChangeError event is fired.
457
- *
458
- * The map object is:
459
- *
460
- * - key - {string}: name of dependency to be injected into controller
461
- * - factory - {string|function}: If string then it is alias for service. Otherwise if function,
462
- * it is injected and return value it treated as dependency. If result is a promise, it is
463
- * resolved before its value is injected into controller.
464
- *
465
- * <pre>resolve: {
466
- * myResolve1:
467
- * function($http, $stateParams) {
468
- * return $http.get("/api/foos/"+stateParams.fooID);
469
- * }
470
- * }</pre>
471
- *
472
- * @param {string=} stateConfig.url
473
- * <a id='url'></a>
474
- *
475
- * A url fragment with optional parameters. When a state is navigated or
476
- * transitioned to, the `$stateParams` service will be populated with any
477
- * parameters that were passed.
478
- *
479
- * examples:
480
- * <pre>url: "/home"
481
- * url: "/users/:userid"
482
- * url: "/books/{bookid:[a-zA-Z_-]}"
483
- * url: "/books/{categoryid:int}"
484
- * url: "/books/{publishername:string}/{categoryid:int}"
485
- * url: "/messages?before&after"
486
- * url: "/messages?{before:date}&{after:date}"</pre>
487
- * url: "/messages/:mailboxid?{before:date}&{after:date}"
488
- *
489
- * @param {object=} stateConfig.views
490
- * <a id='views'></a>
491
- * an optional map&lt;string, object&gt; which defined multiple views, or targets views
492
- * manually/explicitly.
493
- *
494
- * Examples:
495
- *
496
- * Targets three named `ui-view`s in the parent state's template
497
- * <pre>views: {
498
- * header: {
499
- * controller: "headerCtrl",
500
- * templateUrl: "header.html"
501
- * }, body: {
502
- * controller: "bodyCtrl",
503
- * templateUrl: "body.html"
504
- * }, footer: {
505
- * controller: "footCtrl",
506
- * templateUrl: "footer.html"
507
- * }
508
- * }</pre>
509
- *
510
- * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template.
511
- * <pre>views: {
512
- * 'header@top': {
513
- * controller: "msgHeaderCtrl",
514
- * templateUrl: "msgHeader.html"
515
- * }, 'body': {
516
- * controller: "messagesCtrl",
517
- * templateUrl: "messages.html"
518
- * }
519
- * }</pre>
520
- *
521
- * @param {boolean=} [stateConfig.abstract=false]
522
- * <a id='abstract'></a>
523
- * An abstract state will never be directly activated,
524
- * but can provide inherited properties to its common children states.
525
- * <pre>abstract: true</pre>
526
- *
527
- * @param {function=} stateConfig.onEnter
528
- * <a id='onEnter'></a>
529
- *
530
- * Callback function for when a state is entered. Good way
531
- * to trigger an action or dispatch an event, such as opening a dialog.
532
- * If minifying your scripts, make sure to explictly annotate this function,
533
- * because it won't be automatically annotated by your build tools.
534
- *
535
- * <pre>onEnter: function(MyService, $stateParams) {
536
- * MyService.foo($stateParams.myParam);
537
- * }</pre>
538
- *
539
- * @param {function=} stateConfig.onExit
540
- * <a id='onExit'></a>
541
- *
542
- * Callback function for when a state is exited. Good way to
543
- * trigger an action or dispatch an event, such as opening a dialog.
544
- * If minifying your scripts, make sure to explictly annotate this function,
545
- * because it won't be automatically annotated by your build tools.
546
- *
547
- * <pre>onExit: function(MyService, $stateParams) {
548
- * MyService.cleanup($stateParams.myParam);
549
- * }</pre>
550
- *
551
- * @param {boolean=} [stateConfig.reloadOnSearch=true]
552
- * <a id='reloadOnSearch'></a>
553
- *
554
- * If `false`, will not retrigger the same state
555
- * just because a search/query parameter has changed (via $location.search() or $location.hash()).
556
- * Useful for when you'd like to modify $location.search() without triggering a reload.
557
- * <pre>reloadOnSearch: false</pre>
558
- *
559
- * @param {object=} stateConfig.data
560
- * <a id='data'></a>
561
- *
562
- * Arbitrary data object, useful for custom configuration. The parent state's `data` is
563
- * prototypally inherited. In other words, adding a data property to a state adds it to
564
- * the entire subtree via prototypal inheritance.
565
- *
566
- * <pre>data: {
567
- * requiredRole: 'foo'
568
- * } </pre>
569
- *
570
- * @param {object=} stateConfig.params
571
- * <a id='params'></a>
572
- *
573
- * A map which optionally configures parameters declared in the `url`, or
574
- * defines additional non-url parameters. For each parameter being
575
- * configured, add a configuration object keyed to the name of the parameter.
576
- *
577
- * Each parameter configuration object may contain the following properties:
578
- *
579
- * - ** value ** - {object|function=}: specifies the default value for this
580
- * parameter. This implicitly sets this parameter as optional.
581
- *
582
- * When UI-Router routes to a state and no value is
583
- * specified for this parameter in the URL or transition, the
584
- * default value will be used instead. If `value` is a function,
585
- * it will be injected and invoked, and the return value used.
586
- *
587
- * *Note*: `undefined` is treated as "no default value" while `null`
588
- * is treated as "the default value is `null`".
589
- *
590
- * *Shorthand*: If you only need to configure the default value of the
591
- * parameter, you may use a shorthand syntax. In the **`params`**
592
- * map, instead mapping the param name to a full parameter configuration
593
- * object, simply set map it to the default parameter value, e.g.:
594
- *
595
- * <pre>// define a parameter's default value
596
- * params: {
597
- * param1: { value: "defaultValue" }
598
- * }
599
- * // shorthand default values
600
- * params: {
601
- * param1: "defaultValue",
602
- * param2: "param2Default"
603
- * }</pre>
604
- *
605
- * - ** array ** - {boolean=}: *(default: false)* If true, the param value will be
606
- * treated as an array of values. If you specified a Type, the value will be
607
- * treated as an array of the specified Type. Note: query parameter values
608
- * default to a special `"auto"` mode.
609
- *
610
- * For query parameters in `"auto"` mode, if multiple values for a single parameter
611
- * are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values
612
- * are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`). However, if
613
- * only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single
614
- * value (e.g.: `{ foo: '1' }`).
615
- *
616
- * <pre>params: {
617
- * param1: { array: true }
618
- * }</pre>
619
- *
620
- * - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when
621
- * the current parameter value is the same as the default value. If `squash` is not set, it uses the
622
- * configured default squash policy.
623
- * (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`})
624
- *
625
- * There are three squash settings:
626
- *
627
- * - false: The parameter's default value is not squashed. It is encoded and included in the URL
628
- * - true: The parameter's default value is omitted from the URL. If the parameter is preceeded and followed
629
- * by slashes in the state's `url` declaration, then one of those slashes are omitted.
630
- * This can allow for cleaner looking URLs.
631
- * - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary placeholder of your choice.
632
- *
633
- * <pre>params: {
634
- * param1: {
635
- * value: "defaultId",
636
- * squash: true
637
- * } }
638
- * // squash "defaultValue" to "~"
639
- * params: {
640
- * param1: {
641
- * value: "defaultValue",
642
- * squash: "~"
643
- * } }
644
- * </pre>
645
- *
646
- *
647
- * @example
648
- * <pre>
649
- * // Some state name examples
650
- *
651
- * // stateName can be a single top-level name (must be unique).
652
- * $stateProvider.state("home", {});
653
- *
654
- * // Or it can be a nested state name. This state is a child of the
655
- * // above "home" state.
656
- * $stateProvider.state("home.newest", {});
657
- *
658
- * // Nest states as deeply as needed.
659
- * $stateProvider.state("home.newest.abc.xyz.inception", {});
660
- *
661
- * // state() returns $stateProvider, so you can chain state declarations.
662
- * $stateProvider
663
- * .state("home", {})
664
- * .state("about", {})
665
- * .state("contacts", {});
666
- * </pre>
667
- *
668
- */
669
- this.state = state;
670
- function state(name, definition) {
671
- /*jshint validthis: true */
672
- if (isObject(name)) definition = name;
673
- else definition.name = name;
674
- registerState(definition);
675
- return this;
676
- }
677
-
678
- /**
679
- * @ngdoc object
680
- * @name ui.router.state.$state
681
- *
682
- * @requires $rootScope
683
- * @requires $q
684
- * @requires ui.router.state.$view
685
- * @requires $injector
686
- * @requires ui.router.util.$resolve
687
- * @requires ui.router.state.$stateParams
688
- * @requires ui.router.router.$urlRouter
689
- *
690
- * @property {object} params A param object, e.g. {sectionId: section.id)}, that
691
- * you'd like to test against the current active state.
692
- * @property {object} current A reference to the state's config object. However
693
- * you passed it in. Useful for accessing custom data.
694
- * @property {object} transition Currently pending transition. A promise that'll
695
- * resolve or reject.
696
- *
697
- * @description
698
- * `$state` service is responsible for representing states as well as transitioning
699
- * between them. It also provides interfaces to ask for current state or even states
700
- * you're coming from.
701
- */
702
- this.$get = $get;
703
- $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory'];
704
- function $get( $rootScope, $q, $view, $injector, $resolve, $stateParams, $urlRouter, $location, $urlMatcherFactory) {
705
-
706
- var TransitionSuperseded = $q.reject(new Error('transition superseded'));
707
- var TransitionPrevented = $q.reject(new Error('transition prevented'));
708
- var TransitionAborted = $q.reject(new Error('transition aborted'));
709
- var TransitionFailed = $q.reject(new Error('transition failed'));
710
-
711
- // Handles the case where a state which is the target of a transition is not found, and the user
712
- // can optionally retry or defer the transition
713
- function handleRedirect(redirect, state, params, options) {
714
- /**
715
- * @ngdoc event
716
- * @name ui.router.state.$state#$stateNotFound
717
- * @eventOf ui.router.state.$state
718
- * @eventType broadcast on root scope
719
- * @description
720
- * Fired when a requested state **cannot be found** using the provided state name during transition.
721
- * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
722
- * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
723
- * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
724
- * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
725
- *
726
- * @param {Object} event Event object.
727
- * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
728
- * @param {State} fromState Current state object.
729
- * @param {Object} fromParams Current state params.
730
- *
731
- * @example
732
- *
733
- * <pre>
734
- * // somewhere, assume lazy.state has not been defined
735
- * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
736
- *
737
- * // somewhere else
738
- * $scope.$on('$stateNotFound',
739
- * function(event, unfoundState, fromState, fromParams){
740
- * console.log(unfoundState.to); // "lazy.state"
741
- * console.log(unfoundState.toParams); // {a:1, b:2}
742
- * console.log(unfoundState.options); // {inherit:false} + default options
743
- * })
744
- * </pre>
745
- */
746
- var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params);
747
-
748
- if (evt.defaultPrevented) {
749
- $urlRouter.update();
750
- return TransitionAborted;
751
- }
752
-
753
- if (!evt.retry) {
754
- return null;
755
- }
756
-
757
- // Allow the handler to return a promise to defer state lookup retry
758
- if (options.$retry) {
759
- $urlRouter.update();
760
- return TransitionFailed;
761
- }
762
- var retryTransition = $state.transition = $q.when(evt.retry);
763
-
764
- retryTransition.then(function() {
765
- if (retryTransition !== $state.transition) return TransitionSuperseded;
766
- redirect.options.$retry = true;
767
- return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
768
- }, function() {
769
- return TransitionAborted;
770
- });
771
- $urlRouter.update();
772
-
773
- return retryTransition;
774
- }
775
-
776
- root.locals = { resolve: null, globals: { $stateParams: {} } };
777
-
778
- $state = {
779
- params: {},
780
- current: root.self,
781
- $current: root,
782
- transition: null
783
- };
784
-
785
- /**
786
- * @ngdoc function
787
- * @name ui.router.state.$state#reload
788
- * @methodOf ui.router.state.$state
789
- *
790
- * @description
791
- * A method that force reloads the current state. All resolves are re-resolved, events are not re-fired,
792
- * and controllers reinstantiated (bug with controllers reinstantiating right now, fixing soon).
793
- *
794
- * @example
795
- * <pre>
796
- * var app angular.module('app', ['ui.router']);
797
- *
798
- * app.controller('ctrl', function ($scope, $state) {
799
- * $scope.reload = function(){
800
- * $state.reload();
801
- * }
802
- * });
803
- * </pre>
804
- *
805
- * `reload()` is just an alias for:
806
- * <pre>
807
- * $state.transitionTo($state.current, $stateParams, {
808
- * reload: true, inherit: false, notify: true
809
- * });
810
- * </pre>
811
- *
812
- * @returns {promise} A promise representing the state of the new transition. See
813
- * {@link ui.router.state.$state#methods_go $state.go}.
814
- */
815
- $state.reload = function reload() {
816
- return $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true });
817
- };
818
-
819
- /**
820
- * @ngdoc function
821
- * @name ui.router.state.$state#go
822
- * @methodOf ui.router.state.$state
823
- *
824
- * @description
825
- * Convenience method for transitioning to a new state. `$state.go` calls
826
- * `$state.transitionTo` internally but automatically sets options to
827
- * `{ location: true, inherit: true, relative: $state.$current, notify: true }`.
828
- * This allows you to easily use an absolute or relative to path and specify
829
- * only the parameters you'd like to update (while letting unspecified parameters
830
- * inherit from the currently active ancestor states).
831
- *
832
- * @example
833
- * <pre>
834
- * var app = angular.module('app', ['ui.router']);
835
- *
836
- * app.controller('ctrl', function ($scope, $state) {
837
- * $scope.changeState = function () {
838
- * $state.go('contact.detail');
839
- * };
840
- * });
841
- * </pre>
842
- * <img src='../ngdoc_assets/StateGoExamples.png'/>
843
- *
844
- * @param {string} to Absolute state name or relative state path. Some examples:
845
- *
846
- * - `$state.go('contact.detail')` - will go to the `contact.detail` state
847
- * - `$state.go('^')` - will go to a parent state
848
- * - `$state.go('^.sibling')` - will go to a sibling state
849
- * - `$state.go('.child.grandchild')` - will go to grandchild state
850
- *
851
- * @param {object=} params A map of the parameters that will be sent to the state,
852
- * will populate $stateParams. Any parameters that are not specified will be inherited from currently
853
- * defined parameters. This allows, for example, going to a sibling state that shares parameters
854
- * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
855
- * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
856
- * will get you all current parameters, etc.
857
- * @param {object=} options Options object. The options are:
858
- *
859
- * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
860
- * will not. If string, must be `"replace"`, which will update url and also replace last history record.
861
- * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
862
- * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'),
863
- * defines which state to be relative from.
864
- * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
865
- * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params
866
- * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
867
- * use this when you want to force a reload when *everything* is the same, including search params.
868
- *
869
- * @returns {promise} A promise representing the state of the new transition.
870
- *
871
- * Possible success values:
872
- *
873
- * - $state.current
874
- *
875
- * <br/>Possible rejection values:
876
- *
877
- * - 'transition superseded' - when a newer transition has been started after this one
878
- * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
879
- * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
880
- * when a `$stateNotFound` `event.retry` promise errors.
881
- * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
882
- * - *resolve error* - when an error has occurred with a `resolve`
883
- *
884
- */
885
- $state.go = function go(to, params, options) {
886
- return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
887
- };
888
-
889
- /**
890
- * @ngdoc function
891
- * @name ui.router.state.$state#transitionTo
892
- * @methodOf ui.router.state.$state
893
- *
894
- * @description
895
- * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
896
- * uses `transitionTo` internally. `$state.go` is recommended in most situations.
897
- *
898
- * @example
899
- * <pre>
900
- * var app = angular.module('app', ['ui.router']);
901
- *
902
- * app.controller('ctrl', function ($scope, $state) {
903
- * $scope.changeState = function () {
904
- * $state.transitionTo('contact.detail');
905
- * };
906
- * });
907
- * </pre>
908
- *
909
- * @param {string} to State name.
910
- * @param {object=} toParams A map of the parameters that will be sent to the state,
911
- * will populate $stateParams.
912
- * @param {object=} options Options object. The options are:
913
- *
914
- * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
915
- * will not. If string, must be `"replace"`, which will update url and also replace last history record.
916
- * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
917
- * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'),
918
- * defines which state to be relative from.
919
- * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
920
- * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params
921
- * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
922
- * use this when you want to force a reload when *everything* is the same, including search params.
923
- *
924
- * @returns {promise} A promise representing the state of the new transition. See
925
- * {@link ui.router.state.$state#methods_go $state.go}.
926
- */
927
- $state.transitionTo = function transitionTo(to, toParams, options) {
928
- toParams = toParams || {};
929
- options = extend({
930
- location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
931
- }, options || {});
932
-
933
- var from = $state.$current, fromParams = $state.params, fromPath = from.path;
934
- var evt, toState = findState(to, options.relative);
935
-
936
- if (!isDefined(toState)) {
937
- var redirect = { to: to, toParams: toParams, options: options };
938
- var redirectResult = handleRedirect(redirect, from.self, fromParams, options);
939
-
940
- if (redirectResult) {
941
- return redirectResult;
942
- }
943
-
944
- // Always retry once if the $stateNotFound was not prevented
945
- // (handles either redirect changed or state lazy-definition)
946
- to = redirect.to;
947
- toParams = redirect.toParams;
948
- options = redirect.options;
949
- toState = findState(to, options.relative);
950
-
951
- if (!isDefined(toState)) {
952
- if (!options.relative) throw new Error("No such state '" + to + "'");
953
- throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
954
- }
955
- }
956
- if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
957
- if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
958
- if (!toState.params.$$validates(toParams)) return TransitionFailed;
959
-
960
- toParams = toState.params.$$values(toParams);
961
- to = toState;
962
-
963
- var toPath = to.path;
964
-
965
- // Starting from the root of the path, keep all levels that haven't changed
966
- var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
967
-
968
- if (!options.reload) {
969
- while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
970
- locals = toLocals[keep] = state.locals;
971
- keep++;
972
- state = toPath[keep];
973
- }
974
- }
975
-
976
- // If we're going to the same state and all locals are kept, we've got nothing to do.
977
- // But clear 'transition', as we still want to cancel any other pending transitions.
978
- // TODO: We may not want to bump 'transition' if we're called from a location change
979
- // that we've initiated ourselves, because we might accidentally abort a legitimate
980
- // transition initiated from code?
981
- if (shouldTriggerReload(to, from, locals, options)) {
982
- if (to.self.reloadOnSearch !== false) $urlRouter.update();
983
- $state.transition = null;
984
- return $q.when($state.current);
985
- }
986
-
987
- // Filter parameters before we pass them to event handlers etc.
988
- toParams = filterByKeys(to.params.$$keys(), toParams || {});
989
-
990
- // Broadcast start event and cancel the transition if requested
991
- if (options.notify) {
992
- /**
993
- * @ngdoc event
994
- * @name ui.router.state.$state#$stateChangeStart
995
- * @eventOf ui.router.state.$state
996
- * @eventType broadcast on root scope
997
- * @description
998
- * Fired when the state transition **begins**. You can use `event.preventDefault()`
999
- * to prevent the transition from happening and then the transition promise will be
1000
- * rejected with a `'transition prevented'` value.
1001
- *
1002
- * @param {Object} event Event object.
1003
- * @param {State} toState The state being transitioned to.
1004
- * @param {Object} toParams The params supplied to the `toState`.
1005
- * @param {State} fromState The current state, pre-transition.
1006
- * @param {Object} fromParams The params supplied to the `fromState`.
1007
- *
1008
- * @example
1009
- *
1010
- * <pre>
1011
- * $rootScope.$on('$stateChangeStart',
1012
- * function(event, toState, toParams, fromState, fromParams){
1013
- * event.preventDefault();
1014
- * // transitionTo() promise will be rejected with
1015
- * // a 'transition prevented' error
1016
- * })
1017
- * </pre>
1018
- */
1019
- if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams).defaultPrevented) {
1020
- $urlRouter.update();
1021
- return TransitionPrevented;
1022
- }
1023
- }
1024
-
1025
- // Resolve locals for the remaining states, but don't update any global state just
1026
- // yet -- if anything fails to resolve the current state needs to remain untouched.
1027
- // We also set up an inheritance chain for the locals here. This allows the view directive
1028
- // to quickly look up the correct definition for each view in the current state. Even
1029
- // though we create the locals object itself outside resolveState(), it is initially
1030
- // empty and gets filled asynchronously. We need to keep track of the promise for the
1031
- // (fully resolved) current locals, and pass this down the chain.
1032
- var resolved = $q.when(locals);
1033
-
1034
- for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
1035
- locals = toLocals[l] = inherit(locals);
1036
- resolved = resolveState(state, toParams, state === to, resolved, locals, options);
1037
- }
1038
-
1039
- // Once everything is resolved, we are ready to perform the actual transition
1040
- // and return a promise for the new state. We also keep track of what the
1041
- // current promise is, so that we can detect overlapping transitions and
1042
- // keep only the outcome of the last transition.
1043
- var transition = $state.transition = resolved.then(function () {
1044
- var l, entering, exiting;
1045
-
1046
- if ($state.transition !== transition) return TransitionSuperseded;
1047
-
1048
- // Exit 'from' states not kept
1049
- for (l = fromPath.length - 1; l >= keep; l--) {
1050
- exiting = fromPath[l];
1051
- if (exiting.self.onExit) {
1052
- $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
1053
- }
1054
- exiting.locals = null;
1055
- }
1056
-
1057
- // Enter 'to' states not kept
1058
- for (l = keep; l < toPath.length; l++) {
1059
- entering = toPath[l];
1060
- entering.locals = toLocals[l];
1061
- if (entering.self.onEnter) {
1062
- $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
1063
- }
1064
- }
1065
-
1066
- // Run it again, to catch any transitions in callbacks
1067
- if ($state.transition !== transition) return TransitionSuperseded;
1068
-
1069
- // Update globals in $state
1070
- $state.$current = to;
1071
- $state.current = to.self;
1072
- $state.params = toParams;
1073
- copy($state.params, $stateParams);
1074
- $state.transition = null;
1075
-
1076
- if (options.location && to.navigable) {
1077
- $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
1078
- $$avoidResync: true, replace: options.location === 'replace'
1079
- });
1080
- }
1081
-
1082
- if (options.notify) {
1083
- /**
1084
- * @ngdoc event
1085
- * @name ui.router.state.$state#$stateChangeSuccess
1086
- * @eventOf ui.router.state.$state
1087
- * @eventType broadcast on root scope
1088
- * @description
1089
- * Fired once the state transition is **complete**.
1090
- *
1091
- * @param {Object} event Event object.
1092
- * @param {State} toState The state being transitioned to.
1093
- * @param {Object} toParams The params supplied to the `toState`.
1094
- * @param {State} fromState The current state, pre-transition.
1095
- * @param {Object} fromParams The params supplied to the `fromState`.
1096
- */
1097
- $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
1098
- }
1099
- $urlRouter.update(true);
1100
-
1101
- return $state.current;
1102
- }, function (error) {
1103
- if ($state.transition !== transition) return TransitionSuperseded;
1104
-
1105
- $state.transition = null;
1106
- /**
1107
- * @ngdoc event
1108
- * @name ui.router.state.$state#$stateChangeError
1109
- * @eventOf ui.router.state.$state
1110
- * @eventType broadcast on root scope
1111
- * @description
1112
- * Fired when an **error occurs** during transition. It's important to note that if you
1113
- * have any errors in your resolve functions (javascript errors, non-existent services, etc)
1114
- * they will not throw traditionally. You must listen for this $stateChangeError event to
1115
- * catch **ALL** errors.
1116
- *
1117
- * @param {Object} event Event object.
1118
- * @param {State} toState The state being transitioned to.
1119
- * @param {Object} toParams The params supplied to the `toState`.
1120
- * @param {State} fromState The current state, pre-transition.
1121
- * @param {Object} fromParams The params supplied to the `fromState`.
1122
- * @param {Error} error The resolve error object.
1123
- */
1124
- evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
1125
-
1126
- if (!evt.defaultPrevented) {
1127
- $urlRouter.update();
1128
- }
1129
-
1130
- return $q.reject(error);
1131
- });
1132
-
1133
- return transition;
1134
- };
1135
-
1136
- /**
1137
- * @ngdoc function
1138
- * @name ui.router.state.$state#is
1139
- * @methodOf ui.router.state.$state
1140
- *
1141
- * @description
1142
- * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
1143
- * but only checks for the full state name. If params is supplied then it will be
1144
- * tested for strict equality against the current active params object, so all params
1145
- * must match with none missing and no extras.
1146
- *
1147
- * @example
1148
- * <pre>
1149
- * $state.$current.name = 'contacts.details.item';
1150
- *
1151
- * // absolute name
1152
- * $state.is('contact.details.item'); // returns true
1153
- * $state.is(contactDetailItemStateObject); // returns true
1154
- *
1155
- * // relative name (. and ^), typically from a template
1156
- * // E.g. from the 'contacts.details' template
1157
- * <div ng-class="{highlighted: $state.is('.item')}">Item</div>
1158
- * </pre>
1159
- *
1160
- * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check.
1161
- * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like
1162
- * to test against the current active state.
1163
- * @param {object=} options An options object. The options are:
1164
- *
1165
- * - **`relative`** - {string|object} - If `stateOrName` is a relative state name and `options.relative` is set, .is will
1166
- * test relative to `options.relative` state (or name).
1167
- *
1168
- * @returns {boolean} Returns true if it is the state.
1169
- */
1170
- $state.is = function is(stateOrName, params, options) {
1171
- options = extend({ relative: $state.$current }, options || {});
1172
- var state = findState(stateOrName, options.relative);
1173
-
1174
- if (!isDefined(state)) { return undefined; }
1175
- if ($state.$current !== state) { return false; }
1176
- return params ? equalForKeys(state.params.$$values(params), $stateParams) : true;
1177
- };
1178
-
1179
- /**
1180
- * @ngdoc function
1181
- * @name ui.router.state.$state#includes
1182
- * @methodOf ui.router.state.$state
1183
- *
1184
- * @description
1185
- * A method to determine if the current active state is equal to or is the child of the
1186
- * state stateName. If any params are passed then they will be tested for a match as well.
1187
- * Not all the parameters need to be passed, just the ones you'd like to test for equality.
1188
- *
1189
- * @example
1190
- * Partial and relative names
1191
- * <pre>
1192
- * $state.$current.name = 'contacts.details.item';
1193
- *
1194
- * // Using partial names
1195
- * $state.includes("contacts"); // returns true
1196
- * $state.includes("contacts.details"); // returns true
1197
- * $state.includes("contacts.details.item"); // returns true
1198
- * $state.includes("contacts.list"); // returns false
1199
- * $state.includes("about"); // returns false
1200
- *
1201
- * // Using relative names (. and ^), typically from a template
1202
- * // E.g. from the 'contacts.details' template
1203
- * <div ng-class="{highlighted: $state.includes('.item')}">Item</div>
1204
- * </pre>
1205
- *
1206
- * Basic globbing patterns
1207
- * <pre>
1208
- * $state.$current.name = 'contacts.details.item.url';
1209
- *
1210
- * $state.includes("*.details.*.*"); // returns true
1211
- * $state.includes("*.details.**"); // returns true
1212
- * $state.includes("**.item.**"); // returns true
1213
- * $state.includes("*.details.item.url"); // returns true
1214
- * $state.includes("*.details.*.url"); // returns true
1215
- * $state.includes("*.details.*"); // returns false
1216
- * $state.includes("item.**"); // returns false
1217
- * </pre>
1218
- *
1219
- * @param {string} stateOrName A partial name, relative name, or glob pattern
1220
- * to be searched for within the current state name.
1221
- * @param {object=} params A param object, e.g. `{sectionId: section.id}`,
1222
- * that you'd like to test against the current active state.
1223
- * @param {object=} options An options object. The options are:
1224
- *
1225
- * - **`relative`** - {string|object=} - If `stateOrName` is a relative state reference and `options.relative` is set,
1226
- * .includes will test relative to `options.relative` state (or name).
1227
- *
1228
- * @returns {boolean} Returns true if it does include the state
1229
- */
1230
- $state.includes = function includes(stateOrName, params, options) {
1231
- options = extend({ relative: $state.$current }, options || {});
1232
- if (isString(stateOrName) && isGlob(stateOrName)) {
1233
- if (!doesStateMatchGlob(stateOrName)) {
1234
- return false;
1235
- }
1236
- stateOrName = $state.$current.name;
1237
- }
1238
-
1239
- var state = findState(stateOrName, options.relative);
1240
- if (!isDefined(state)) { return undefined; }
1241
- if (!isDefined($state.$current.includes[state.name])) { return false; }
1242
- return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true;
1243
- };
1244
-
1245
-
1246
- /**
1247
- * @ngdoc function
1248
- * @name ui.router.state.$state#href
1249
- * @methodOf ui.router.state.$state
1250
- *
1251
- * @description
1252
- * A url generation method that returns the compiled url for the given state populated with the given params.
1253
- *
1254
- * @example
1255
- * <pre>
1256
- * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
1257
- * </pre>
1258
- *
1259
- * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
1260
- * @param {object=} params An object of parameter values to fill the state's required parameters.
1261
- * @param {object=} options Options object. The options are:
1262
- *
1263
- * - **`lossy`** - {boolean=true} - If true, and if there is no url associated with the state provided in the
1264
- * first parameter, then the constructed href url will be built from the first navigable ancestor (aka
1265
- * ancestor with a valid url).
1266
- * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
1267
- * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'),
1268
- * defines which state to be relative from.
1269
- * - **`absolute`** - {boolean=false}, If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
1270
- *
1271
- * @returns {string} compiled state url
1272
- */
1273
- $state.href = function href(stateOrName, params, options) {
1274
- options = extend({
1275
- lossy: true,
1276
- inherit: true,
1277
- absolute: false,
1278
- relative: $state.$current
1279
- }, options || {});
1280
-
1281
- var state = findState(stateOrName, options.relative);
1282
-
1283
- if (!isDefined(state)) return null;
1284
- if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state);
1285
-
1286
- var nav = (state && options.lossy) ? state.navigable : state;
1287
-
1288
- if (!nav || nav.url === undefined || nav.url === null) {
1289
- return null;
1290
- }
1291
- return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys(), params || {}), {
1292
- absolute: options.absolute
1293
- });
1294
- };
1295
-
1296
- /**
1297
- * @ngdoc function
1298
- * @name ui.router.state.$state#get
1299
- * @methodOf ui.router.state.$state
1300
- *
1301
- * @description
1302
- * Returns the state configuration object for any specific state or all states.
1303
- *
1304
- * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for
1305
- * the requested state. If not provided, returns an array of ALL state configs.
1306
- * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context.
1307
- * @returns {Object|Array} State configuration object or array of all objects.
1308
- */
1309
- $state.get = function (stateOrName, context) {
1310
- if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; });
1311
- var state = findState(stateOrName, context || $state.$current);
1312
- return (state && state.self) ? state.self : null;
1313
- };
1314
-
1315
- function resolveState(state, params, paramsAreFiltered, inherited, dst, options) {
1316
- // Make a restricted $stateParams with only the parameters that apply to this state if
1317
- // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
1318
- // we also need $stateParams to be available for any $injector calls we make during the
1319
- // dependency resolution process.
1320
- var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params);
1321
- var locals = { $stateParams: $stateParams };
1322
-
1323
- // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
1324
- // We're also including $stateParams in this; that way the parameters are restricted
1325
- // to the set that should be visible to the state, and are independent of when we update
1326
- // the global $state and $stateParams values.
1327
- dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
1328
- var promises = [dst.resolve.then(function (globals) {
1329
- dst.globals = globals;
1330
- })];
1331
- if (inherited) promises.push(inherited);
1332
-
1333
- // Resolve template and dependencies for all views.
1334
- forEach(state.views, function (view, name) {
1335
- var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
1336
- injectables.$template = [ function () {
1337
- return $view.load(name, { view: view, locals: locals, params: $stateParams, notify: options.notify }) || '';
1338
- }];
1339
-
1340
- promises.push($resolve.resolve(injectables, locals, dst.resolve, state).then(function (result) {
1341
- // References to the controller (only instantiated at link time)
1342
- if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
1343
- var injectLocals = angular.extend({}, injectables, locals);
1344
- result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
1345
- } else {
1346
- result.$$controller = view.controller;
1347
- }
1348
- // Provide access to the state itself for internal use
1349
- result.$$state = state;
1350
- result.$$controllerAs = view.controllerAs;
1351
- dst[name] = result;
1352
- }));
1353
- });
1354
-
1355
- // Wait for all the promises and then return the activation object
1356
- return $q.all(promises).then(function (values) {
1357
- return dst;
1358
- });
1359
- }
1360
-
1361
- return $state;
1362
- }
1363
-
1364
- function shouldTriggerReload(to, from, locals, options) {
1365
- if (to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false))) {
1366
- return true;
1367
- }
1368
- }
1369
- }
1370
-
1371
- angular.module('ui.router.state')
1372
- .value('$stateParams', {})
1373
- .provider('$state', $StateProvider);