red_base 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +339 -0
  3. data/README.rdoc +40 -0
  4. data/Rakefile +42 -0
  5. data/app/assets/fonts/DroidNaskh-Bold.ttf +0 -0
  6. data/app/assets/fonts/DroidNaskh-Regular.ttf +0 -0
  7. data/app/assets/fonts/OpenSans-Bold.ttf +0 -0
  8. data/app/assets/fonts/OpenSans-BoldItalic.ttf +0 -0
  9. data/app/assets/fonts/OpenSans-ExtraBold.ttf +0 -0
  10. data/app/assets/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
  11. data/app/assets/fonts/OpenSans-Italic.ttf +0 -0
  12. data/app/assets/fonts/OpenSans-Light.ttf +0 -0
  13. data/app/assets/fonts/OpenSans-LightItalic.ttf +0 -0
  14. data/app/assets/fonts/OpenSans-Regular.ttf +0 -0
  15. data/app/assets/fonts/OpenSans-Semibold.ttf +0 -0
  16. data/app/assets/fonts/OpenSans-SemiboldItalic.ttf +0 -0
  17. data/app/assets/javascripts/red_base/application.js +20 -0
  18. data/app/assets/javascripts/red_base/dashboard/angular.js +9 -0
  19. data/app/assets/javascripts/red_base/dashboard/app.js +65 -0
  20. data/app/assets/javascripts/red_base/dashboard/application.js.erb +24 -0
  21. data/app/assets/javascripts/red_base/dashboard/functions.js.erb +91 -0
  22. data/app/assets/javascripts/red_base/dashboard/init.js +38 -0
  23. data/app/assets/javascripts/red_base/dashboard/init.js~ +0 -0
  24. data/app/assets/javascripts/red_base/dashboard/lib/angular-animate.js +1226 -0
  25. data/app/assets/javascripts/red_base/dashboard/lib/angular-gettext.js +202 -0
  26. data/app/assets/javascripts/red_base/dashboard/lib/angular-resource.js +578 -0
  27. data/app/assets/javascripts/red_base/dashboard/lib/angular-route.js +880 -0
  28. data/app/assets/javascripts/red_base/dashboard/lib/angular.js +20031 -0
  29. data/app/assets/javascripts/red_base/dashboard/lib/lodash.underscore.js +4893 -0
  30. data/app/assets/javascripts/red_base/dashboard/lib/restangular.js +1066 -0
  31. data/app/assets/javascripts/red_base/dashboard/locale/translations.js +5 -0
  32. data/app/assets/javascripts/red_base/dashboard/modules/anim.js +32 -0
  33. data/app/assets/javascripts/red_base/dashboard/modules/api.js +32 -0
  34. data/app/assets/javascripts/red_base/dashboard/modules/auth/auth.js +34 -0
  35. data/app/assets/javascripts/red_base/dashboard/modules/auth/group.js +174 -0
  36. data/app/assets/javascripts/red_base/dashboard/modules/auth/user.js +122 -0
  37. data/app/assets/javascripts/red_base/dashboard/modules/list-view.js +293 -0
  38. data/app/assets/javascripts/red_base/dashboard/modules/logs.js +41 -0
  39. data/app/assets/javascripts/red_base/dashboard/modules/modules.js +50 -0
  40. data/app/assets/javascripts/red_base/dashboard/modules/nav.js.erb +92 -0
  41. data/app/assets/javascripts/red_base/dashboard/templates/application.handlebars.erb +42 -0
  42. data/app/assets/javascripts/red_base/dashboard/templates/auth/groups/details.handlebars.erb +15 -0
  43. data/app/assets/javascripts/red_base/dashboard/templates/auth/groups/index.handlebars.erb +7 -0
  44. data/app/assets/javascripts/red_base/dashboard/templates/auth/groups/new.handlebars.erb +39 -0
  45. data/app/assets/javascripts/red_base/dashboard/templates/auth/index.handlebars.erb +31 -0
  46. data/app/assets/javascripts/red_base/dashboard/templates/auth/users/details.handlebars.erb +15 -0
  47. data/app/assets/javascripts/red_base/dashboard/templates/auth/users/index.handlebars.erb +11 -0
  48. data/app/assets/javascripts/red_base/dashboard/templates/auth/users/new.handlebars.erb +33 -0
  49. data/app/assets/javascripts/red_base/dashboard/templates/components/list-view.handlebars.erb +59 -0
  50. data/app/assets/javascripts/red_base/dashboard/templates/components/model-form.handlebars.erb +3 -0
  51. data/app/assets/javascripts/red_base/dashboard/templates/modules.handlebars.erb +15 -0
  52. data/app/assets/javascripts/red_base/dashboard/templates/navigation.handlebars.erb +43 -0
  53. data/app/assets/javascripts/red_base/dashboard/templates/widgets.handlebars +23 -0
  54. data/app/assets/javascripts/red_base/dashboard/variables.js.erb +17 -0
  55. data/app/assets/javascripts/red_base/groups.js +2 -0
  56. data/app/assets/javascripts/red_base/home.js +2 -0
  57. data/app/assets/javascripts/red_base/i18n.js +13 -0
  58. data/app/assets/javascripts/red_base/locale/en.json +27 -0
  59. data/app/assets/javascripts/red_base/locale/fa.json +27 -0
  60. data/app/assets/javascripts/red_base/users.js +2 -0
  61. data/app/assets/stylesheets/red_base/base.css.scss +402 -0
  62. data/app/assets/stylesheets/red_base/dashboard/dashboard.css.scss +169 -0
  63. data/app/assets/stylesheets/red_base/dashboard/ltr/application.css +21 -0
  64. data/app/assets/stylesheets/red_base/dashboard/ltr/base.css.scss.erb +28 -0
  65. data/app/assets/stylesheets/red_base/dashboard/ltr/base.css.scss~ +15 -0
  66. data/app/assets/stylesheets/red_base/dashboard/ltr/buttons.css.scss.erb +48 -0
  67. data/app/assets/stylesheets/red_base/dashboard/ltr/direction.css.scss +38 -0
  68. data/app/assets/stylesheets/red_base/dashboard/ltr/foundation_and_overrides.css.scss +1014 -0
  69. data/app/assets/stylesheets/red_base/dashboard/rtl/application.css +21 -0
  70. data/app/assets/stylesheets/red_base/dashboard/rtl/base.css.scss.erb +31 -0
  71. data/app/assets/stylesheets/red_base/dashboard/rtl/base.css.scss~ +1 -0
  72. data/app/assets/stylesheets/red_base/dashboard/rtl/base.css_flymake.scss +25 -0
  73. data/app/assets/stylesheets/red_base/dashboard/rtl/buttons.css.scss.erb +45 -0
  74. data/app/assets/stylesheets/red_base/dashboard/rtl/direction.css.scss +37 -0
  75. data/app/assets/stylesheets/red_base/dashboard/rtl/foundation_and_overrides.css.scss +1014 -0
  76. data/app/assets/stylesheets/red_base/dashboard/sidebar.css.scss +93 -0
  77. data/app/assets/stylesheets/red_base/devise.css.scss +34 -0
  78. data/app/assets/stylesheets/red_base/groups.css +4 -0
  79. data/app/assets/stylesheets/red_base/home.css.scss +14 -0
  80. data/app/assets/stylesheets/red_base/ltr/application.css +20 -0
  81. data/app/assets/stylesheets/red_base/ltr/buttons.css.scss.erb +48 -0
  82. data/app/assets/stylesheets/red_base/ltr/foundation_and_overrides.scss.erb +1012 -0
  83. data/app/assets/stylesheets/red_base/mixins.css.scss +15 -0
  84. data/app/assets/stylesheets/red_base/mixins.css.scss~ +7 -0
  85. data/app/assets/stylesheets/red_base/rtl/application.css +20 -0
  86. data/app/assets/stylesheets/red_base/rtl/buttons.css.scss.erb +48 -0
  87. data/app/assets/stylesheets/red_base/rtl/foundation_and_overrides.scss.erb +1012 -0
  88. data/app/assets/stylesheets/red_base/users.css +4 -0
  89. data/app/assets/stylesheets/red_base/variables.css.scss +100 -0
  90. data/app/controllers/red_base/api/v1/groups_controller.rb +65 -0
  91. data/app/controllers/red_base/api/v1/logs_controller.rb +12 -0
  92. data/app/controllers/red_base/api/v1/permissions_controller.rb +17 -0
  93. data/app/controllers/red_base/api/v1/users_controller.rb +54 -0
  94. data/app/controllers/red_base/api_controller.rb +51 -0
  95. data/app/controllers/red_base/application_controller.rb +34 -0
  96. data/app/controllers/red_base/dashboard_controller.rb +40 -0
  97. data/app/controllers/red_base/home_controller.rb +19 -0
  98. data/app/controllers/red_base/omniauth/callbacks_controller.rb +43 -0
  99. data/app/controllers/red_base/users/omniauth_callbacks_controller.rb~ +2 -0
  100. data/app/helpers/red_base/application_helper.rb +4 -0
  101. data/app/helpers/red_base/dashboard_helper.rb +5 -0
  102. data/app/helpers/red_base/groups_helper.rb +4 -0
  103. data/app/helpers/red_base/home_helper.rb +4 -0
  104. data/app/helpers/red_base/users_helper.rb +4 -0
  105. data/app/models/ability.rb +39 -0
  106. data/app/models/red_base/group.rb +27 -0
  107. data/app/models/red_base/permission.rb +15 -0
  108. data/app/models/red_base/user.rb +77 -0
  109. data/app/views/angularjs_templates/auth/groups/details.html +21 -0
  110. data/app/views/angularjs_templates/auth/groups/index.html +5 -0
  111. data/app/views/angularjs_templates/auth/groups/new.html +40 -0
  112. data/app/views/angularjs_templates/auth/index.html +30 -0
  113. data/app/views/angularjs_templates/auth/users/details.html +28 -0
  114. data/app/views/angularjs_templates/auth/users/index.html +6 -0
  115. data/app/views/angularjs_templates/auth/users/new.html +45 -0
  116. data/app/views/angularjs_templates/index.html +8 -0
  117. data/app/views/angularjs_templates/list-view/index.html +66 -0
  118. data/app/views/angularjs_templates/locale/fa.po +25 -0
  119. data/app/views/angularjs_templates/locale/templates.pot +24 -0
  120. data/app/views/angularjs_templates/logs/index.html +6 -0
  121. data/app/views/angularjs_templates/modules.html +17 -0
  122. data/app/views/angularjs_templates/nav.html.erb +38 -0
  123. data/app/views/angularjs_templates/nav.html.erb~ +43 -0
  124. data/app/views/devise/confirmations/new.html.erb +34 -0
  125. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  126. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  127. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  128. data/app/views/devise/passwords/edit.html.erb +44 -0
  129. data/app/views/devise/passwords/new.html.erb +32 -0
  130. data/app/views/devise/registrations/edit.html.erb +29 -0
  131. data/app/views/devise/registrations/new.html.erb +91 -0
  132. data/app/views/devise/sessions/new.html.erb +98 -0
  133. data/app/views/devise/shared/_links.erb +25 -0
  134. data/app/views/devise/unlocks/new.html.erb +30 -0
  135. data/app/views/layouts/red_base/application.html.erb +90 -0
  136. data/app/views/layouts/red_base/dashboard.html.erb +21 -0
  137. data/app/views/red_base/api/v1/groups/create.json.jbuilder +4 -0
  138. data/app/views/red_base/api/v1/groups/destroy.html.erb +2 -0
  139. data/app/views/red_base/api/v1/groups/destroy.json.jbuilder +1 -0
  140. data/app/views/red_base/api/v1/groups/edit.html.erb +2 -0
  141. data/app/views/red_base/api/v1/groups/index.html.erb +2 -0
  142. data/app/views/red_base/api/v1/groups/index.json.jbuilder +6 -0
  143. data/app/views/red_base/api/v1/groups/new.html.erb +2 -0
  144. data/app/views/red_base/api/v1/groups/show.html.erb +2 -0
  145. data/app/views/red_base/api/v1/groups/show.json.jbuilder +5 -0
  146. data/app/views/red_base/api/v1/groups/update.json.jbuilder +4 -0
  147. data/app/views/red_base/api/v1/logs/index.json.jbuilder +1 -0
  148. data/app/views/red_base/api/v1/permissions/index.json.jbuilder +1 -0
  149. data/app/views/red_base/api/v1/users/create.html.erb +2 -0
  150. data/app/views/red_base/api/v1/users/create.json.jbuilder +1 -0
  151. data/app/views/red_base/api/v1/users/destroy.json.jbuilder +1 -0
  152. data/app/views/red_base/api/v1/users/distroy.html.erb +2 -0
  153. data/app/views/red_base/api/v1/users/edit.html.erb +2 -0
  154. data/app/views/red_base/api/v1/users/index.html.erb +2 -0
  155. data/app/views/red_base/api/v1/users/index.json.jbuilder +4 -0
  156. data/app/views/red_base/api/v1/users/show.html.erb +2 -0
  157. data/app/views/red_base/api/v1/users/show.json.jbuilder +2 -0
  158. data/app/views/red_base/api/v1/users/update.json.jbuilder +1 -0
  159. data/app/views/red_base/dashboard/index.html.erb +37 -0
  160. data/app/views/red_base/home/index.html.erb +119 -0
  161. data/config/initializers/devise.rb +28 -0
  162. data/config/locales/devise.en.yml +59 -0
  163. data/config/locales/devise.fa.yml +56 -0
  164. data/config/locales/fa/LC_MESSAGES/red_base.mo +0 -0
  165. data/config/locales/fa/messages.mo +0 -0
  166. data/config/locales/fa/red_base.po +181 -0
  167. data/config/locales/red_base.pot +181 -0
  168. data/config/routes.rb +33 -0
  169. data/db/migrate/20131013091000_devise_create_red_base_users.rb +64 -0
  170. data/db/migrate/20131020124701_create_red_base_groups.rb +9 -0
  171. data/db/migrate/20131021170923_create_red_base_permissions.rb +10 -0
  172. data/db/migrate/20131123120422_add_permissions_groups_table.rb +8 -0
  173. data/db/seeds.rb +15 -0
  174. data/lib/devise_patch.rb~ +5 -0
  175. data/lib/generators/red_base/USAGE +8 -0
  176. data/lib/generators/red_base/angularjs_resource_generator.rb +74 -0
  177. data/lib/generators/red_base/install_all_generator.rb +38 -0
  178. data/lib/generators/red_base/install_generator.rb +42 -0
  179. data/lib/generators/red_base/install_specs_generator.rb +48 -0
  180. data/lib/generators/red_base/js_scaffold_generator.rb +232 -0
  181. data/lib/generators/red_base/templates/README +41 -0
  182. data/lib/generators/red_base/templates/README~ +4 -0
  183. data/lib/generators/red_base/templates/SPECS +13 -0
  184. data/lib/generators/red_base/templates/angularjs/details.html.erb +20 -0
  185. data/lib/generators/red_base/templates/angularjs/details.html.erb~ +0 -0
  186. data/lib/generators/red_base/templates/angularjs/index.html.erb +59 -0
  187. data/lib/generators/red_base/templates/angularjs/module.js.erb +259 -0
  188. data/lib/generators/red_base/templates/angularjs/new.html.erb +43 -0
  189. data/lib/generators/red_base/templates/api/controller.rb.erb +54 -0
  190. data/lib/generators/red_base/templates/api/controller.rb.erb~ +37 -0
  191. data/lib/generators/red_base/templates/devise.rb +251 -0
  192. data/lib/generators/red_base/templates/devise.rb~ +238 -0
  193. data/lib/generators/red_base/templates/fast_gettext.rb +4 -0
  194. data/lib/generators/red_base/templates/features/api.feature +92 -0
  195. data/lib/generators/red_base/templates/features/api.step.rb +7 -0
  196. data/lib/generators/red_base/templates/features/step_definitions/email_steps.rb +206 -0
  197. data/lib/generators/red_base/templates/features/support/email_spec.rb +1 -0
  198. data/lib/generators/red_base/templates/features/support/env.rb +79 -0
  199. data/lib/generators/red_base/templates/formtastic.rb +76 -0
  200. data/lib/generators/red_base/templates/js_scaffold.README +25 -0
  201. data/lib/generators/red_base/templates/red_base.rb +14 -0
  202. data/lib/generators/red_base/templates/red_base.rb~ +251 -0
  203. data/lib/generators/red_base/templates/seeds.rb +1 -0
  204. data/lib/generators/red_base/templates/spec/factories/groups.rb +5 -0
  205. data/lib/generators/red_base/templates/spec/factories/users.rb +10 -0
  206. data/lib/generators/red_base/templates/spec/spec_helper.rb +69 -0
  207. data/lib/generators/red_base/templates/spec/support/devise.rb +3 -0
  208. data/lib/generators/red_base/templates/views/create.json.jbuilder.erb +2 -0
  209. data/lib/generators/red_base/templates/views/destroy.json.jbuilder.erb +1 -0
  210. data/lib/generators/red_base/templates/views/index.json.jbuilder.erb +10 -0
  211. data/lib/generators/red_base/templates/views/index.json.jbuilder.erb~ +0 -0
  212. data/lib/generators/red_base/templates/views/show.json.jbuilder.erb +6 -0
  213. data/lib/generators/red_base/templates/views/update.json.jbuilder.erb +6 -0
  214. data/lib/generators/red_base/views_generator.rb +41 -0
  215. data/lib/red_base/active_record.rb +78 -0
  216. data/lib/red_base/active_record.rb~ +0 -0
  217. data/lib/red_base/api/groups_api.rb +41 -0
  218. data/lib/red_base/api/permissions_api.rb +24 -0
  219. data/lib/red_base/api/root.rb +15 -0
  220. data/lib/red_base/api/users_api.rb +20 -0
  221. data/lib/red_base/api.rb +61 -0
  222. data/lib/red_base/cucumber/auth.rb +45 -0
  223. data/lib/red_base/cucumber/exceptions.rb +40 -0
  224. data/lib/red_base/cucumber/interaction.rb +43 -0
  225. data/lib/red_base/cucumber/query.rb +28 -0
  226. data/lib/red_base/cucumber/urls.rb +76 -0
  227. data/lib/red_base/cucumber.rb +25 -0
  228. data/lib/red_base/dashboard/controller.rb +42 -0
  229. data/lib/red_base/dashboard/module.rb +45 -0
  230. data/lib/red_base/dashboard/module.rb~ +25 -0
  231. data/lib/red_base/dashboard.rb +60 -0
  232. data/lib/red_base/dashboard.rb~ +18 -0
  233. data/lib/red_base/engine.rb +132 -0
  234. data/lib/red_base/exceptions.rb +26 -0
  235. data/lib/red_base/i18n.rb +35 -0
  236. data/lib/red_base/initialize.rb +7 -0
  237. data/lib/red_base/omniauth/callbacks.rb +58 -0
  238. data/lib/red_base/omniauth/callbakcs.rb~ +7 -0
  239. data/lib/red_base/omniauth.rb +24 -0
  240. data/lib/red_base/omniauth.rb~ +1 -0
  241. data/lib/red_base/plugins.rb +44 -0
  242. data/lib/red_base/version.rb +22 -0
  243. data/lib/red_base.rb +30 -0
  244. data/lib/tasks/grunt/Gruntfile.js +25 -0
  245. data/lib/tasks/red_base_tasks.rake +23 -0
  246. data/spec/dummy/README.rdoc +28 -0
  247. data/spec/dummy/Rakefile +6 -0
  248. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  249. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  250. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  251. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  252. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  253. data/spec/dummy/bin/bundle +3 -0
  254. data/spec/dummy/bin/rails +4 -0
  255. data/spec/dummy/bin/rake +4 -0
  256. data/spec/dummy/config/application.rb +23 -0
  257. data/spec/dummy/config/boot.rb +5 -0
  258. data/spec/dummy/config/database.yml +25 -0
  259. data/spec/dummy/config/environment.rb +5 -0
  260. data/spec/dummy/config/environments/development.rb +29 -0
  261. data/spec/dummy/config/environments/production.rb +80 -0
  262. data/spec/dummy/config/environments/test.rb +36 -0
  263. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  264. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  265. data/spec/dummy/config/initializers/inflections.rb +16 -0
  266. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  267. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  268. data/spec/dummy/config/initializers/session_store.rb +3 -0
  269. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  270. data/spec/dummy/config/locales/en.yml +23 -0
  271. data/spec/dummy/config/routes.rb +4 -0
  272. data/spec/dummy/config.ru +4 -0
  273. data/spec/dummy/public/404.html +58 -0
  274. data/spec/dummy/public/422.html +58 -0
  275. data/spec/dummy/public/500.html +57 -0
  276. data/spec/dummy/public/favicon.ico +0 -0
  277. data/spec/spec_helper.rb +52 -0
  278. metadata +661 -0
@@ -0,0 +1,1226 @@
1
+ /**
2
+ * @license AngularJS v1.2.1
3
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {'use strict';
7
+
8
+ /* jshint maxlen: false */
9
+
10
+ /**
11
+ * @ngdoc overview
12
+ * @name ngAnimate
13
+ * @description
14
+ *
15
+ * # ngAnimate
16
+ *
17
+ * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
18
+ *
19
+ * {@installModule animate}
20
+ *
21
+ * <div doc-module-components="ngAnimate"></div>
22
+ *
23
+ * # Usage
24
+ *
25
+ * To see animations in action, all that is required is to define the appropriate CSS classes
26
+ * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
27
+ * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
28
+ * by using the `$animate` service.
29
+ *
30
+ * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
31
+ *
32
+ * | Directive | Supported Animations |
33
+ * |---------------------------------------------------------- |----------------------------------------------------|
34
+ * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
35
+ * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
36
+ * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
37
+ * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
38
+ * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
39
+ * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
40
+ * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
41
+ *
42
+ * You can find out more information about animations upon visiting each directive page.
43
+ *
44
+ * Below is an example of how to apply animations to a directive that supports animation hooks:
45
+ *
46
+ * <pre>
47
+ * <style type="text/css">
48
+ * .slide.ng-enter, .slide.ng-leave {
49
+ * -webkit-transition:0.5s linear all;
50
+ * transition:0.5s linear all;
51
+ * }
52
+ *
53
+ * .slide.ng-enter { } /&#42; starting animations for enter &#42;/
54
+ * .slide.ng-enter-active { } /&#42; terminal animations for enter &#42;/
55
+ * .slide.ng-leave { } /&#42; starting animations for leave &#42;/
56
+ * .slide.ng-leave-active { } /&#42; terminal animations for leave &#42;/
57
+ * </style>
58
+ *
59
+ * <!--
60
+ * the animate service will automatically add .ng-enter and .ng-leave to the element
61
+ * to trigger the CSS transition/animations
62
+ * -->
63
+ * <ANY class="slide" ng-include="..."></ANY>
64
+ * </pre>
65
+ *
66
+ * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's
67
+ * animation has completed.
68
+ *
69
+ * <h2>CSS-defined Animations</h2>
70
+ * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
71
+ * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
72
+ * and can be used to play along with this naming structure.
73
+ *
74
+ * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
75
+ *
76
+ * <pre>
77
+ * <style type="text/css">
78
+ * /&#42;
79
+ * The animate class is apart of the element and the ng-enter class
80
+ * is attached to the element once the enter animation event is triggered
81
+ * &#42;/
82
+ * .reveal-animation.ng-enter {
83
+ * -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
84
+ * transition: 1s linear all; /&#42; All other modern browsers and IE10+ &#42;/
85
+ *
86
+ * /&#42; The animation preparation code &#42;/
87
+ * opacity: 0;
88
+ * }
89
+ *
90
+ * /&#42;
91
+ * Keep in mind that you want to combine both CSS
92
+ * classes together to avoid any CSS-specificity
93
+ * conflicts
94
+ * &#42;/
95
+ * .reveal-animation.ng-enter.ng-enter-active {
96
+ * /&#42; The animation code itself &#42;/
97
+ * opacity: 1;
98
+ * }
99
+ * </style>
100
+ *
101
+ * <div class="view-container">
102
+ * <div ng-view class="reveal-animation"></div>
103
+ * </div>
104
+ * </pre>
105
+ *
106
+ * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
107
+ *
108
+ * <pre>
109
+ * <style type="text/css">
110
+ * .reveal-animation.ng-enter {
111
+ * -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
112
+ * animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
113
+ * }
114
+ * &#64-webkit-keyframes enter_sequence {
115
+ * from { opacity:0; }
116
+ * to { opacity:1; }
117
+ * }
118
+ * &#64keyframes enter_sequence {
119
+ * from { opacity:0; }
120
+ * to { opacity:1; }
121
+ * }
122
+ * </style>
123
+ *
124
+ * <div class="view-container">
125
+ * <div ng-view class="reveal-animation"></div>
126
+ * </div>
127
+ * </pre>
128
+ *
129
+ * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
130
+ *
131
+ * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
132
+ * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
133
+ * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
134
+ * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
135
+ * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
136
+ * has no CSS transition/animation classes applied to it.
137
+ *
138
+ * <h3>CSS Staggering Animations</h3>
139
+ * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
140
+ * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
141
+ * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
142
+ * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
143
+ * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
144
+ *
145
+ * <pre>
146
+ * .my-animation.ng-enter {
147
+ * /&#42; standard transition code &#42;/
148
+ * -webkit-transition: 1s linear all;
149
+ * transition: 1s linear all;
150
+ * opacity:0;
151
+ * }
152
+ * .my-animation.ng-enter-stagger {
153
+ * /&#42; this will have a 100ms delay between each successive leave animation &#42;/
154
+ * -webkit-transition-delay: 0.1s;
155
+ * transition-delay: 0.1s;
156
+ *
157
+ * /&#42; in case the stagger doesn't work then these two values
158
+ * must be set to 0 to avoid an accidental CSS inheritance &#42;/
159
+ * -webkit-transition-duration: 0s;
160
+ * transition-duration: 0s;
161
+ * }
162
+ * .my-animation.ng-enter.ng-enter-active {
163
+ * /&#42; standard transition styles &#42;/
164
+ * opacity:1;
165
+ * }
166
+ * </pre>
167
+ *
168
+ * Staggering animations work by default in ngRepeat (so long as the CSS class is defiend). Outside of ngRepeat, to use staggering animations
169
+ * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
170
+ * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
171
+ * will also be reset if more than 10ms has passed after the last animation has been fired.
172
+ *
173
+ * The following code will issue the **ng-leave-stagger** event on the element provided:
174
+ *
175
+ * <pre>
176
+ * var kids = parent.children();
177
+ *
178
+ * $animate.leave(kids[0]); //stagger index=0
179
+ * $animate.leave(kids[1]); //stagger index=1
180
+ * $animate.leave(kids[2]); //stagger index=2
181
+ * $animate.leave(kids[3]); //stagger index=3
182
+ * $animate.leave(kids[4]); //stagger index=4
183
+ *
184
+ * $timeout(function() {
185
+ * //stagger has reset itself
186
+ * $animate.leave(kids[5]); //stagger index=0
187
+ * $animate.leave(kids[6]); //stagger index=1
188
+ * }, 100, false);
189
+ * </pre>
190
+ *
191
+ * Stagger animations are currently only supported within CSS-defined animations.
192
+ *
193
+ * <h2>JavaScript-defined Animations</h2>
194
+ * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
195
+ * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
196
+ *
197
+ * <pre>
198
+ * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
199
+ * var ngModule = angular.module('YourApp', []);
200
+ * ngModule.animation('.my-crazy-animation', function() {
201
+ * return {
202
+ * enter: function(element, done) {
203
+ * //run the animation here and call done when the animation is complete
204
+ * return function(cancelled) {
205
+ * //this (optional) function will be called when the animation
206
+ * //completes or when the animation is cancelled (the cancelled
207
+ * //flag will be set to true if cancelled).
208
+ * }
209
+ * }
210
+ * leave: function(element, done) { },
211
+ * move: function(element, done) { },
212
+ *
213
+ * //animation that can be triggered before the class is added
214
+ * beforeAddClass: function(element, className, done) { },
215
+ *
216
+ * //animation that can be triggered after the class is added
217
+ * addClass: function(element, className, done) { },
218
+ *
219
+ * //animation that can be triggered before the class is removed
220
+ * beforeRemoveClass: function(element, className, done) { },
221
+ *
222
+ * //animation that can be triggered after the class is removed
223
+ * removeClass: function(element, className, done) { }
224
+ * }
225
+ * });
226
+ * </pre>
227
+ *
228
+ * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
229
+ * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
230
+ * the element's CSS class attribute value and then run the matching animation event function (if found).
231
+ * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function
232
+ * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
233
+ *
234
+ * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
235
+ * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
236
+ * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
237
+ * or transition code that is defined via a stylesheet).
238
+ *
239
+ */
240
+
241
+ angular.module('ngAnimate', ['ng'])
242
+
243
+ /**
244
+ * @ngdoc object
245
+ * @name ngAnimate.$animateProvider
246
+ * @description
247
+ *
248
+ * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
249
+ * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
250
+ * the provided name value.
251
+ *
252
+ * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
253
+ *
254
+ * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
255
+ *
256
+ */
257
+ .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
258
+ var noop = angular.noop;
259
+ var forEach = angular.forEach;
260
+ var selectors = $animateProvider.$$selectors;
261
+
262
+ var ELEMENT_NODE = 1;
263
+ var NG_ANIMATE_STATE = '$$ngAnimateState';
264
+ var NG_ANIMATE_CLASS_NAME = 'ng-animate';
265
+ var rootAnimateState = {running: true};
266
+
267
+ $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document',
268
+ function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) {
269
+
270
+ $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
271
+
272
+ // disable animations during bootstrap, but once we bootstrapped, enable animations
273
+ $rootScope.$$postDigest(function() {
274
+ rootAnimateState.running = false;
275
+ });
276
+
277
+ function lookup(name) {
278
+ if (name) {
279
+ var matches = [],
280
+ flagMap = {},
281
+ classes = name.substr(1).split('.');
282
+
283
+ //the empty string value is the default animation
284
+ //operation which performs CSS transition and keyframe
285
+ //animations sniffing. This is always included for each
286
+ //element animation procedure if the browser supports
287
+ //transitions and/or keyframe animations
288
+ if ($sniffer.transitions || $sniffer.animations) {
289
+ classes.push('');
290
+ }
291
+
292
+ for(var i=0; i < classes.length; i++) {
293
+ var klass = classes[i],
294
+ selectorFactoryName = selectors[klass];
295
+ if(selectorFactoryName && !flagMap[klass]) {
296
+ matches.push($injector.get(selectorFactoryName));
297
+ flagMap[klass] = true;
298
+ }
299
+ }
300
+ return matches;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * @ngdoc object
306
+ * @name ngAnimate.$animate
307
+ * @function
308
+ *
309
+ * @description
310
+ * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
311
+ * When any of these operations are run, the $animate service
312
+ * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
313
+ * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
314
+ *
315
+ * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
316
+ * will work out of the box without any extra configuration.
317
+ *
318
+ * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
319
+ *
320
+ * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
321
+ *
322
+ */
323
+ return {
324
+ /**
325
+ * @ngdoc function
326
+ * @name ngAnimate.$animate#enter
327
+ * @methodOf ngAnimate.$animate
328
+ * @function
329
+ *
330
+ * @description
331
+ * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
332
+ * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
333
+ *
334
+ * Below is a breakdown of each step that occurs during enter animation:
335
+ *
336
+ * | Animation Step | What the element class attribute looks like |
337
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
338
+ * | 1. $animate.enter(...) is called | class="my-animation" |
339
+ * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
340
+ * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
341
+ * | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
342
+ * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
343
+ * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" |
344
+ * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
345
+ * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
346
+ * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
347
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
348
+ *
349
+ * @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
350
+ * @param {jQuery/jqLite element} parentElement the parent element of the element that will be the focus of the enter animation
351
+ * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
352
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
353
+ */
354
+ enter : function(element, parentElement, afterElement, doneCallback) {
355
+ this.enabled(false, element);
356
+ $delegate.enter(element, parentElement, afterElement);
357
+ $rootScope.$$postDigest(function() {
358
+ performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
359
+ });
360
+ },
361
+
362
+ /**
363
+ * @ngdoc function
364
+ * @name ngAnimate.$animate#leave
365
+ * @methodOf ngAnimate.$animate
366
+ * @function
367
+ *
368
+ * @description
369
+ * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
370
+ * the animation is started, the following CSS classes will be added for the duration of the animation:
371
+ *
372
+ * Below is a breakdown of each step that occurs during enter animation:
373
+ *
374
+ * | Animation Step | What the element class attribute looks like |
375
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
376
+ * | 1. $animate.leave(...) is called | class="my-animation" |
377
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
378
+ * | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
379
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
380
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" |
381
+ * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
382
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
383
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
384
+ * | 9. The element is removed from the DOM | ... |
385
+ * | 10. The doneCallback() callback is fired (if provided) | ... |
386
+ *
387
+ * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
388
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
389
+ */
390
+ leave : function(element, doneCallback) {
391
+ cancelChildAnimations(element);
392
+ this.enabled(false, element);
393
+ $rootScope.$$postDigest(function() {
394
+ performAnimation('leave', 'ng-leave', element, null, null, function() {
395
+ $delegate.leave(element);
396
+ }, doneCallback);
397
+ });
398
+ },
399
+
400
+ /**
401
+ * @ngdoc function
402
+ * @name ngAnimate.$animate#move
403
+ * @methodOf ngAnimate.$animate
404
+ * @function
405
+ *
406
+ * @description
407
+ * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
408
+ * add the element directly after the afterElement element if present. Then the move animation will be run. Once
409
+ * the animation is started, the following CSS classes will be added for the duration of the animation:
410
+ *
411
+ * Below is a breakdown of each step that occurs during move animation:
412
+ *
413
+ * | Animation Step | What the element class attribute looks like |
414
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
415
+ * | 1. $animate.move(...) is called | class="my-animation" |
416
+ * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
417
+ * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
418
+ * | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
419
+ * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
420
+ * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" |
421
+ * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
422
+ * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
423
+ * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
424
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
425
+ *
426
+ * @param {jQuery/jqLite element} element the element that will be the focus of the move animation
427
+ * @param {jQuery/jqLite element} parentElement the parentElement element of the element that will be the focus of the move animation
428
+ * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
429
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
430
+ */
431
+ move : function(element, parentElement, afterElement, doneCallback) {
432
+ cancelChildAnimations(element);
433
+ this.enabled(false, element);
434
+ $delegate.move(element, parentElement, afterElement);
435
+ $rootScope.$$postDigest(function() {
436
+ performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
437
+ });
438
+ },
439
+
440
+ /**
441
+ * @ngdoc function
442
+ * @name ngAnimate.$animate#addClass
443
+ * @methodOf ngAnimate.$animate
444
+ *
445
+ * @description
446
+ * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
447
+ * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
448
+ * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
449
+ * or keyframes are defined on the -add or base CSS class).
450
+ *
451
+ * Below is a breakdown of each step that occurs during addClass animation:
452
+ *
453
+ * | Animation Step | What the element class attribute looks like |
454
+ * |------------------------------------------------------------------------------------------------|---------------------------------------------|
455
+ * | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
456
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
457
+ * | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" |
458
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
459
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" |
460
+ * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active" |
461
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super-add super-add-active" |
462
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
463
+ * | 9. The super class is kept on the element | class="my-animation super" |
464
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
465
+ *
466
+ * @param {jQuery/jqLite element} element the element that will be animated
467
+ * @param {string} className the CSS class that will be added to the element and then animated
468
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
469
+ */
470
+ addClass : function(element, className, doneCallback) {
471
+ performAnimation('addClass', className, element, null, null, function() {
472
+ $delegate.addClass(element, className);
473
+ }, doneCallback);
474
+ },
475
+
476
+ /**
477
+ * @ngdoc function
478
+ * @name ngAnimate.$animate#removeClass
479
+ * @methodOf ngAnimate.$animate
480
+ *
481
+ * @description
482
+ * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
483
+ * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
484
+ * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
485
+ * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
486
+ *
487
+ * Below is a breakdown of each step that occurs during removeClass animation:
488
+ *
489
+ * | Animation Step | What the element class attribute looks like |
490
+ * |-----------------------------------------------------------------------------------------------|---------------------------------------------|
491
+ * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
492
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" |
493
+ * | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"|
494
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
495
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" |
496
+ * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
497
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
498
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
499
+ * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
500
+ *
501
+ *
502
+ * @param {jQuery/jqLite element} element the element that will be animated
503
+ * @param {string} className the CSS class that will be animated and then removed from the element
504
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
505
+ */
506
+ removeClass : function(element, className, doneCallback) {
507
+ performAnimation('removeClass', className, element, null, null, function() {
508
+ $delegate.removeClass(element, className);
509
+ }, doneCallback);
510
+ },
511
+
512
+ /**
513
+ * @ngdoc function
514
+ * @name ngAnimate.$animate#enabled
515
+ * @methodOf ngAnimate.$animate
516
+ * @function
517
+ *
518
+ * @param {boolean=} value If provided then set the animation on or off.
519
+ * @return {boolean} Current animation state.
520
+ *
521
+ * @description
522
+ * Globally enables/disables animations.
523
+ *
524
+ */
525
+ enabled : function(value, element) {
526
+ switch(arguments.length) {
527
+ case 2:
528
+ if(value) {
529
+ cleanup(element);
530
+ } else {
531
+ var data = element.data(NG_ANIMATE_STATE) || {};
532
+ data.disabled = true;
533
+ element.data(NG_ANIMATE_STATE, data);
534
+ }
535
+ break;
536
+
537
+ case 1:
538
+ rootAnimateState.disabled = !value;
539
+ break;
540
+
541
+ default:
542
+ value = !rootAnimateState.disabled;
543
+ break;
544
+ }
545
+ return !!value;
546
+ }
547
+ };
548
+
549
+ /*
550
+ all animations call this shared animation triggering function internally.
551
+ The animationEvent variable refers to the JavaScript animation event that will be triggered
552
+ and the className value is the name of the animation that will be applied within the
553
+ CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
554
+ and the onComplete callback will be fired once the animation is fully complete.
555
+ */
556
+ function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
557
+ var classes = (element.attr('class') || '') + ' ' + className;
558
+ var animationLookup = (' ' + classes).replace(/\s+/g,'.');
559
+ if (!parentElement) {
560
+ parentElement = afterElement ? afterElement.parent() : element.parent();
561
+ }
562
+
563
+ var matches = lookup(animationLookup);
564
+ var isClassBased = animationEvent == 'addClass' || animationEvent == 'removeClass';
565
+ var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
566
+
567
+ //skip the animation if animations are disabled, a parent is already being animated,
568
+ //the element is not currently attached to the document body or then completely close
569
+ //the animation if any matching animations are not found at all.
570
+ //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
571
+ if (animationsDisabled(element, parentElement) || matches.length === 0) {
572
+ domOperation();
573
+ closeAnimation();
574
+ return;
575
+ }
576
+
577
+ var animations = [];
578
+ //only add animations if the currently running animation is not structural
579
+ //or if there is no animation running at all
580
+ if(!ngAnimateState.running || !(isClassBased && ngAnimateState.structural)) {
581
+ forEach(matches, function(animation) {
582
+ //add the animation to the queue to if it is allowed to be cancelled
583
+ if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) {
584
+ var beforeFn, afterFn = animation[animationEvent];
585
+
586
+ //Special case for a leave animation since there is no point in performing an
587
+ //animation on a element node that has already been removed from the DOM
588
+ if(animationEvent == 'leave') {
589
+ beforeFn = afterFn;
590
+ afterFn = null; //this must be falsy so that the animation is skipped for leave
591
+ } else {
592
+ beforeFn = animation['before' + animationEvent.charAt(0).toUpperCase() + animationEvent.substr(1)];
593
+ }
594
+ animations.push({
595
+ before : beforeFn,
596
+ after : afterFn
597
+ });
598
+ }
599
+ });
600
+ }
601
+
602
+ //this would mean that an animation was not allowed so let the existing
603
+ //animation do it's thing and close this one early
604
+ if(animations.length === 0) {
605
+ domOperation();
606
+ fireDoneCallbackAsync();
607
+ return;
608
+ }
609
+
610
+ if(ngAnimateState.running) {
611
+ //if an animation is currently running on the element then lets take the steps
612
+ //to cancel that animation and fire any required callbacks
613
+ $timeout.cancel(ngAnimateState.closeAnimationTimeout);
614
+ cleanup(element);
615
+ cancelAnimations(ngAnimateState.animations);
616
+ (ngAnimateState.done || noop)(true);
617
+ }
618
+
619
+ //There is no point in perform a class-based animation if the element already contains
620
+ //(on addClass) or doesn't contain (on removeClass) the className being animated.
621
+ //The reason why this is being called after the previous animations are cancelled
622
+ //is so that the CSS classes present on the element can be properly examined.
623
+ if((animationEvent == 'addClass' && element.hasClass(className)) ||
624
+ (animationEvent == 'removeClass' && !element.hasClass(className))) {
625
+ domOperation();
626
+ fireDoneCallbackAsync();
627
+ return;
628
+ }
629
+
630
+ //the ng-animate class does nothing, but it's here to allow for
631
+ //parent animations to find and cancel child animations when needed
632
+ element.addClass(NG_ANIMATE_CLASS_NAME);
633
+
634
+ element.data(NG_ANIMATE_STATE, {
635
+ running:true,
636
+ structural:!isClassBased,
637
+ animations:animations,
638
+ done:onBeforeAnimationsComplete
639
+ });
640
+
641
+ //first we run the before animations and when all of those are complete
642
+ //then we perform the DOM operation and run the next set of animations
643
+ invokeRegisteredAnimationFns(animations, 'before', onBeforeAnimationsComplete);
644
+
645
+ function onBeforeAnimationsComplete(cancelled) {
646
+ domOperation();
647
+ if(cancelled === true) {
648
+ closeAnimation();
649
+ return;
650
+ }
651
+
652
+ //set the done function to the final done function
653
+ //so that the DOM event won't be executed twice by accident
654
+ //if the after animation is cancelled as well
655
+ var data = element.data(NG_ANIMATE_STATE);
656
+ if(data) {
657
+ data.done = closeAnimation;
658
+ element.data(NG_ANIMATE_STATE, data);
659
+ }
660
+ invokeRegisteredAnimationFns(animations, 'after', closeAnimation);
661
+ }
662
+
663
+ function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) {
664
+ var endFnName = phase + 'End';
665
+ forEach(animations, function(animation, index) {
666
+ var animationPhaseCompleted = function() {
667
+ progress(index, phase);
668
+ };
669
+
670
+ //there are no before functions for enter + move since the DOM
671
+ //operations happen before the performAnimation method fires
672
+ if(phase == 'before' && (animationEvent == 'enter' || animationEvent == 'move')) {
673
+ animationPhaseCompleted();
674
+ return;
675
+ }
676
+
677
+ if(animation[phase]) {
678
+ animation[endFnName] = isClassBased ?
679
+ animation[phase](element, className, animationPhaseCompleted) :
680
+ animation[phase](element, animationPhaseCompleted);
681
+ } else {
682
+ animationPhaseCompleted();
683
+ }
684
+ });
685
+
686
+ function progress(index, phase) {
687
+ var phaseCompletionFlag = phase + 'Complete';
688
+ var currentAnimation = animations[index];
689
+ currentAnimation[phaseCompletionFlag] = true;
690
+ (currentAnimation[endFnName] || noop)();
691
+
692
+ for(var i=0;i<animations.length;i++) {
693
+ if(!animations[i][phaseCompletionFlag]) return;
694
+ }
695
+
696
+ allAnimationFnsComplete();
697
+ }
698
+ }
699
+
700
+ function fireDoneCallbackAsync() {
701
+ doneCallback && $timeout(doneCallback, 0, false);
702
+ }
703
+
704
+ function closeAnimation() {
705
+ if(!closeAnimation.hasBeenRun) {
706
+ closeAnimation.hasBeenRun = true;
707
+ var data = element.data(NG_ANIMATE_STATE);
708
+ if(data) {
709
+ /* only structural animations wait for reflow before removing an
710
+ animation, but class-based animations don't. An example of this
711
+ failing would be when a parent HTML tag has a ng-class attribute
712
+ causing ALL directives below to skip animations during the digest */
713
+ if(isClassBased) {
714
+ cleanup(element);
715
+ } else {
716
+ data.closeAnimationTimeout = $timeout(function() {
717
+ cleanup(element);
718
+ }, 0, false);
719
+ element.data(NG_ANIMATE_STATE, data);
720
+ }
721
+ }
722
+ fireDoneCallbackAsync();
723
+ }
724
+ }
725
+ }
726
+
727
+ function cancelChildAnimations(element) {
728
+ var node = element[0];
729
+ if(node.nodeType != ELEMENT_NODE) {
730
+ return;
731
+ }
732
+
733
+ forEach(node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME), function(element) {
734
+ element = angular.element(element);
735
+ var data = element.data(NG_ANIMATE_STATE);
736
+ if(data) {
737
+ cancelAnimations(data.animations);
738
+ cleanup(element);
739
+ }
740
+ });
741
+ }
742
+
743
+ function cancelAnimations(animations) {
744
+ var isCancelledFlag = true;
745
+ forEach(animations, function(animation) {
746
+ if(!animations['beforeComplete']) {
747
+ (animation.beforeEnd || noop)(isCancelledFlag);
748
+ }
749
+ if(!animations['afterComplete']) {
750
+ (animation.afterEnd || noop)(isCancelledFlag);
751
+ }
752
+ });
753
+ }
754
+
755
+ function cleanup(element) {
756
+ if(element[0] == $rootElement[0]) {
757
+ if(!rootAnimateState.disabled) {
758
+ rootAnimateState.running = false;
759
+ rootAnimateState.structural = false;
760
+ }
761
+ } else {
762
+ element.removeClass(NG_ANIMATE_CLASS_NAME);
763
+ element.removeData(NG_ANIMATE_STATE);
764
+ }
765
+ }
766
+
767
+ function animationsDisabled(element, parentElement) {
768
+ if (rootAnimateState.disabled) return true;
769
+
770
+ if(element[0] == $rootElement[0]) {
771
+ return rootAnimateState.disabled || rootAnimateState.running;
772
+ }
773
+
774
+ do {
775
+ //the element did not reach the root element which means that it
776
+ //is not apart of the DOM. Therefore there is no reason to do
777
+ //any animations on it
778
+ if(parentElement.length === 0) break;
779
+
780
+ var isRoot = parentElement[0] == $rootElement[0];
781
+ var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
782
+ var result = state && (!!state.disabled || !!state.running);
783
+ if(isRoot || result) {
784
+ return result;
785
+ }
786
+
787
+ if(isRoot) return true;
788
+ }
789
+ while(parentElement = parentElement.parent());
790
+
791
+ return true;
792
+ }
793
+ }]);
794
+
795
+ $animateProvider.register('', ['$window', '$sniffer', '$timeout', function($window, $sniffer, $timeout) {
796
+ // Detect proper transitionend/animationend event names.
797
+ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
798
+
799
+ // If unprefixed events are not supported but webkit-prefixed are, use the latter.
800
+ // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
801
+ // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
802
+ // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
803
+ // Register both events in case `window.onanimationend` is not supported because of that,
804
+ // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
805
+ // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
806
+ // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
807
+ if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
808
+ CSS_PREFIX = '-webkit-';
809
+ TRANSITION_PROP = 'WebkitTransition';
810
+ TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
811
+ } else {
812
+ TRANSITION_PROP = 'transition';
813
+ TRANSITIONEND_EVENT = 'transitionend';
814
+ }
815
+
816
+ if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
817
+ CSS_PREFIX = '-webkit-';
818
+ ANIMATION_PROP = 'WebkitAnimation';
819
+ ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
820
+ } else {
821
+ ANIMATION_PROP = 'animation';
822
+ ANIMATIONEND_EVENT = 'animationend';
823
+ }
824
+
825
+ var DURATION_KEY = 'Duration';
826
+ var PROPERTY_KEY = 'Property';
827
+ var DELAY_KEY = 'Delay';
828
+ var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
829
+ var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
830
+ var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
831
+ var NG_ANIMATE_FALLBACK_CLASS_NAME = 'ng-animate-start';
832
+ var NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME = 'ng-animate-active';
833
+
834
+ var lookupCache = {};
835
+ var parentCounter = 0;
836
+
837
+ var animationReflowQueue = [], animationTimer, timeOut = false;
838
+ function afterReflow(callback) {
839
+ animationReflowQueue.push(callback);
840
+ $timeout.cancel(animationTimer);
841
+ animationTimer = $timeout(function() {
842
+ forEach(animationReflowQueue, function(fn) {
843
+ fn();
844
+ });
845
+ animationReflowQueue = [];
846
+ animationTimer = null;
847
+ lookupCache = {};
848
+ }, 10, false);
849
+ }
850
+
851
+ function applyStyle(node, style) {
852
+ var oldStyle = node.getAttribute('style') || '';
853
+ var newStyle = (oldStyle.length > 0 ? '; ' : '') + style;
854
+ node.setAttribute('style', newStyle);
855
+ return oldStyle;
856
+ }
857
+
858
+ function getElementAnimationDetails(element, cacheKey) {
859
+ var data = cacheKey ? lookupCache[cacheKey] : null;
860
+ if(!data) {
861
+ var transitionDuration = 0;
862
+ var transitionDelay = 0;
863
+ var animationDuration = 0;
864
+ var animationDelay = 0;
865
+ var transitionDelayStyle;
866
+ var animationDelayStyle;
867
+ var transitionDurationStyle;
868
+ var transitionPropertyStyle;
869
+
870
+ //we want all the styles defined before and after
871
+ forEach(element, function(element) {
872
+ if (element.nodeType == ELEMENT_NODE) {
873
+ var elementStyles = $window.getComputedStyle(element) || {};
874
+
875
+ transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
876
+
877
+ transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
878
+
879
+ transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
880
+
881
+ transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
882
+
883
+ transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
884
+
885
+ animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
886
+
887
+ animationDelay = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
888
+
889
+ var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
890
+
891
+ if(aDuration > 0) {
892
+ aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
893
+ }
894
+
895
+ animationDuration = Math.max(aDuration, animationDuration);
896
+ }
897
+ });
898
+ data = {
899
+ total : 0,
900
+ transitionPropertyStyle: transitionPropertyStyle,
901
+ transitionDurationStyle: transitionDurationStyle,
902
+ transitionDelayStyle: transitionDelayStyle,
903
+ transitionDelay: transitionDelay,
904
+ transitionDuration: transitionDuration,
905
+ animationDelayStyle: animationDelayStyle,
906
+ animationDelay: animationDelay,
907
+ animationDuration: animationDuration
908
+ };
909
+ if(cacheKey) {
910
+ lookupCache[cacheKey] = data;
911
+ }
912
+ }
913
+ return data;
914
+ }
915
+
916
+ function parseMaxTime(str) {
917
+ var maxValue = 0;
918
+ var values = angular.isString(str) ?
919
+ str.split(/\s*,\s*/) :
920
+ [];
921
+ forEach(values, function(value) {
922
+ maxValue = Math.max(parseFloat(value) || 0, maxValue);
923
+ });
924
+ return maxValue;
925
+ }
926
+
927
+ function getCacheKey(element) {
928
+ var parentElement = element.parent();
929
+ var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
930
+ if(!parentID) {
931
+ parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
932
+ parentID = parentCounter;
933
+ }
934
+ return parentID + '-' + element[0].className;
935
+ }
936
+
937
+ function animateSetup(element, className) {
938
+ var cacheKey = getCacheKey(element);
939
+ var eventCacheKey = cacheKey + ' ' + className;
940
+ var stagger = {};
941
+ var ii = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
942
+
943
+ if(ii > 0) {
944
+ var staggerClassName = className + '-stagger';
945
+ var staggerCacheKey = cacheKey + ' ' + staggerClassName;
946
+ var applyClasses = !lookupCache[staggerCacheKey];
947
+
948
+ applyClasses && element.addClass(staggerClassName);
949
+
950
+ stagger = getElementAnimationDetails(element, staggerCacheKey);
951
+
952
+ applyClasses && element.removeClass(staggerClassName);
953
+ }
954
+
955
+ element.addClass(className);
956
+
957
+ var timings = getElementAnimationDetails(element, eventCacheKey);
958
+
959
+ /* there is no point in performing a reflow if the animation
960
+ timeout is empty (this would cause a flicker bug normally
961
+ in the page. There is also no point in performing an animation
962
+ that only has a delay and no duration */
963
+ var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
964
+ if(maxDuration === 0) {
965
+ element.removeClass(className);
966
+ return false;
967
+ }
968
+
969
+ var node = element[0];
970
+ //temporarily disable the transition so that the enter styles
971
+ //don't animate twice (this is here to avoid a bug in Chrome/FF).
972
+ var activeClassName = '';
973
+ if(timings.transitionDuration > 0) {
974
+ element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
975
+ activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
976
+ node.style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
977
+ }
978
+
979
+ forEach(className.split(' '), function(klass, i) {
980
+ activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
981
+ });
982
+
983
+ element.data(NG_ANIMATE_CSS_DATA_KEY, {
984
+ className : className,
985
+ activeClassName : activeClassName,
986
+ maxDuration : maxDuration,
987
+ classes : className + ' ' + activeClassName,
988
+ timings : timings,
989
+ stagger : stagger,
990
+ ii : ii
991
+ });
992
+
993
+ return true;
994
+ }
995
+
996
+ function animateRun(element, className, activeAnimationComplete) {
997
+ var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
998
+ if(!element.hasClass(className) || !data) {
999
+ activeAnimationComplete();
1000
+ return;
1001
+ }
1002
+
1003
+ var node = element[0];
1004
+ var timings = data.timings;
1005
+ var stagger = data.stagger;
1006
+ var maxDuration = data.maxDuration;
1007
+ var activeClassName = data.activeClassName;
1008
+ var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000;
1009
+ var startTime = Date.now();
1010
+ var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
1011
+ var formerStyle;
1012
+ var ii = data.ii;
1013
+
1014
+ var applyFallbackStyle, style = '';
1015
+ if(timings.transitionDuration > 0) {
1016
+ node.style[TRANSITION_PROP + PROPERTY_KEY] = '';
1017
+
1018
+ var propertyStyle = timings.transitionPropertyStyle;
1019
+ if(propertyStyle.indexOf('all') == -1) {
1020
+ applyFallbackStyle = true;
1021
+ var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'clip';
1022
+ style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
1023
+ style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
1024
+ }
1025
+ }
1026
+
1027
+ if(ii > 0) {
1028
+ if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
1029
+ var delayStyle = timings.transitionDelayStyle;
1030
+ if(applyFallbackStyle) {
1031
+ delayStyle += ', ' + timings.transitionDelay + 's';
1032
+ }
1033
+
1034
+ style += CSS_PREFIX + 'transition-delay: ' +
1035
+ prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
1036
+ }
1037
+
1038
+ if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
1039
+ style += CSS_PREFIX + 'animation-delay: ' +
1040
+ prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; ';
1041
+ }
1042
+ }
1043
+
1044
+ if(style.length > 0) {
1045
+ formerStyle = applyStyle(node, style);
1046
+ }
1047
+
1048
+ element.on(css3AnimationEvents, onAnimationProgress);
1049
+ element.addClass(activeClassName);
1050
+
1051
+ // This will automatically be called by $animate so
1052
+ // there is no need to attach this internally to the
1053
+ // timeout done method.
1054
+ return function onEnd(cancelled) {
1055
+ element.off(css3AnimationEvents, onAnimationProgress);
1056
+ element.removeClass(activeClassName);
1057
+ animateClose(element, className);
1058
+ if(formerStyle != null) {
1059
+ formerStyle.length > 0 ?
1060
+ node.setAttribute('style', formerStyle) :
1061
+ node.removeAttribute('style');
1062
+ }
1063
+ };
1064
+
1065
+ function onAnimationProgress(event) {
1066
+ event.stopPropagation();
1067
+ var ev = event.originalEvent || event;
1068
+ var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
1069
+ /* $manualTimeStamp is a mocked timeStamp value which is set
1070
+ * within browserTrigger(). This is only here so that tests can
1071
+ * mock animations properly. Real events fallback to event.timeStamp,
1072
+ * or, if they don't, then a timeStamp is automatically created for them.
1073
+ * We're checking to see if the timeStamp surpasses the expected delay,
1074
+ * but we're using elapsedTime instead of the timeStamp on the 2nd
1075
+ * pre-condition since animations sometimes close off early */
1076
+ if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && ev.elapsedTime >= maxDuration) {
1077
+ activeAnimationComplete();
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ function prepareStaggerDelay(delayStyle, staggerDelay, index) {
1083
+ var style = '';
1084
+ forEach(delayStyle.split(','), function(val, i) {
1085
+ style += (i > 0 ? ',' : '') +
1086
+ (index * staggerDelay + parseInt(val, 10)) + 's';
1087
+ });
1088
+ return style;
1089
+ }
1090
+
1091
+ function animateBefore(element, className) {
1092
+ if(animateSetup(element, className)) {
1093
+ return function(cancelled) {
1094
+ cancelled && animateClose(element, className);
1095
+ };
1096
+ }
1097
+ }
1098
+
1099
+ function animateAfter(element, className, afterAnimationComplete) {
1100
+ if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
1101
+ return animateRun(element, className, afterAnimationComplete);
1102
+ } else {
1103
+ animateClose(element, className);
1104
+ afterAnimationComplete();
1105
+ }
1106
+ }
1107
+
1108
+ function animate(element, className, animationComplete) {
1109
+ //If the animateSetup function doesn't bother returning a
1110
+ //cancellation function then it means that there is no animation
1111
+ //to perform at all
1112
+ var preReflowCancellation = animateBefore(element, className);
1113
+ if(!preReflowCancellation) {
1114
+ animationComplete();
1115
+ return;
1116
+ }
1117
+
1118
+ //There are two cancellation functions: one is before the first
1119
+ //reflow animation and the second is during the active state
1120
+ //animation. The first function will take care of removing the
1121
+ //data from the element which will not make the 2nd animation
1122
+ //happen in the first place
1123
+ var cancel = preReflowCancellation;
1124
+ afterReflow(function() {
1125
+ //once the reflow is complete then we point cancel to
1126
+ //the new cancellation function which will remove all of the
1127
+ //animation properties from the active animation
1128
+ cancel = animateAfter(element, className, animationComplete);
1129
+ });
1130
+
1131
+ return function(cancelled) {
1132
+ (cancel || noop)(cancelled);
1133
+ };
1134
+ }
1135
+
1136
+ function animateClose(element, className) {
1137
+ element.removeClass(className);
1138
+ element.removeClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
1139
+ element.removeData(NG_ANIMATE_CSS_DATA_KEY);
1140
+ }
1141
+
1142
+ return {
1143
+ allowCancel : function(element, animationEvent, className) {
1144
+ //always cancel the current animation if it is a
1145
+ //structural animation
1146
+ var oldClasses = (element.data(NG_ANIMATE_CSS_DATA_KEY) || {}).classes;
1147
+ if(!oldClasses || ['enter','leave','move'].indexOf(animationEvent) >= 0) {
1148
+ return true;
1149
+ }
1150
+
1151
+ var parentElement = element.parent();
1152
+ var clone = angular.element(element[0].cloneNode());
1153
+
1154
+ //make the element super hidden and override any CSS style values
1155
+ clone.attr('style','position:absolute; top:-9999px; left:-9999px');
1156
+ clone.removeAttr('id');
1157
+ clone.html('');
1158
+
1159
+ forEach(oldClasses.split(' '), function(klass) {
1160
+ clone.removeClass(klass);
1161
+ });
1162
+
1163
+ var suffix = animationEvent == 'addClass' ? '-add' : '-remove';
1164
+ clone.addClass(suffixClasses(className, suffix));
1165
+ parentElement.append(clone);
1166
+
1167
+ var timings = getElementAnimationDetails(clone);
1168
+ clone.remove();
1169
+
1170
+ return Math.max(timings.transitionDuration, timings.animationDuration) > 0;
1171
+ },
1172
+
1173
+ enter : function(element, animationCompleted) {
1174
+ return animate(element, 'ng-enter', animationCompleted);
1175
+ },
1176
+
1177
+ leave : function(element, animationCompleted) {
1178
+ return animate(element, 'ng-leave', animationCompleted);
1179
+ },
1180
+
1181
+ move : function(element, animationCompleted) {
1182
+ return animate(element, 'ng-move', animationCompleted);
1183
+ },
1184
+
1185
+ beforeAddClass : function(element, className, animationCompleted) {
1186
+ var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
1187
+ if(cancellationMethod) {
1188
+ afterReflow(animationCompleted);
1189
+ return cancellationMethod;
1190
+ }
1191
+ animationCompleted();
1192
+ },
1193
+
1194
+ addClass : function(element, className, animationCompleted) {
1195
+ return animateAfter(element, suffixClasses(className, '-add'), animationCompleted);
1196
+ },
1197
+
1198
+ beforeRemoveClass : function(element, className, animationCompleted) {
1199
+ var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
1200
+ if(cancellationMethod) {
1201
+ afterReflow(animationCompleted);
1202
+ return cancellationMethod;
1203
+ }
1204
+ animationCompleted();
1205
+ },
1206
+
1207
+ removeClass : function(element, className, animationCompleted) {
1208
+ return animateAfter(element, suffixClasses(className, '-remove'), animationCompleted);
1209
+ }
1210
+ };
1211
+
1212
+ function suffixClasses(classes, suffix) {
1213
+ var className = '';
1214
+ classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
1215
+ forEach(classes, function(klass, i) {
1216
+ if(klass && klass.length > 0) {
1217
+ className += (i > 0 ? ' ' : '') + klass + suffix;
1218
+ }
1219
+ });
1220
+ return className;
1221
+ }
1222
+ }]);
1223
+ }]);
1224
+
1225
+
1226
+ })(window, window.angular);