praxis 0.0.1 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (484) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.simplecov +7 -0
  6. data/.travis.yml +4 -0
  7. data/CONTRIBUTING.md +183 -0
  8. data/Gemfile +3 -0
  9. data/Guardfile +8 -0
  10. data/LICENSE +22 -0
  11. data/MAINTAINERS +2 -0
  12. data/MAINTAINERS.md +86 -0
  13. data/README.md +69 -3
  14. data/Rakefile +18 -0
  15. data/bin/praxis +10 -0
  16. data/lib/api_browser/.bowerrc +3 -0
  17. data/lib/api_browser/.editorconfig +21 -0
  18. data/lib/api_browser/Gruntfile.js +264 -0
  19. data/lib/api_browser/app/bower_components/angular/.bower.json +16 -0
  20. data/lib/api_browser/app/bower_components/angular/README.md +48 -0
  21. data/lib/api_browser/app/bower_components/angular/angular-csp.css +18 -0
  22. data/lib/api_browser/app/bower_components/angular/angular.js +21464 -0
  23. data/lib/api_browser/app/bower_components/angular/angular.min.js +210 -0
  24. data/lib/api_browser/app/bower_components/angular/angular.min.js.gzip +0 -0
  25. data/lib/api_browser/app/bower_components/angular/angular.min.js.map +8 -0
  26. data/lib/api_browser/app/bower_components/angular/bower.json +7 -0
  27. data/lib/api_browser/app/bower_components/angular-sanitize/.bower.json +19 -0
  28. data/lib/api_browser/app/bower_components/angular-sanitize/README.md +54 -0
  29. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.js +624 -0
  30. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.min.js +14 -0
  31. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.min.js.map +8 -0
  32. data/lib/api_browser/app/bower_components/angular-sanitize/bower.json +8 -0
  33. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/.bower.json +24 -0
  34. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/bower.json +11 -0
  35. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.js +4116 -0
  36. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.min.js +10 -0
  37. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap.js +3799 -0
  38. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap.min.js +9 -0
  39. data/lib/api_browser/app/bower_components/angular-ui-router/.bower.json +34 -0
  40. data/lib/api_browser/app/bower_components/angular-ui-router/CHANGELOG.md +23 -0
  41. data/lib/api_browser/app/bower_components/angular-ui-router/LICENSE +21 -0
  42. data/lib/api_browser/app/bower_components/angular-ui-router/README.md +280 -0
  43. data/lib/api_browser/app/bower_components/angular-ui-router/bower.json +23 -0
  44. data/lib/api_browser/app/bower_components/angular-ui-router/release/angular-ui-router.js +3223 -0
  45. data/lib/api_browser/app/bower_components/angular-ui-router/release/angular-ui-router.min.js +7 -0
  46. data/lib/api_browser/app/bower_components/angular-ui-router/src/common.js +246 -0
  47. data/lib/api_browser/app/bower_components/angular-ui-router/src/compat.js +146 -0
  48. data/lib/api_browser/app/bower_components/angular-ui-router/src/resolve.js +242 -0
  49. data/lib/api_browser/app/bower_components/angular-ui-router/src/state.js +1204 -0
  50. data/lib/api_browser/app/bower_components/angular-ui-router/src/stateDirectives.js +226 -0
  51. data/lib/api_browser/app/bower_components/angular-ui-router/src/stateFilters.js +35 -0
  52. data/lib/api_browser/app/bower_components/angular-ui-router/src/templateFactory.js +110 -0
  53. data/lib/api_browser/app/bower_components/angular-ui-router/src/urlMatcherFactory.js +325 -0
  54. data/lib/api_browser/app/bower_components/angular-ui-router/src/urlRouter.js +273 -0
  55. data/lib/api_browser/app/bower_components/angular-ui-router/src/view.js +71 -0
  56. data/lib/api_browser/app/bower_components/angular-ui-router/src/viewDirective.js +290 -0
  57. data/lib/api_browser/app/bower_components/angular-ui-router/src/viewScroll.js +52 -0
  58. data/lib/api_browser/app/bower_components/bootstrap-sass/.bower.json +26 -0
  59. data/lib/api_browser/app/bower_components/bootstrap-sass/CNAME +1 -0
  60. data/lib/api_browser/app/bower_components/bootstrap-sass/CONTRIBUTING.md +61 -0
  61. data/lib/api_browser/app/bower_components/bootstrap-sass/DOCS-LICENSE +319 -0
  62. data/lib/api_browser/app/bower_components/bootstrap-sass/Gemfile +5 -0
  63. data/lib/api_browser/app/bower_components/bootstrap-sass/Gemfile.lock +14 -0
  64. data/lib/api_browser/app/bower_components/bootstrap-sass/Gruntfile.js +244 -0
  65. data/lib/api_browser/app/bower_components/bootstrap-sass/LICENSE +176 -0
  66. data/lib/api_browser/app/bower_components/bootstrap-sass/LICENSE-MIT +21 -0
  67. data/lib/api_browser/app/bower_components/bootstrap-sass/README.md +277 -0
  68. data/lib/api_browser/app/bower_components/bootstrap-sass/Rakefile +44 -0
  69. data/lib/api_browser/app/bower_components/bootstrap-sass/_config.yml +25 -0
  70. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/ads.html +1 -0
  71. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/footer.html +34 -0
  72. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/header.html +42 -0
  73. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-about.html +12 -0
  74. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-components.html +137 -0
  75. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-css.html +99 -0
  76. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-customize.html +40 -0
  77. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-getting-started.html +44 -0
  78. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-javascript.html +88 -0
  79. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-main.html +37 -0
  80. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/old-bs-docs.html +8 -0
  81. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/social-buttons.html +16 -0
  82. data/lib/api_browser/app/bower_components/bootstrap-sass/_layouts/default.html +79 -0
  83. data/lib/api_browser/app/bower_components/bootstrap-sass/_layouts/home.html +47 -0
  84. data/lib/api_browser/app/bower_components/bootstrap-sass/about.html +93 -0
  85. data/lib/api_browser/app/bower_components/bootstrap-sass/bower.json +11 -0
  86. data/lib/api_browser/app/bower_components/bootstrap-sass/browserstack.json +37 -0
  87. data/lib/api_browser/app/bower_components/bootstrap-sass/components.html +3689 -0
  88. data/lib/api_browser/app/bower_components/bootstrap-sass/composer.json +28 -0
  89. data/lib/api_browser/app/bower_components/bootstrap-sass/css.html +2674 -0
  90. data/lib/api_browser/app/bower_components/bootstrap-sass/customize.html +1715 -0
  91. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap-theme.css +427 -0
  92. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap-theme.min.css +1 -0
  93. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap.css +6350 -0
  94. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap.min.css +1 -0
  95. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  96. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/fonts/glyphicons-halflings-regular.svg +229 -0
  97. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  98. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  99. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/js/bootstrap.js +2002 -0
  100. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/js/bootstrap.min.js +9 -0
  101. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/css/docs.css +1195 -0
  102. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/css/pygments-manni.css +66 -0
  103. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  104. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/ico/favicon.png +0 -0
  105. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/application.js +103 -0
  106. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/customizer.js +332 -0
  107. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/filesaver.js +169 -0
  108. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/holder.js +404 -0
  109. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/ie8-responsive-file-warning.js +12 -0
  110. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/jszip.js +1467 -0
  111. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/less.js +9 -0
  112. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/raw-files.js +3 -0
  113. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/uglify.js +14 -0
  114. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/carousel/carousel.css +148 -0
  115. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/carousel/index.html +206 -0
  116. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/grid/grid.css +28 -0
  117. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/grid/index.html +148 -0
  118. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron/index.html +99 -0
  119. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron/jumbotron.css +5 -0
  120. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron-narrow/index.html +82 -0
  121. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron-narrow/jumbotron-narrow.css +79 -0
  122. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/justified-nav/index.html +83 -0
  123. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/justified-nav/justified-nav.css +88 -0
  124. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar/index.html +88 -0
  125. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar/navbar.css +8 -0
  126. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-fixed-top/index.html +91 -0
  127. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-fixed-top/navbar-fixed-top.css +4 -0
  128. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-static-top/index.html +92 -0
  129. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-static-top/navbar-static-top.css +7 -0
  130. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/non-responsive/index.html +101 -0
  131. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/non-responsive/non-responsive.css +116 -0
  132. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/index.html +130 -0
  133. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/offcanvas.css +50 -0
  134. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/offcanvas.js +5 -0
  135. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/carousel.jpg +0 -0
  136. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/grid.jpg +0 -0
  137. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/jumbotron-narrow.jpg +0 -0
  138. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/jumbotron.jpg +0 -0
  139. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/justified-nav.jpg +0 -0
  140. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar-fixed.jpg +0 -0
  141. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar-static.jpg +0 -0
  142. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar.jpg +0 -0
  143. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/non-responsive.jpg +0 -0
  144. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/offcanvas.jpg +0 -0
  145. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sign-in.jpg +0 -0
  146. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/starter-template.jpg +0 -0
  147. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sticky-footer-navbar.jpg +0 -0
  148. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sticky-footer.jpg +0 -0
  149. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/theme.jpg +0 -0
  150. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/signin/index.html +50 -0
  151. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/signin/signin.css +40 -0
  152. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/starter-template/index.html +68 -0
  153. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/starter-template/starter-template.css +7 -0
  154. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer/index.html +55 -0
  155. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer/sticky-footer.css +38 -0
  156. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer-navbar/index.html +91 -0
  157. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer-navbar/sticky-footer-navbar.css +45 -0
  158. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/theme/index.html +384 -0
  159. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/theme/theme.css +14 -0
  160. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.eot +0 -0
  161. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.svg +229 -0
  162. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.ttf +0 -0
  163. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.woff +0 -0
  164. data/lib/api_browser/app/bower_components/bootstrap-sass/getting-started.html +1021 -0
  165. data/lib/api_browser/app/bower_components/bootstrap-sass/index.html +16 -0
  166. data/lib/api_browser/app/bower_components/bootstrap-sass/javascript.html +1983 -0
  167. data/lib/api_browser/app/bower_components/bootstrap-sass/js/affix.js +126 -0
  168. data/lib/api_browser/app/bower_components/bootstrap-sass/js/alert.js +98 -0
  169. data/lib/api_browser/app/bower_components/bootstrap-sass/js/button.js +109 -0
  170. data/lib/api_browser/app/bower_components/bootstrap-sass/js/carousel.js +217 -0
  171. data/lib/api_browser/app/bower_components/bootstrap-sass/js/collapse.js +179 -0
  172. data/lib/api_browser/app/bower_components/bootstrap-sass/js/dropdown.js +154 -0
  173. data/lib/api_browser/app/bower_components/bootstrap-sass/js/modal.js +246 -0
  174. data/lib/api_browser/app/bower_components/bootstrap-sass/js/popover.js +117 -0
  175. data/lib/api_browser/app/bower_components/bootstrap-sass/js/scrollspy.js +158 -0
  176. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tab.js +135 -0
  177. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/index.html +52 -0
  178. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/affix.js +25 -0
  179. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/alert.js +62 -0
  180. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/button.js +116 -0
  181. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/carousel.js +87 -0
  182. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/collapse.js +164 -0
  183. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/dropdown.js +219 -0
  184. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/modal.js +196 -0
  185. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/phantom.js +69 -0
  186. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/popover.js +133 -0
  187. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/scrollspy.js +37 -0
  188. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/tab.js +86 -0
  189. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/tooltip.js +437 -0
  190. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/transition.js +13 -0
  191. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/jquery.js +6 -0
  192. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/qunit.css +232 -0
  193. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/qunit.js +1510 -0
  194. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tooltip.js +386 -0
  195. data/lib/api_browser/app/bower_components/bootstrap-sass/js/transition.js +56 -0
  196. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_alerts.scss +67 -0
  197. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_badges.scss +51 -0
  198. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_breadcrumbs.scss +23 -0
  199. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_button-groups.scss +253 -0
  200. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_buttons.scss +158 -0
  201. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_carousel.scss +231 -0
  202. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_close.scss +35 -0
  203. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_code.scss +53 -0
  204. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_component-animations.scss +29 -0
  205. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_dropdowns.scss +193 -0
  206. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_forms.scss +363 -0
  207. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_glyphicons.scss +237 -0
  208. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_grid.scss +93 -0
  209. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_input-groups.scss +136 -0
  210. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_jumbotron.scss +40 -0
  211. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_labels.scss +58 -0
  212. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_list-group.scss +88 -0
  213. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_media.scss +56 -0
  214. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_mixins.scss +861 -0
  215. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_modals.scss +132 -0
  216. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_navbar.scss +628 -0
  217. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_navs.scss +262 -0
  218. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_normalize.scss +406 -0
  219. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_pager.scss +55 -0
  220. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_pagination.scss +85 -0
  221. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_panels.scss +172 -0
  222. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_popovers.scss +133 -0
  223. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_print.scss +105 -0
  224. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_progress-bars.scss +92 -0
  225. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_responsive-utilities.scss +198 -0
  226. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_scaffolding.scss +119 -0
  227. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_tables.scss +244 -0
  228. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_theme.scss +247 -0
  229. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_thumbnails.scss +32 -0
  230. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_tooltip.scss +95 -0
  231. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_type.scss +279 -0
  232. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_utilities.scss +56 -0
  233. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_variables.scss +637 -0
  234. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/_wells.scss +29 -0
  235. data/lib/api_browser/app/bower_components/bootstrap-sass/lib/bootstrap.scss +49 -0
  236. data/lib/api_browser/app/bower_components/bootstrap-sass/package.json +40 -0
  237. data/lib/api_browser/app/bower_components/jquery/.bower.json +38 -0
  238. data/lib/api_browser/app/bower_components/jquery/MIT-LICENSE.txt +21 -0
  239. data/lib/api_browser/app/bower_components/jquery/bower.json +27 -0
  240. data/lib/api_browser/app/bower_components/jquery/dist/jquery.js +9190 -0
  241. data/lib/api_browser/app/bower_components/jquery/dist/jquery.min.js +5 -0
  242. data/lib/api_browser/app/bower_components/jquery/dist/jquery.min.map +1 -0
  243. data/lib/api_browser/app/bower_components/jquery/src/ajax/jsonp.js +89 -0
  244. data/lib/api_browser/app/bower_components/jquery/src/ajax/load.js +75 -0
  245. data/lib/api_browser/app/bower_components/jquery/src/ajax/parseJSON.js +13 -0
  246. data/lib/api_browser/app/bower_components/jquery/src/ajax/parseXML.js +28 -0
  247. data/lib/api_browser/app/bower_components/jquery/src/ajax/script.js +64 -0
  248. data/lib/api_browser/app/bower_components/jquery/src/ajax/var/nonce.js +5 -0
  249. data/lib/api_browser/app/bower_components/jquery/src/ajax/var/rquery.js +3 -0
  250. data/lib/api_browser/app/bower_components/jquery/src/ajax/xhr.js +135 -0
  251. data/lib/api_browser/app/bower_components/jquery/src/ajax.js +806 -0
  252. data/lib/api_browser/app/bower_components/jquery/src/attributes/attr.js +143 -0
  253. data/lib/api_browser/app/bower_components/jquery/src/attributes/classes.js +158 -0
  254. data/lib/api_browser/app/bower_components/jquery/src/attributes/prop.js +96 -0
  255. data/lib/api_browser/app/bower_components/jquery/src/attributes/support.js +35 -0
  256. data/lib/api_browser/app/bower_components/jquery/src/attributes/val.js +163 -0
  257. data/lib/api_browser/app/bower_components/jquery/src/attributes.js +11 -0
  258. data/lib/api_browser/app/bower_components/jquery/src/callbacks.js +205 -0
  259. data/lib/api_browser/app/bower_components/jquery/src/core/access.js +60 -0
  260. data/lib/api_browser/app/bower_components/jquery/src/core/init.js +123 -0
  261. data/lib/api_browser/app/bower_components/jquery/src/core/parseHTML.js +39 -0
  262. data/lib/api_browser/app/bower_components/jquery/src/core/ready.js +97 -0
  263. data/lib/api_browser/app/bower_components/jquery/src/core/var/rsingleTag.js +4 -0
  264. data/lib/api_browser/app/bower_components/jquery/src/core.js +498 -0
  265. data/lib/api_browser/app/bower_components/jquery/src/css/addGetHookIf.js +24 -0
  266. data/lib/api_browser/app/bower_components/jquery/src/css/curCSS.js +57 -0
  267. data/lib/api_browser/app/bower_components/jquery/src/css/defaultDisplay.js +70 -0
  268. data/lib/api_browser/app/bower_components/jquery/src/css/hiddenVisibleSelectors.js +15 -0
  269. data/lib/api_browser/app/bower_components/jquery/src/css/support.js +91 -0
  270. data/lib/api_browser/app/bower_components/jquery/src/css/swap.js +28 -0
  271. data/lib/api_browser/app/bower_components/jquery/src/css/var/cssExpand.js +3 -0
  272. data/lib/api_browser/app/bower_components/jquery/src/css/var/getStyles.js +5 -0
  273. data/lib/api_browser/app/bower_components/jquery/src/css/var/isHidden.js +13 -0
  274. data/lib/api_browser/app/bower_components/jquery/src/css/var/rmargin.js +3 -0
  275. data/lib/api_browser/app/bower_components/jquery/src/css/var/rnumnonpx.js +5 -0
  276. data/lib/api_browser/app/bower_components/jquery/src/css.js +451 -0
  277. data/lib/api_browser/app/bower_components/jquery/src/data/Data.js +181 -0
  278. data/lib/api_browser/app/bower_components/jquery/src/data/accepts.js +20 -0
  279. data/lib/api_browser/app/bower_components/jquery/src/data/var/data_priv.js +5 -0
  280. data/lib/api_browser/app/bower_components/jquery/src/data/var/data_user.js +5 -0
  281. data/lib/api_browser/app/bower_components/jquery/src/data.js +179 -0
  282. data/lib/api_browser/app/bower_components/jquery/src/deferred.js +149 -0
  283. data/lib/api_browser/app/bower_components/jquery/src/deprecated.js +13 -0
  284. data/lib/api_browser/app/bower_components/jquery/src/dimensions.js +50 -0
  285. data/lib/api_browser/app/bower_components/jquery/src/effects/Tween.js +114 -0
  286. data/lib/api_browser/app/bower_components/jquery/src/effects/animatedSelector.js +13 -0
  287. data/lib/api_browser/app/bower_components/jquery/src/effects.js +649 -0
  288. data/lib/api_browser/app/bower_components/jquery/src/event/alias.js +39 -0
  289. data/lib/api_browser/app/bower_components/jquery/src/event/support.js +9 -0
  290. data/lib/api_browser/app/bower_components/jquery/src/event.js +868 -0
  291. data/lib/api_browser/app/bower_components/jquery/src/exports/amd.js +24 -0
  292. data/lib/api_browser/app/bower_components/jquery/src/exports/global.js +32 -0
  293. data/lib/api_browser/app/bower_components/jquery/src/intro.js +44 -0
  294. data/lib/api_browser/app/bower_components/jquery/src/jquery.js +36 -0
  295. data/lib/api_browser/app/bower_components/jquery/src/manipulation/_evalUrl.js +18 -0
  296. data/lib/api_browser/app/bower_components/jquery/src/manipulation/support.js +31 -0
  297. data/lib/api_browser/app/bower_components/jquery/src/manipulation/var/rcheckableType.js +3 -0
  298. data/lib/api_browser/app/bower_components/jquery/src/manipulation.js +582 -0
  299. data/lib/api_browser/app/bower_components/jquery/src/offset.js +204 -0
  300. data/lib/api_browser/app/bower_components/jquery/src/outro.js +1 -0
  301. data/lib/api_browser/app/bower_components/jquery/src/queue/delay.js +22 -0
  302. data/lib/api_browser/app/bower_components/jquery/src/queue.js +142 -0
  303. data/lib/api_browser/app/bower_components/jquery/src/selector-native.js +172 -0
  304. data/lib/api_browser/app/bower_components/jquery/src/selector-sizzle.js +14 -0
  305. data/lib/api_browser/app/bower_components/jquery/src/selector.js +1 -0
  306. data/lib/api_browser/app/bower_components/jquery/src/serialize.js +111 -0
  307. data/lib/api_browser/app/bower_components/jquery/src/sizzle/dist/sizzle.js +2044 -0
  308. data/lib/api_browser/app/bower_components/jquery/src/sizzle/dist/sizzle.min.js +3 -0
  309. data/lib/api_browser/app/bower_components/jquery/src/sizzle/dist/sizzle.min.map +1 -0
  310. data/lib/api_browser/app/bower_components/jquery/src/traversing/findFilter.js +100 -0
  311. data/lib/api_browser/app/bower_components/jquery/src/traversing/var/rneedsContext.js +6 -0
  312. data/lib/api_browser/app/bower_components/jquery/src/traversing.js +200 -0
  313. data/lib/api_browser/app/bower_components/jquery/src/var/arr.js +3 -0
  314. data/lib/api_browser/app/bower_components/jquery/src/var/class2type.js +4 -0
  315. data/lib/api_browser/app/bower_components/jquery/src/var/concat.js +5 -0
  316. data/lib/api_browser/app/bower_components/jquery/src/var/hasOwn.js +5 -0
  317. data/lib/api_browser/app/bower_components/jquery/src/var/indexOf.js +5 -0
  318. data/lib/api_browser/app/bower_components/jquery/src/var/pnum.js +3 -0
  319. data/lib/api_browser/app/bower_components/jquery/src/var/push.js +5 -0
  320. data/lib/api_browser/app/bower_components/jquery/src/var/rnotwhite.js +3 -0
  321. data/lib/api_browser/app/bower_components/jquery/src/var/slice.js +5 -0
  322. data/lib/api_browser/app/bower_components/jquery/src/var/strundefined.js +3 -0
  323. data/lib/api_browser/app/bower_components/jquery/src/var/support.js +4 -0
  324. data/lib/api_browser/app/bower_components/jquery/src/var/toString.js +5 -0
  325. data/lib/api_browser/app/bower_components/jquery/src/wrap.js +78 -0
  326. data/lib/api_browser/app/bower_components/lodash/.bower.json +34 -0
  327. data/lib/api_browser/app/bower_components/lodash/LICENSE.txt +22 -0
  328. data/lib/api_browser/app/bower_components/lodash/bower.json +23 -0
  329. data/lib/api_browser/app/bower_components/lodash/dist/lodash.compat.js +7157 -0
  330. data/lib/api_browser/app/bower_components/lodash/dist/lodash.compat.min.js +61 -0
  331. data/lib/api_browser/app/bower_components/lodash/dist/lodash.js +6785 -0
  332. data/lib/api_browser/app/bower_components/lodash/dist/lodash.min.js +56 -0
  333. data/lib/api_browser/app/bower_components/lodash/dist/lodash.underscore.js +4979 -0
  334. data/lib/api_browser/app/bower_components/lodash/dist/lodash.underscore.min.js +39 -0
  335. data/lib/api_browser/app/css/main.css +4510 -0
  336. data/lib/api_browser/app/index.html +51 -0
  337. data/lib/api_browser/app/js/app.js +32 -0
  338. data/lib/api_browser/app/js/controllers/action.js +51 -0
  339. data/lib/api_browser/app/js/controllers/controller.js +10 -0
  340. data/lib/api_browser/app/js/controllers/menu.js +49 -0
  341. data/lib/api_browser/app/js/controllers/type.js +28 -0
  342. data/lib/api_browser/app/js/directives/attribute_description.js +43 -0
  343. data/lib/api_browser/app/js/directives/attribute_table.js +27 -0
  344. data/lib/api_browser/app/js/directives/attribute_table_row.js +17 -0
  345. data/lib/api_browser/app/js/directives/no_container.js +8 -0
  346. data/lib/api_browser/app/js/directives/request_body.js +25 -0
  347. data/lib/api_browser/app/js/directives/request_headers.js +20 -0
  348. data/lib/api_browser/app/js/directives/request_parameters.js +20 -0
  349. data/lib/api_browser/app/js/directives/type_label.js +53 -0
  350. data/lib/api_browser/app/js/factories/Documentation.js +16 -0
  351. data/lib/api_browser/app/js/factories/PayloadTemplates.js +10 -0
  352. data/lib/api_browser/app/js/factories/TemplateProvider.js +45 -0
  353. data/lib/api_browser/app/js/factories/TypeTemplates.js +11 -0
  354. data/lib/api_browser/app/js/filters/attribute_name.js +9 -0
  355. data/lib/api_browser/app/js/filters/friendly_json.js +5 -0
  356. data/lib/api_browser/app/js/filters/is_empty.js +8 -0
  357. data/lib/api_browser/app/js/filters/resource_name.js +5 -0
  358. data/lib/api_browser/app/sass/main.scss +59 -0
  359. data/lib/api_browser/app/sass/modules/_body.scss +11 -0
  360. data/lib/api_browser/app/sass/modules/_cloke.scss +8 -0
  361. data/lib/api_browser/app/sass/modules/_header.scss +15 -0
  362. data/lib/api_browser/app/sass/modules/_nav.scss +7 -0
  363. data/lib/api_browser/app/sass/modules/_sidebar.scss +26 -0
  364. data/lib/api_browser/app/sass/modules/_switch.scss +55 -0
  365. data/lib/api_browser/app/sass/modules/_table.scss +13 -0
  366. data/lib/api_browser/app/sass/variables/_bootstrap-variables.scss +762 -0
  367. data/lib/api_browser/app/views/action.html +83 -0
  368. data/lib/api_browser/app/views/controller.html +24 -0
  369. data/lib/api_browser/app/views/directives/attribute_description/_default.html +2 -0
  370. data/lib/api_browser/app/views/directives/attribute_description/_example.html +8 -0
  371. data/lib/api_browser/app/views/directives/attribute_description/_headers.html +8 -0
  372. data/lib/api_browser/app/views/directives/attribute_description.html +2 -0
  373. data/lib/api_browser/app/views/directives/attribute_table.html +23 -0
  374. data/lib/api_browser/app/views/directives/attribute_table_row/_default.html +10 -0
  375. data/lib/api_browser/app/views/directives/attribute_table_row/_links.html +10 -0
  376. data/lib/api_browser/app/views/directives/attribute_table_row/_struct.html +2 -0
  377. data/lib/api_browser/app/views/directives/request_body/_default.html +20 -0
  378. data/lib/api_browser/app/views/directives/request_body/_struct.html +1 -0
  379. data/lib/api_browser/app/views/home.html +7 -0
  380. data/lib/api_browser/app/views/layout.html +50 -0
  381. data/lib/api_browser/app/views/resource/_actions.html +23 -0
  382. data/lib/api_browser/app/views/type/_details.html +29 -0
  383. data/lib/api_browser/app/views/type.html +25 -0
  384. data/lib/api_browser/bower.json +26 -0
  385. data/lib/api_browser/package.json +30 -0
  386. data/lib/praxis/action_definition/headers_dsl_compiler.rb +36 -0
  387. data/lib/praxis/action_definition.rb +153 -0
  388. data/lib/praxis/api_definition.rb +59 -0
  389. data/lib/praxis/application.rb +65 -0
  390. data/lib/praxis/bootloader.rb +91 -0
  391. data/lib/praxis/bootloader_stages/environment.rb +57 -0
  392. data/lib/praxis/bootloader_stages/file_loader.rb +31 -0
  393. data/lib/praxis/bootloader_stages/routing.rb +34 -0
  394. data/lib/praxis/bootloader_stages/subgroup_loader.rb +27 -0
  395. data/lib/praxis/bootloader_stages/warn_unloaded_files.rb +40 -0
  396. data/lib/praxis/config.rb +92 -0
  397. data/lib/praxis/content_type_parser.rb +62 -0
  398. data/lib/praxis/controller.rb +59 -0
  399. data/lib/praxis/dispatcher.rb +102 -0
  400. data/lib/praxis/exception.rb +4 -0
  401. data/lib/praxis/exceptions/config.rb +6 -0
  402. data/lib/praxis/exceptions/config_load.rb +9 -0
  403. data/lib/praxis/exceptions/config_validation.rb +9 -0
  404. data/lib/praxis/exceptions/invalid_configuration.rb +6 -0
  405. data/lib/praxis/exceptions/invalid_response.rb +6 -0
  406. data/lib/praxis/exceptions/invalid_trait.rb +6 -0
  407. data/lib/praxis/exceptions/stage_not_found.rb +6 -0
  408. data/lib/praxis/exceptions/validation.rb +6 -0
  409. data/lib/praxis/file_group.rb +39 -0
  410. data/lib/praxis/links.rb +110 -0
  411. data/lib/praxis/media_type.rb +40 -0
  412. data/lib/praxis/media_type_collection.rb +120 -0
  413. data/lib/praxis/multipart/parser.rb +213 -0
  414. data/lib/praxis/multipart/part.rb +26 -0
  415. data/lib/praxis/plugin.rb +30 -0
  416. data/lib/praxis/request.rb +131 -0
  417. data/lib/praxis/request_stages/action.rb +20 -0
  418. data/lib/praxis/request_stages/load_request.rb +13 -0
  419. data/lib/praxis/request_stages/request_stage.rb +52 -0
  420. data/lib/praxis/request_stages/response.rb +26 -0
  421. data/lib/praxis/request_stages/validate.rb +20 -0
  422. data/lib/praxis/request_stages/validate_params_and_headers.rb +38 -0
  423. data/lib/praxis/request_stages/validate_payload.rb +32 -0
  424. data/lib/praxis/resource_definition.rb +89 -0
  425. data/lib/praxis/response.rb +107 -0
  426. data/lib/praxis/response_definition.rb +264 -0
  427. data/lib/praxis/response_template.rb +34 -0
  428. data/lib/praxis/responses/http.rb +166 -0
  429. data/lib/praxis/responses/validation_error.rb +36 -0
  430. data/lib/praxis/route.rb +27 -0
  431. data/lib/praxis/router.rb +89 -0
  432. data/lib/praxis/simple_media_type.rb +24 -0
  433. data/lib/praxis/skeletor/restful_routing_config.rb +45 -0
  434. data/lib/praxis/stage.rb +94 -0
  435. data/lib/praxis/tasks/api_docs.rb +336 -0
  436. data/lib/praxis/tasks/console.rb +11 -0
  437. data/lib/praxis/tasks/environment.rb +5 -0
  438. data/lib/praxis/tasks/routes.rb +45 -0
  439. data/lib/praxis/tasks.rb +4 -0
  440. data/lib/praxis/types/collection.rb +17 -0
  441. data/lib/praxis/types/multipart.rb +69 -0
  442. data/lib/praxis/version.rb +3 -0
  443. data/lib/praxis.rb +119 -1
  444. data/praxis.gemspec +50 -0
  445. data/spec/functional_spec.rb +186 -0
  446. data/spec/praxis/action_definition_spec.rb +134 -0
  447. data/spec/praxis/api_resource_spec.rb +0 -0
  448. data/spec/praxis/application_spec.rb +46 -0
  449. data/spec/praxis/bootloader_spec.rb +58 -0
  450. data/spec/praxis/config_spec.rb +118 -0
  451. data/spec/praxis/content_type_parser_spec.rb +91 -0
  452. data/spec/praxis/controller_spec.rb +73 -0
  453. data/spec/praxis/dispatcher_spec.rb +0 -0
  454. data/spec/praxis/file_group_spec.rb +34 -0
  455. data/spec/praxis/links_spec.rb +45 -0
  456. data/spec/praxis/media_type_collection_spec.rb +145 -0
  457. data/spec/praxis/media_type_spec.rb +80 -0
  458. data/spec/praxis/multipart/parser_spec.rb +54 -0
  459. data/spec/praxis/request_spec.rb +109 -0
  460. data/spec/praxis/request_stages_validate_spec.rb +34 -0
  461. data/spec/praxis/resource_definition_spec.rb +116 -0
  462. data/spec/praxis/response_definition_spec.rb +500 -0
  463. data/spec/praxis/response_spec.rb +166 -0
  464. data/spec/praxis/restful_routing_config_spec.rb +88 -0
  465. data/spec/praxis/route_spec.rb +42 -0
  466. data/spec/praxis/router_spec.rb +148 -0
  467. data/spec/praxis/stage_spec.rb +110 -0
  468. data/spec/praxis/types/multipart_spec.rb +81 -0
  469. data/spec/spec_app/app/controllers/instances.rb +63 -0
  470. data/spec/spec_app/app/responses/bulk_response.rb +6 -0
  471. data/spec/spec_app/app/responses/multipart.rb +10 -0
  472. data/spec/spec_app/app/responses/other_response.rb +6 -0
  473. data/spec/spec_app/config/environment.rb +17 -0
  474. data/spec/spec_app/config.ru +17 -0
  475. data/spec/spec_app/design/api.rb +27 -0
  476. data/spec/spec_app/design/media_types/instance.rb +35 -0
  477. data/spec/spec_app/design/media_types/volume.rb +34 -0
  478. data/spec/spec_app/design/media_types/volume_snapshot.rb +38 -0
  479. data/spec/spec_app/design/resources/instances.rb +161 -0
  480. data/spec/spec_helper.rb +39 -0
  481. data/spec/support/spec_media_types.rb +46 -0
  482. data/spec/support/spec_resource_definitions.rb +33 -0
  483. data/tasks/praxis_app_generator.thor +307 -0
  484. metadata +847 -12
@@ -0,0 +1,4116 @@
1
+ /*
2
+ * angular-ui-bootstrap
3
+ * http://angular-ui.github.io/bootstrap/
4
+
5
+ * Version: 0.11.0 - 2014-05-01
6
+ * License: MIT
7
+ */
8
+ angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
9
+ angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]);
10
+ angular.module('ui.bootstrap.transition', [])
11
+
12
+ /**
13
+ * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
14
+ * @param {DOMElement} element The DOMElement that will be animated.
15
+ * @param {string|object|function} trigger The thing that will cause the transition to start:
16
+ * - As a string, it represents the css class to be added to the element.
17
+ * - As an object, it represents a hash of style attributes to be applied to the element.
18
+ * - As a function, it represents a function to be called that will cause the transition to occur.
19
+ * @return {Promise} A promise that is resolved when the transition finishes.
20
+ */
21
+ .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
22
+
23
+ var $transition = function(element, trigger, options) {
24
+ options = options || {};
25
+ var deferred = $q.defer();
26
+ var endEventName = $transition[options.animation ? 'animationEndEventName' : 'transitionEndEventName'];
27
+
28
+ var transitionEndHandler = function(event) {
29
+ $rootScope.$apply(function() {
30
+ element.unbind(endEventName, transitionEndHandler);
31
+ deferred.resolve(element);
32
+ });
33
+ };
34
+
35
+ if (endEventName) {
36
+ element.bind(endEventName, transitionEndHandler);
37
+ }
38
+
39
+ // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
40
+ $timeout(function() {
41
+ if ( angular.isString(trigger) ) {
42
+ element.addClass(trigger);
43
+ } else if ( angular.isFunction(trigger) ) {
44
+ trigger(element);
45
+ } else if ( angular.isObject(trigger) ) {
46
+ element.css(trigger);
47
+ }
48
+ //If browser does not support transitions, instantly resolve
49
+ if ( !endEventName ) {
50
+ deferred.resolve(element);
51
+ }
52
+ });
53
+
54
+ // Add our custom cancel function to the promise that is returned
55
+ // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
56
+ // i.e. it will therefore never raise a transitionEnd event for that transition
57
+ deferred.promise.cancel = function() {
58
+ if ( endEventName ) {
59
+ element.unbind(endEventName, transitionEndHandler);
60
+ }
61
+ deferred.reject('Transition cancelled');
62
+ };
63
+
64
+ return deferred.promise;
65
+ };
66
+
67
+ // Work out the name of the transitionEnd event
68
+ var transElement = document.createElement('trans');
69
+ var transitionEndEventNames = {
70
+ 'WebkitTransition': 'webkitTransitionEnd',
71
+ 'MozTransition': 'transitionend',
72
+ 'OTransition': 'oTransitionEnd',
73
+ 'transition': 'transitionend'
74
+ };
75
+ var animationEndEventNames = {
76
+ 'WebkitTransition': 'webkitAnimationEnd',
77
+ 'MozTransition': 'animationend',
78
+ 'OTransition': 'oAnimationEnd',
79
+ 'transition': 'animationend'
80
+ };
81
+ function findEndEventName(endEventNames) {
82
+ for (var name in endEventNames){
83
+ if (transElement.style[name] !== undefined) {
84
+ return endEventNames[name];
85
+ }
86
+ }
87
+ }
88
+ $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
89
+ $transition.animationEndEventName = findEndEventName(animationEndEventNames);
90
+ return $transition;
91
+ }]);
92
+
93
+ angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition'])
94
+
95
+ .directive('collapse', ['$transition', function ($transition) {
96
+
97
+ return {
98
+ link: function (scope, element, attrs) {
99
+
100
+ var initialAnimSkip = true;
101
+ var currentTransition;
102
+
103
+ function doTransition(change) {
104
+ var newTransition = $transition(element, change);
105
+ if (currentTransition) {
106
+ currentTransition.cancel();
107
+ }
108
+ currentTransition = newTransition;
109
+ newTransition.then(newTransitionDone, newTransitionDone);
110
+ return newTransition;
111
+
112
+ function newTransitionDone() {
113
+ // Make sure it's this transition, otherwise, leave it alone.
114
+ if (currentTransition === newTransition) {
115
+ currentTransition = undefined;
116
+ }
117
+ }
118
+ }
119
+
120
+ function expand() {
121
+ if (initialAnimSkip) {
122
+ initialAnimSkip = false;
123
+ expandDone();
124
+ } else {
125
+ element.removeClass('collapse').addClass('collapsing');
126
+ doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone);
127
+ }
128
+ }
129
+
130
+ function expandDone() {
131
+ element.removeClass('collapsing');
132
+ element.addClass('collapse in');
133
+ element.css({height: 'auto'});
134
+ }
135
+
136
+ function collapse() {
137
+ if (initialAnimSkip) {
138
+ initialAnimSkip = false;
139
+ collapseDone();
140
+ element.css({height: 0});
141
+ } else {
142
+ // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value
143
+ element.css({ height: element[0].scrollHeight + 'px' });
144
+ //trigger reflow so a browser realizes that height was updated from auto to a specific value
145
+ var x = element[0].offsetWidth;
146
+
147
+ element.removeClass('collapse in').addClass('collapsing');
148
+
149
+ doTransition({ height: 0 }).then(collapseDone);
150
+ }
151
+ }
152
+
153
+ function collapseDone() {
154
+ element.removeClass('collapsing');
155
+ element.addClass('collapse');
156
+ }
157
+
158
+ scope.$watch(attrs.collapse, function (shouldCollapse) {
159
+ if (shouldCollapse) {
160
+ collapse();
161
+ } else {
162
+ expand();
163
+ }
164
+ });
165
+ }
166
+ };
167
+ }]);
168
+
169
+ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
170
+
171
+ .constant('accordionConfig', {
172
+ closeOthers: true
173
+ })
174
+
175
+ .controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
176
+
177
+ // This array keeps track of the accordion groups
178
+ this.groups = [];
179
+
180
+ // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
181
+ this.closeOthers = function(openGroup) {
182
+ var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
183
+ if ( closeOthers ) {
184
+ angular.forEach(this.groups, function (group) {
185
+ if ( group !== openGroup ) {
186
+ group.isOpen = false;
187
+ }
188
+ });
189
+ }
190
+ };
191
+
192
+ // This is called from the accordion-group directive to add itself to the accordion
193
+ this.addGroup = function(groupScope) {
194
+ var that = this;
195
+ this.groups.push(groupScope);
196
+
197
+ groupScope.$on('$destroy', function (event) {
198
+ that.removeGroup(groupScope);
199
+ });
200
+ };
201
+
202
+ // This is called from the accordion-group directive when to remove itself
203
+ this.removeGroup = function(group) {
204
+ var index = this.groups.indexOf(group);
205
+ if ( index !== -1 ) {
206
+ this.groups.splice(index, 1);
207
+ }
208
+ };
209
+
210
+ }])
211
+
212
+ // The accordion directive simply sets up the directive controller
213
+ // and adds an accordion CSS class to itself element.
214
+ .directive('accordion', function () {
215
+ return {
216
+ restrict:'EA',
217
+ controller:'AccordionController',
218
+ transclude: true,
219
+ replace: false,
220
+ templateUrl: 'template/accordion/accordion.html'
221
+ };
222
+ })
223
+
224
+ // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
225
+ .directive('accordionGroup', function() {
226
+ return {
227
+ require:'^accordion', // We need this directive to be inside an accordion
228
+ restrict:'EA',
229
+ transclude:true, // It transcludes the contents of the directive into the template
230
+ replace: true, // The element containing the directive will be replaced with the template
231
+ templateUrl:'template/accordion/accordion-group.html',
232
+ scope: {
233
+ heading: '@', // Interpolate the heading attribute onto this scope
234
+ isOpen: '=?',
235
+ isDisabled: '=?'
236
+ },
237
+ controller: function() {
238
+ this.setHeading = function(element) {
239
+ this.heading = element;
240
+ };
241
+ },
242
+ link: function(scope, element, attrs, accordionCtrl) {
243
+ accordionCtrl.addGroup(scope);
244
+
245
+ scope.$watch('isOpen', function(value) {
246
+ if ( value ) {
247
+ accordionCtrl.closeOthers(scope);
248
+ }
249
+ });
250
+
251
+ scope.toggleOpen = function() {
252
+ if ( !scope.isDisabled ) {
253
+ scope.isOpen = !scope.isOpen;
254
+ }
255
+ };
256
+ }
257
+ };
258
+ })
259
+
260
+ // Use accordion-heading below an accordion-group to provide a heading containing HTML
261
+ // <accordion-group>
262
+ // <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
263
+ // </accordion-group>
264
+ .directive('accordionHeading', function() {
265
+ return {
266
+ restrict: 'EA',
267
+ transclude: true, // Grab the contents to be used as the heading
268
+ template: '', // In effect remove this element!
269
+ replace: true,
270
+ require: '^accordionGroup',
271
+ link: function(scope, element, attr, accordionGroupCtrl, transclude) {
272
+ // Pass the heading to the accordion-group controller
273
+ // so that it can be transcluded into the right place in the template
274
+ // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
275
+ accordionGroupCtrl.setHeading(transclude(scope, function() {}));
276
+ }
277
+ };
278
+ })
279
+
280
+ // Use in the accordion-group template to indicate where you want the heading to be transcluded
281
+ // You must provide the property on the accordion-group controller that will hold the transcluded element
282
+ // <div class="accordion-group">
283
+ // <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
284
+ // ...
285
+ // </div>
286
+ .directive('accordionTransclude', function() {
287
+ return {
288
+ require: '^accordionGroup',
289
+ link: function(scope, element, attr, controller) {
290
+ scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
291
+ if ( heading ) {
292
+ element.html('');
293
+ element.append(heading);
294
+ }
295
+ });
296
+ }
297
+ };
298
+ });
299
+
300
+ angular.module('ui.bootstrap.alert', [])
301
+
302
+ .controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) {
303
+ $scope.closeable = 'close' in $attrs;
304
+ }])
305
+
306
+ .directive('alert', function () {
307
+ return {
308
+ restrict:'EA',
309
+ controller:'AlertController',
310
+ templateUrl:'template/alert/alert.html',
311
+ transclude:true,
312
+ replace:true,
313
+ scope: {
314
+ type: '@',
315
+ close: '&'
316
+ }
317
+ };
318
+ });
319
+
320
+ angular.module('ui.bootstrap.bindHtml', [])
321
+
322
+ .directive('bindHtmlUnsafe', function () {
323
+ return function (scope, element, attr) {
324
+ element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe);
325
+ scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) {
326
+ element.html(value || '');
327
+ });
328
+ };
329
+ });
330
+ angular.module('ui.bootstrap.buttons', [])
331
+
332
+ .constant('buttonConfig', {
333
+ activeClass: 'active',
334
+ toggleEvent: 'click'
335
+ })
336
+
337
+ .controller('ButtonsController', ['buttonConfig', function(buttonConfig) {
338
+ this.activeClass = buttonConfig.activeClass || 'active';
339
+ this.toggleEvent = buttonConfig.toggleEvent || 'click';
340
+ }])
341
+
342
+ .directive('btnRadio', function () {
343
+ return {
344
+ require: ['btnRadio', 'ngModel'],
345
+ controller: 'ButtonsController',
346
+ link: function (scope, element, attrs, ctrls) {
347
+ var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
348
+
349
+ //model -> UI
350
+ ngModelCtrl.$render = function () {
351
+ element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
352
+ };
353
+
354
+ //ui->model
355
+ element.bind(buttonsCtrl.toggleEvent, function () {
356
+ var isActive = element.hasClass(buttonsCtrl.activeClass);
357
+
358
+ if (!isActive || angular.isDefined(attrs.uncheckable)) {
359
+ scope.$apply(function () {
360
+ ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
361
+ ngModelCtrl.$render();
362
+ });
363
+ }
364
+ });
365
+ }
366
+ };
367
+ })
368
+
369
+ .directive('btnCheckbox', function () {
370
+ return {
371
+ require: ['btnCheckbox', 'ngModel'],
372
+ controller: 'ButtonsController',
373
+ link: function (scope, element, attrs, ctrls) {
374
+ var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
375
+
376
+ function getTrueValue() {
377
+ return getCheckboxValue(attrs.btnCheckboxTrue, true);
378
+ }
379
+
380
+ function getFalseValue() {
381
+ return getCheckboxValue(attrs.btnCheckboxFalse, false);
382
+ }
383
+
384
+ function getCheckboxValue(attributeValue, defaultValue) {
385
+ var val = scope.$eval(attributeValue);
386
+ return angular.isDefined(val) ? val : defaultValue;
387
+ }
388
+
389
+ //model -> UI
390
+ ngModelCtrl.$render = function () {
391
+ element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
392
+ };
393
+
394
+ //ui->model
395
+ element.bind(buttonsCtrl.toggleEvent, function () {
396
+ scope.$apply(function () {
397
+ ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
398
+ ngModelCtrl.$render();
399
+ });
400
+ });
401
+ }
402
+ };
403
+ });
404
+
405
+ /**
406
+ * @ngdoc overview
407
+ * @name ui.bootstrap.carousel
408
+ *
409
+ * @description
410
+ * AngularJS version of an image carousel.
411
+ *
412
+ */
413
+ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
414
+ .controller('CarouselController', ['$scope', '$timeout', '$transition', function ($scope, $timeout, $transition) {
415
+ var self = this,
416
+ slides = self.slides = $scope.slides = [],
417
+ currentIndex = -1,
418
+ currentTimeout, isPlaying;
419
+ self.currentSlide = null;
420
+
421
+ var destroyed = false;
422
+ /* direction: "prev" or "next" */
423
+ self.select = $scope.select = function(nextSlide, direction) {
424
+ var nextIndex = slides.indexOf(nextSlide);
425
+ //Decide direction if it's not given
426
+ if (direction === undefined) {
427
+ direction = nextIndex > currentIndex ? 'next' : 'prev';
428
+ }
429
+ if (nextSlide && nextSlide !== self.currentSlide) {
430
+ if ($scope.$currentTransition) {
431
+ $scope.$currentTransition.cancel();
432
+ //Timeout so ng-class in template has time to fix classes for finished slide
433
+ $timeout(goNext);
434
+ } else {
435
+ goNext();
436
+ }
437
+ }
438
+ function goNext() {
439
+ // Scope has been destroyed, stop here.
440
+ if (destroyed) { return; }
441
+ //If we have a slide to transition from and we have a transition type and we're allowed, go
442
+ if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
443
+ //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime
444
+ nextSlide.$element.addClass(direction);
445
+ var reflow = nextSlide.$element[0].offsetWidth; //force reflow
446
+
447
+ //Set all other slides to stop doing their stuff for the new transition
448
+ angular.forEach(slides, function(slide) {
449
+ angular.extend(slide, {direction: '', entering: false, leaving: false, active: false});
450
+ });
451
+ angular.extend(nextSlide, {direction: direction, active: true, entering: true});
452
+ angular.extend(self.currentSlide||{}, {direction: direction, leaving: true});
453
+
454
+ $scope.$currentTransition = $transition(nextSlide.$element, {});
455
+ //We have to create new pointers inside a closure since next & current will change
456
+ (function(next,current) {
457
+ $scope.$currentTransition.then(
458
+ function(){ transitionDone(next, current); },
459
+ function(){ transitionDone(next, current); }
460
+ );
461
+ }(nextSlide, self.currentSlide));
462
+ } else {
463
+ transitionDone(nextSlide, self.currentSlide);
464
+ }
465
+ self.currentSlide = nextSlide;
466
+ currentIndex = nextIndex;
467
+ //every time you change slides, reset the timer
468
+ restartTimer();
469
+ }
470
+ function transitionDone(next, current) {
471
+ angular.extend(next, {direction: '', active: true, leaving: false, entering: false});
472
+ angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false});
473
+ $scope.$currentTransition = null;
474
+ }
475
+ };
476
+ $scope.$on('$destroy', function () {
477
+ destroyed = true;
478
+ });
479
+
480
+ /* Allow outside people to call indexOf on slides array */
481
+ self.indexOfSlide = function(slide) {
482
+ return slides.indexOf(slide);
483
+ };
484
+
485
+ $scope.next = function() {
486
+ var newIndex = (currentIndex + 1) % slides.length;
487
+
488
+ //Prevent this user-triggered transition from occurring if there is already one in progress
489
+ if (!$scope.$currentTransition) {
490
+ return self.select(slides[newIndex], 'next');
491
+ }
492
+ };
493
+
494
+ $scope.prev = function() {
495
+ var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
496
+
497
+ //Prevent this user-triggered transition from occurring if there is already one in progress
498
+ if (!$scope.$currentTransition) {
499
+ return self.select(slides[newIndex], 'prev');
500
+ }
501
+ };
502
+
503
+ $scope.isActive = function(slide) {
504
+ return self.currentSlide === slide;
505
+ };
506
+
507
+ $scope.$watch('interval', restartTimer);
508
+ $scope.$on('$destroy', resetTimer);
509
+
510
+ function restartTimer() {
511
+ resetTimer();
512
+ var interval = +$scope.interval;
513
+ if (!isNaN(interval) && interval>=0) {
514
+ currentTimeout = $timeout(timerFn, interval);
515
+ }
516
+ }
517
+
518
+ function resetTimer() {
519
+ if (currentTimeout) {
520
+ $timeout.cancel(currentTimeout);
521
+ currentTimeout = null;
522
+ }
523
+ }
524
+
525
+ function timerFn() {
526
+ if (isPlaying) {
527
+ $scope.next();
528
+ restartTimer();
529
+ } else {
530
+ $scope.pause();
531
+ }
532
+ }
533
+
534
+ $scope.play = function() {
535
+ if (!isPlaying) {
536
+ isPlaying = true;
537
+ restartTimer();
538
+ }
539
+ };
540
+ $scope.pause = function() {
541
+ if (!$scope.noPause) {
542
+ isPlaying = false;
543
+ resetTimer();
544
+ }
545
+ };
546
+
547
+ self.addSlide = function(slide, element) {
548
+ slide.$element = element;
549
+ slides.push(slide);
550
+ //if this is the first slide or the slide is set to active, select it
551
+ if(slides.length === 1 || slide.active) {
552
+ self.select(slides[slides.length-1]);
553
+ if (slides.length == 1) {
554
+ $scope.play();
555
+ }
556
+ } else {
557
+ slide.active = false;
558
+ }
559
+ };
560
+
561
+ self.removeSlide = function(slide) {
562
+ //get the index of the slide inside the carousel
563
+ var index = slides.indexOf(slide);
564
+ slides.splice(index, 1);
565
+ if (slides.length > 0 && slide.active) {
566
+ if (index >= slides.length) {
567
+ self.select(slides[index-1]);
568
+ } else {
569
+ self.select(slides[index]);
570
+ }
571
+ } else if (currentIndex > index) {
572
+ currentIndex--;
573
+ }
574
+ };
575
+
576
+ }])
577
+
578
+ /**
579
+ * @ngdoc directive
580
+ * @name ui.bootstrap.carousel.directive:carousel
581
+ * @restrict EA
582
+ *
583
+ * @description
584
+ * Carousel is the outer container for a set of image 'slides' to showcase.
585
+ *
586
+ * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
587
+ * @param {boolean=} noTransition Whether to disable transitions on the carousel.
588
+ * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
589
+ *
590
+ * @example
591
+ <example module="ui.bootstrap">
592
+ <file name="index.html">
593
+ <carousel>
594
+ <slide>
595
+ <img src="http://placekitten.com/150/150" style="margin:auto;">
596
+ <div class="carousel-caption">
597
+ <p>Beautiful!</p>
598
+ </div>
599
+ </slide>
600
+ <slide>
601
+ <img src="http://placekitten.com/100/150" style="margin:auto;">
602
+ <div class="carousel-caption">
603
+ <p>D'aww!</p>
604
+ </div>
605
+ </slide>
606
+ </carousel>
607
+ </file>
608
+ <file name="demo.css">
609
+ .carousel-indicators {
610
+ top: auto;
611
+ bottom: 15px;
612
+ }
613
+ </file>
614
+ </example>
615
+ */
616
+ .directive('carousel', [function() {
617
+ return {
618
+ restrict: 'EA',
619
+ transclude: true,
620
+ replace: true,
621
+ controller: 'CarouselController',
622
+ require: 'carousel',
623
+ templateUrl: 'template/carousel/carousel.html',
624
+ scope: {
625
+ interval: '=',
626
+ noTransition: '=',
627
+ noPause: '='
628
+ }
629
+ };
630
+ }])
631
+
632
+ /**
633
+ * @ngdoc directive
634
+ * @name ui.bootstrap.carousel.directive:slide
635
+ * @restrict EA
636
+ *
637
+ * @description
638
+ * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element.
639
+ *
640
+ * @param {boolean=} active Model binding, whether or not this slide is currently active.
641
+ *
642
+ * @example
643
+ <example module="ui.bootstrap">
644
+ <file name="index.html">
645
+ <div ng-controller="CarouselDemoCtrl">
646
+ <carousel>
647
+ <slide ng-repeat="slide in slides" active="slide.active">
648
+ <img ng-src="{{slide.image}}" style="margin:auto;">
649
+ <div class="carousel-caption">
650
+ <h4>Slide {{$index}}</h4>
651
+ <p>{{slide.text}}</p>
652
+ </div>
653
+ </slide>
654
+ </carousel>
655
+ Interval, in milliseconds: <input type="number" ng-model="myInterval">
656
+ <br />Enter a negative number to stop the interval.
657
+ </div>
658
+ </file>
659
+ <file name="script.js">
660
+ function CarouselDemoCtrl($scope) {
661
+ $scope.myInterval = 5000;
662
+ }
663
+ </file>
664
+ <file name="demo.css">
665
+ .carousel-indicators {
666
+ top: auto;
667
+ bottom: 15px;
668
+ }
669
+ </file>
670
+ </example>
671
+ */
672
+
673
+ .directive('slide', function() {
674
+ return {
675
+ require: '^carousel',
676
+ restrict: 'EA',
677
+ transclude: true,
678
+ replace: true,
679
+ templateUrl: 'template/carousel/slide.html',
680
+ scope: {
681
+ active: '=?'
682
+ },
683
+ link: function (scope, element, attrs, carouselCtrl) {
684
+ carouselCtrl.addSlide(scope, element);
685
+ //when the scope is destroyed then remove the slide from the current slides array
686
+ scope.$on('$destroy', function() {
687
+ carouselCtrl.removeSlide(scope);
688
+ });
689
+
690
+ scope.$watch('active', function(active) {
691
+ if (active) {
692
+ carouselCtrl.select(scope);
693
+ }
694
+ });
695
+ }
696
+ };
697
+ });
698
+
699
+ angular.module('ui.bootstrap.dateparser', [])
700
+
701
+ .service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {
702
+
703
+ this.parsers = {};
704
+
705
+ var formatCodeToRegex = {
706
+ 'yyyy': {
707
+ regex: '\\d{4}',
708
+ apply: function(value) { this.year = +value; }
709
+ },
710
+ 'yy': {
711
+ regex: '\\d{2}',
712
+ apply: function(value) { this.year = +value + 2000; }
713
+ },
714
+ 'y': {
715
+ regex: '\\d{1,4}',
716
+ apply: function(value) { this.year = +value; }
717
+ },
718
+ 'MMMM': {
719
+ regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
720
+ apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
721
+ },
722
+ 'MMM': {
723
+ regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
724
+ apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
725
+ },
726
+ 'MM': {
727
+ regex: '0[1-9]|1[0-2]',
728
+ apply: function(value) { this.month = value - 1; }
729
+ },
730
+ 'M': {
731
+ regex: '[1-9]|1[0-2]',
732
+ apply: function(value) { this.month = value - 1; }
733
+ },
734
+ 'dd': {
735
+ regex: '[0-2][0-9]{1}|3[0-1]{1}',
736
+ apply: function(value) { this.date = +value; }
737
+ },
738
+ 'd': {
739
+ regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
740
+ apply: function(value) { this.date = +value; }
741
+ },
742
+ 'EEEE': {
743
+ regex: $locale.DATETIME_FORMATS.DAY.join('|')
744
+ },
745
+ 'EEE': {
746
+ regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
747
+ }
748
+ };
749
+
750
+ this.createParser = function(format) {
751
+ var map = [], regex = format.split('');
752
+
753
+ angular.forEach(formatCodeToRegex, function(data, code) {
754
+ var index = format.indexOf(code);
755
+
756
+ if (index > -1) {
757
+ format = format.split('');
758
+
759
+ regex[index] = '(' + data.regex + ')';
760
+ format[index] = '$'; // Custom symbol to define consumed part of format
761
+ for (var i = index + 1, n = index + code.length; i < n; i++) {
762
+ regex[i] = '';
763
+ format[i] = '$';
764
+ }
765
+ format = format.join('');
766
+
767
+ map.push({ index: index, apply: data.apply });
768
+ }
769
+ });
770
+
771
+ return {
772
+ regex: new RegExp('^' + regex.join('') + '$'),
773
+ map: orderByFilter(map, 'index')
774
+ };
775
+ };
776
+
777
+ this.parse = function(input, format) {
778
+ if ( !angular.isString(input) ) {
779
+ return input;
780
+ }
781
+
782
+ format = $locale.DATETIME_FORMATS[format] || format;
783
+
784
+ if ( !this.parsers[format] ) {
785
+ this.parsers[format] = this.createParser(format);
786
+ }
787
+
788
+ var parser = this.parsers[format],
789
+ regex = parser.regex,
790
+ map = parser.map,
791
+ results = input.match(regex);
792
+
793
+ if ( results && results.length ) {
794
+ var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;
795
+
796
+ for( var i = 1, n = results.length; i < n; i++ ) {
797
+ var mapper = map[i-1];
798
+ if ( mapper.apply ) {
799
+ mapper.apply.call(fields, results[i]);
800
+ }
801
+ }
802
+
803
+ if ( isValid(fields.year, fields.month, fields.date) ) {
804
+ dt = new Date( fields.year, fields.month, fields.date, fields.hours);
805
+ }
806
+
807
+ return dt;
808
+ }
809
+ };
810
+
811
+ // Check if date is valid for specific month (and year for February).
812
+ // Month: 0 = Jan, 1 = Feb, etc
813
+ function isValid(year, month, date) {
814
+ if ( month === 1 && date > 28) {
815
+ return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
816
+ }
817
+
818
+ if ( month === 3 || month === 5 || month === 8 || month === 10) {
819
+ return date < 31;
820
+ }
821
+
822
+ return true;
823
+ }
824
+ }]);
825
+
826
+ angular.module('ui.bootstrap.position', [])
827
+
828
+ /**
829
+ * A set of utility methods that can be use to retrieve position of DOM elements.
830
+ * It is meant to be used where we need to absolute-position DOM elements in
831
+ * relation to other, existing elements (this is the case for tooltips, popovers,
832
+ * typeahead suggestions etc.).
833
+ */
834
+ .factory('$position', ['$document', '$window', function ($document, $window) {
835
+
836
+ function getStyle(el, cssprop) {
837
+ if (el.currentStyle) { //IE
838
+ return el.currentStyle[cssprop];
839
+ } else if ($window.getComputedStyle) {
840
+ return $window.getComputedStyle(el)[cssprop];
841
+ }
842
+ // finally try and get inline style
843
+ return el.style[cssprop];
844
+ }
845
+
846
+ /**
847
+ * Checks if a given element is statically positioned
848
+ * @param element - raw DOM element
849
+ */
850
+ function isStaticPositioned(element) {
851
+ return (getStyle(element, 'position') || 'static' ) === 'static';
852
+ }
853
+
854
+ /**
855
+ * returns the closest, non-statically positioned parentOffset of a given element
856
+ * @param element
857
+ */
858
+ var parentOffsetEl = function (element) {
859
+ var docDomEl = $document[0];
860
+ var offsetParent = element.offsetParent || docDomEl;
861
+ while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
862
+ offsetParent = offsetParent.offsetParent;
863
+ }
864
+ return offsetParent || docDomEl;
865
+ };
866
+
867
+ return {
868
+ /**
869
+ * Provides read-only equivalent of jQuery's position function:
870
+ * http://api.jquery.com/position/
871
+ */
872
+ position: function (element) {
873
+ var elBCR = this.offset(element);
874
+ var offsetParentBCR = { top: 0, left: 0 };
875
+ var offsetParentEl = parentOffsetEl(element[0]);
876
+ if (offsetParentEl != $document[0]) {
877
+ offsetParentBCR = this.offset(angular.element(offsetParentEl));
878
+ offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
879
+ offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
880
+ }
881
+
882
+ var boundingClientRect = element[0].getBoundingClientRect();
883
+ return {
884
+ width: boundingClientRect.width || element.prop('offsetWidth'),
885
+ height: boundingClientRect.height || element.prop('offsetHeight'),
886
+ top: elBCR.top - offsetParentBCR.top,
887
+ left: elBCR.left - offsetParentBCR.left
888
+ };
889
+ },
890
+
891
+ /**
892
+ * Provides read-only equivalent of jQuery's offset function:
893
+ * http://api.jquery.com/offset/
894
+ */
895
+ offset: function (element) {
896
+ var boundingClientRect = element[0].getBoundingClientRect();
897
+ return {
898
+ width: boundingClientRect.width || element.prop('offsetWidth'),
899
+ height: boundingClientRect.height || element.prop('offsetHeight'),
900
+ top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
901
+ left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
902
+ };
903
+ },
904
+
905
+ /**
906
+ * Provides coordinates for the targetEl in relation to hostEl
907
+ */
908
+ positionElements: function (hostEl, targetEl, positionStr, appendToBody) {
909
+
910
+ var positionStrParts = positionStr.split('-');
911
+ var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';
912
+
913
+ var hostElPos,
914
+ targetElWidth,
915
+ targetElHeight,
916
+ targetElPos;
917
+
918
+ hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl);
919
+
920
+ targetElWidth = targetEl.prop('offsetWidth');
921
+ targetElHeight = targetEl.prop('offsetHeight');
922
+
923
+ var shiftWidth = {
924
+ center: function () {
925
+ return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
926
+ },
927
+ left: function () {
928
+ return hostElPos.left;
929
+ },
930
+ right: function () {
931
+ return hostElPos.left + hostElPos.width;
932
+ }
933
+ };
934
+
935
+ var shiftHeight = {
936
+ center: function () {
937
+ return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
938
+ },
939
+ top: function () {
940
+ return hostElPos.top;
941
+ },
942
+ bottom: function () {
943
+ return hostElPos.top + hostElPos.height;
944
+ }
945
+ };
946
+
947
+ switch (pos0) {
948
+ case 'right':
949
+ targetElPos = {
950
+ top: shiftHeight[pos1](),
951
+ left: shiftWidth[pos0]()
952
+ };
953
+ break;
954
+ case 'left':
955
+ targetElPos = {
956
+ top: shiftHeight[pos1](),
957
+ left: hostElPos.left - targetElWidth
958
+ };
959
+ break;
960
+ case 'bottom':
961
+ targetElPos = {
962
+ top: shiftHeight[pos0](),
963
+ left: shiftWidth[pos1]()
964
+ };
965
+ break;
966
+ default:
967
+ targetElPos = {
968
+ top: hostElPos.top - targetElHeight,
969
+ left: shiftWidth[pos1]()
970
+ };
971
+ break;
972
+ }
973
+
974
+ return targetElPos;
975
+ }
976
+ };
977
+ }]);
978
+
979
+ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.position'])
980
+
981
+ .constant('datepickerConfig', {
982
+ formatDay: 'dd',
983
+ formatMonth: 'MMMM',
984
+ formatYear: 'yyyy',
985
+ formatDayHeader: 'EEE',
986
+ formatDayTitle: 'MMMM yyyy',
987
+ formatMonthTitle: 'yyyy',
988
+ datepickerMode: 'day',
989
+ minMode: 'day',
990
+ maxMode: 'year',
991
+ showWeeks: true,
992
+ startingDay: 0,
993
+ yearRange: 20,
994
+ minDate: null,
995
+ maxDate: null
996
+ })
997
+
998
+ .controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) {
999
+ var self = this,
1000
+ ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl;
1001
+
1002
+ // Modes chain
1003
+ this.modes = ['day', 'month', 'year'];
1004
+
1005
+ // Configuration attributes
1006
+ angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle',
1007
+ 'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange'], function( key, index ) {
1008
+ self[key] = angular.isDefined($attrs[key]) ? (index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key])) : datepickerConfig[key];
1009
+ });
1010
+
1011
+ // Watchable attributes
1012
+ angular.forEach(['minDate', 'maxDate'], function( key ) {
1013
+ if ( $attrs[key] ) {
1014
+ $scope.$parent.$watch($parse($attrs[key]), function(value) {
1015
+ self[key] = value ? new Date(value) : null;
1016
+ self.refreshView();
1017
+ });
1018
+ } else {
1019
+ self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null;
1020
+ }
1021
+ });
1022
+
1023
+ $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
1024
+ $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
1025
+ this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date();
1026
+
1027
+ $scope.isActive = function(dateObject) {
1028
+ if (self.compare(dateObject.date, self.activeDate) === 0) {
1029
+ $scope.activeDateId = dateObject.uid;
1030
+ return true;
1031
+ }
1032
+ return false;
1033
+ };
1034
+
1035
+ this.init = function( ngModelCtrl_ ) {
1036
+ ngModelCtrl = ngModelCtrl_;
1037
+
1038
+ ngModelCtrl.$render = function() {
1039
+ self.render();
1040
+ };
1041
+ };
1042
+
1043
+ this.render = function() {
1044
+ if ( ngModelCtrl.$modelValue ) {
1045
+ var date = new Date( ngModelCtrl.$modelValue ),
1046
+ isValid = !isNaN(date);
1047
+
1048
+ if ( isValid ) {
1049
+ this.activeDate = date;
1050
+ } else {
1051
+ $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
1052
+ }
1053
+ ngModelCtrl.$setValidity('date', isValid);
1054
+ }
1055
+ this.refreshView();
1056
+ };
1057
+
1058
+ this.refreshView = function() {
1059
+ if ( this.element ) {
1060
+ this._refreshView();
1061
+
1062
+ var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
1063
+ ngModelCtrl.$setValidity('date-disabled', !date || (this.element && !this.isDisabled(date)));
1064
+ }
1065
+ };
1066
+
1067
+ this.createDateObject = function(date, format) {
1068
+ var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
1069
+ return {
1070
+ date: date,
1071
+ label: dateFilter(date, format),
1072
+ selected: model && this.compare(date, model) === 0,
1073
+ disabled: this.isDisabled(date),
1074
+ current: this.compare(date, new Date()) === 0
1075
+ };
1076
+ };
1077
+
1078
+ this.isDisabled = function( date ) {
1079
+ return ((this.minDate && this.compare(date, this.minDate) < 0) || (this.maxDate && this.compare(date, this.maxDate) > 0) || ($attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode})));
1080
+ };
1081
+
1082
+ // Split array into smaller arrays
1083
+ this.split = function(arr, size) {
1084
+ var arrays = [];
1085
+ while (arr.length > 0) {
1086
+ arrays.push(arr.splice(0, size));
1087
+ }
1088
+ return arrays;
1089
+ };
1090
+
1091
+ $scope.select = function( date ) {
1092
+ if ( $scope.datepickerMode === self.minMode ) {
1093
+ var dt = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0);
1094
+ dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() );
1095
+ ngModelCtrl.$setViewValue( dt );
1096
+ ngModelCtrl.$render();
1097
+ } else {
1098
+ self.activeDate = date;
1099
+ $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) - 1 ];
1100
+ }
1101
+ };
1102
+
1103
+ $scope.move = function( direction ) {
1104
+ var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
1105
+ month = self.activeDate.getMonth() + direction * (self.step.months || 0);
1106
+ self.activeDate.setFullYear(year, month, 1);
1107
+ self.refreshView();
1108
+ };
1109
+
1110
+ $scope.toggleMode = function( direction ) {
1111
+ direction = direction || 1;
1112
+
1113
+ if (($scope.datepickerMode === self.maxMode && direction === 1) || ($scope.datepickerMode === self.minMode && direction === -1)) {
1114
+ return;
1115
+ }
1116
+
1117
+ $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) + direction ];
1118
+ };
1119
+
1120
+ // Key event mapper
1121
+ $scope.keys = { 13:'enter', 32:'space', 33:'pageup', 34:'pagedown', 35:'end', 36:'home', 37:'left', 38:'up', 39:'right', 40:'down' };
1122
+
1123
+ var focusElement = function() {
1124
+ $timeout(function() {
1125
+ self.element[0].focus();
1126
+ }, 0 , false);
1127
+ };
1128
+
1129
+ // Listen for focus requests from popup directive
1130
+ $scope.$on('datepicker.focus', focusElement);
1131
+
1132
+ $scope.keydown = function( evt ) {
1133
+ var key = $scope.keys[evt.which];
1134
+
1135
+ if ( !key || evt.shiftKey || evt.altKey ) {
1136
+ return;
1137
+ }
1138
+
1139
+ evt.preventDefault();
1140
+ evt.stopPropagation();
1141
+
1142
+ if (key === 'enter' || key === 'space') {
1143
+ if ( self.isDisabled(self.activeDate)) {
1144
+ return; // do nothing
1145
+ }
1146
+ $scope.select(self.activeDate);
1147
+ focusElement();
1148
+ } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
1149
+ $scope.toggleMode(key === 'up' ? 1 : -1);
1150
+ focusElement();
1151
+ } else {
1152
+ self.handleKeyDown(key, evt);
1153
+ self.refreshView();
1154
+ }
1155
+ };
1156
+ }])
1157
+
1158
+ .directive( 'datepicker', function () {
1159
+ return {
1160
+ restrict: 'EA',
1161
+ replace: true,
1162
+ templateUrl: 'template/datepicker/datepicker.html',
1163
+ scope: {
1164
+ datepickerMode: '=?',
1165
+ dateDisabled: '&'
1166
+ },
1167
+ require: ['datepicker', '?^ngModel'],
1168
+ controller: 'DatepickerController',
1169
+ link: function(scope, element, attrs, ctrls) {
1170
+ var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
1171
+
1172
+ if ( ngModelCtrl ) {
1173
+ datepickerCtrl.init( ngModelCtrl );
1174
+ }
1175
+ }
1176
+ };
1177
+ })
1178
+
1179
+ .directive('daypicker', ['dateFilter', function (dateFilter) {
1180
+ return {
1181
+ restrict: 'EA',
1182
+ replace: true,
1183
+ templateUrl: 'template/datepicker/day.html',
1184
+ require: '^datepicker',
1185
+ link: function(scope, element, attrs, ctrl) {
1186
+ scope.showWeeks = ctrl.showWeeks;
1187
+
1188
+ ctrl.step = { months: 1 };
1189
+ ctrl.element = element;
1190
+
1191
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1192
+ function getDaysInMonth( year, month ) {
1193
+ return ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0))) ? 29 : DAYS_IN_MONTH[month];
1194
+ }
1195
+
1196
+ function getDates(startDate, n) {
1197
+ var dates = new Array(n), current = new Date(startDate), i = 0;
1198
+ current.setHours(12); // Prevent repeated dates because of timezone bug
1199
+ while ( i < n ) {
1200
+ dates[i++] = new Date(current);
1201
+ current.setDate( current.getDate() + 1 );
1202
+ }
1203
+ return dates;
1204
+ }
1205
+
1206
+ ctrl._refreshView = function() {
1207
+ var year = ctrl.activeDate.getFullYear(),
1208
+ month = ctrl.activeDate.getMonth(),
1209
+ firstDayOfMonth = new Date(year, month, 1),
1210
+ difference = ctrl.startingDay - firstDayOfMonth.getDay(),
1211
+ numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
1212
+ firstDate = new Date(firstDayOfMonth);
1213
+
1214
+ if ( numDisplayedFromPreviousMonth > 0 ) {
1215
+ firstDate.setDate( - numDisplayedFromPreviousMonth + 1 );
1216
+ }
1217
+
1218
+ // 42 is the number of days on a six-month calendar
1219
+ var days = getDates(firstDate, 42);
1220
+ for (var i = 0; i < 42; i ++) {
1221
+ days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay), {
1222
+ secondary: days[i].getMonth() !== month,
1223
+ uid: scope.uniqueId + '-' + i
1224
+ });
1225
+ }
1226
+
1227
+ scope.labels = new Array(7);
1228
+ for (var j = 0; j < 7; j++) {
1229
+ scope.labels[j] = {
1230
+ abbr: dateFilter(days[j].date, ctrl.formatDayHeader),
1231
+ full: dateFilter(days[j].date, 'EEEE')
1232
+ };
1233
+ }
1234
+
1235
+ scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle);
1236
+ scope.rows = ctrl.split(days, 7);
1237
+
1238
+ if ( scope.showWeeks ) {
1239
+ scope.weekNumbers = [];
1240
+ var weekNumber = getISO8601WeekNumber( scope.rows[0][0].date ),
1241
+ numWeeks = scope.rows.length;
1242
+ while( scope.weekNumbers.push(weekNumber++) < numWeeks ) {}
1243
+ }
1244
+ };
1245
+
1246
+ ctrl.compare = function(date1, date2) {
1247
+ return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) );
1248
+ };
1249
+
1250
+ function getISO8601WeekNumber(date) {
1251
+ var checkDate = new Date(date);
1252
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
1253
+ var time = checkDate.getTime();
1254
+ checkDate.setMonth(0); // Compare with Jan 1
1255
+ checkDate.setDate(1);
1256
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
1257
+ }
1258
+
1259
+ ctrl.handleKeyDown = function( key, evt ) {
1260
+ var date = ctrl.activeDate.getDate();
1261
+
1262
+ if (key === 'left') {
1263
+ date = date - 1; // up
1264
+ } else if (key === 'up') {
1265
+ date = date - 7; // down
1266
+ } else if (key === 'right') {
1267
+ date = date + 1; // down
1268
+ } else if (key === 'down') {
1269
+ date = date + 7;
1270
+ } else if (key === 'pageup' || key === 'pagedown') {
1271
+ var month = ctrl.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
1272
+ ctrl.activeDate.setMonth(month, 1);
1273
+ date = Math.min(getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()), date);
1274
+ } else if (key === 'home') {
1275
+ date = 1;
1276
+ } else if (key === 'end') {
1277
+ date = getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth());
1278
+ }
1279
+ ctrl.activeDate.setDate(date);
1280
+ };
1281
+
1282
+ ctrl.refreshView();
1283
+ }
1284
+ };
1285
+ }])
1286
+
1287
+ .directive('monthpicker', ['dateFilter', function (dateFilter) {
1288
+ return {
1289
+ restrict: 'EA',
1290
+ replace: true,
1291
+ templateUrl: 'template/datepicker/month.html',
1292
+ require: '^datepicker',
1293
+ link: function(scope, element, attrs, ctrl) {
1294
+ ctrl.step = { years: 1 };
1295
+ ctrl.element = element;
1296
+
1297
+ ctrl._refreshView = function() {
1298
+ var months = new Array(12),
1299
+ year = ctrl.activeDate.getFullYear();
1300
+
1301
+ for ( var i = 0; i < 12; i++ ) {
1302
+ months[i] = angular.extend(ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth), {
1303
+ uid: scope.uniqueId + '-' + i
1304
+ });
1305
+ }
1306
+
1307
+ scope.title = dateFilter(ctrl.activeDate, ctrl.formatMonthTitle);
1308
+ scope.rows = ctrl.split(months, 3);
1309
+ };
1310
+
1311
+ ctrl.compare = function(date1, date2) {
1312
+ return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
1313
+ };
1314
+
1315
+ ctrl.handleKeyDown = function( key, evt ) {
1316
+ var date = ctrl.activeDate.getMonth();
1317
+
1318
+ if (key === 'left') {
1319
+ date = date - 1; // up
1320
+ } else if (key === 'up') {
1321
+ date = date - 3; // down
1322
+ } else if (key === 'right') {
1323
+ date = date + 1; // down
1324
+ } else if (key === 'down') {
1325
+ date = date + 3;
1326
+ } else if (key === 'pageup' || key === 'pagedown') {
1327
+ var year = ctrl.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
1328
+ ctrl.activeDate.setFullYear(year);
1329
+ } else if (key === 'home') {
1330
+ date = 0;
1331
+ } else if (key === 'end') {
1332
+ date = 11;
1333
+ }
1334
+ ctrl.activeDate.setMonth(date);
1335
+ };
1336
+
1337
+ ctrl.refreshView();
1338
+ }
1339
+ };
1340
+ }])
1341
+
1342
+ .directive('yearpicker', ['dateFilter', function (dateFilter) {
1343
+ return {
1344
+ restrict: 'EA',
1345
+ replace: true,
1346
+ templateUrl: 'template/datepicker/year.html',
1347
+ require: '^datepicker',
1348
+ link: function(scope, element, attrs, ctrl) {
1349
+ var range = ctrl.yearRange;
1350
+
1351
+ ctrl.step = { years: range };
1352
+ ctrl.element = element;
1353
+
1354
+ function getStartingYear( year ) {
1355
+ return parseInt((year - 1) / range, 10) * range + 1;
1356
+ }
1357
+
1358
+ ctrl._refreshView = function() {
1359
+ var years = new Array(range);
1360
+
1361
+ for ( var i = 0, start = getStartingYear(ctrl.activeDate.getFullYear()); i < range; i++ ) {
1362
+ years[i] = angular.extend(ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear), {
1363
+ uid: scope.uniqueId + '-' + i
1364
+ });
1365
+ }
1366
+
1367
+ scope.title = [years[0].label, years[range - 1].label].join(' - ');
1368
+ scope.rows = ctrl.split(years, 5);
1369
+ };
1370
+
1371
+ ctrl.compare = function(date1, date2) {
1372
+ return date1.getFullYear() - date2.getFullYear();
1373
+ };
1374
+
1375
+ ctrl.handleKeyDown = function( key, evt ) {
1376
+ var date = ctrl.activeDate.getFullYear();
1377
+
1378
+ if (key === 'left') {
1379
+ date = date - 1; // up
1380
+ } else if (key === 'up') {
1381
+ date = date - 5; // down
1382
+ } else if (key === 'right') {
1383
+ date = date + 1; // down
1384
+ } else if (key === 'down') {
1385
+ date = date + 5;
1386
+ } else if (key === 'pageup' || key === 'pagedown') {
1387
+ date += (key === 'pageup' ? - 1 : 1) * ctrl.step.years;
1388
+ } else if (key === 'home') {
1389
+ date = getStartingYear( ctrl.activeDate.getFullYear() );
1390
+ } else if (key === 'end') {
1391
+ date = getStartingYear( ctrl.activeDate.getFullYear() ) + range - 1;
1392
+ }
1393
+ ctrl.activeDate.setFullYear(date);
1394
+ };
1395
+
1396
+ ctrl.refreshView();
1397
+ }
1398
+ };
1399
+ }])
1400
+
1401
+ .constant('datepickerPopupConfig', {
1402
+ datepickerPopup: 'yyyy-MM-dd',
1403
+ currentText: 'Today',
1404
+ clearText: 'Clear',
1405
+ closeText: 'Done',
1406
+ closeOnDateSelection: true,
1407
+ appendToBody: false,
1408
+ showButtonBar: true
1409
+ })
1410
+
1411
+ .directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'dateParser', 'datepickerPopupConfig',
1412
+ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepickerPopupConfig) {
1413
+ return {
1414
+ restrict: 'EA',
1415
+ require: 'ngModel',
1416
+ scope: {
1417
+ isOpen: '=?',
1418
+ currentText: '@',
1419
+ clearText: '@',
1420
+ closeText: '@',
1421
+ dateDisabled: '&'
1422
+ },
1423
+ link: function(scope, element, attrs, ngModel) {
1424
+ var dateFormat,
1425
+ closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection,
1426
+ appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
1427
+
1428
+ scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
1429
+
1430
+ scope.getText = function( key ) {
1431
+ return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
1432
+ };
1433
+
1434
+ attrs.$observe('datepickerPopup', function(value) {
1435
+ dateFormat = value || datepickerPopupConfig.datepickerPopup;
1436
+ ngModel.$render();
1437
+ });
1438
+
1439
+ // popup element used to display calendar
1440
+ var popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>');
1441
+ popupEl.attr({
1442
+ 'ng-model': 'date',
1443
+ 'ng-change': 'dateSelection()'
1444
+ });
1445
+
1446
+ function cameltoDash( string ){
1447
+ return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
1448
+ }
1449
+
1450
+ // datepicker element
1451
+ var datepickerEl = angular.element(popupEl.children()[0]);
1452
+ if ( attrs.datepickerOptions ) {
1453
+ angular.forEach(scope.$parent.$eval(attrs.datepickerOptions), function( value, option ) {
1454
+ datepickerEl.attr( cameltoDash(option), value );
1455
+ });
1456
+ }
1457
+
1458
+ angular.forEach(['minDate', 'maxDate'], function( key ) {
1459
+ if ( attrs[key] ) {
1460
+ scope.$parent.$watch($parse(attrs[key]), function(value){
1461
+ scope[key] = value;
1462
+ });
1463
+ datepickerEl.attr(cameltoDash(key), key);
1464
+ }
1465
+ });
1466
+ if (attrs.dateDisabled) {
1467
+ datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
1468
+ }
1469
+
1470
+ function parseDate(viewValue) {
1471
+ if (!viewValue) {
1472
+ ngModel.$setValidity('date', true);
1473
+ return null;
1474
+ } else if (angular.isDate(viewValue) && !isNaN(viewValue)) {
1475
+ ngModel.$setValidity('date', true);
1476
+ return viewValue;
1477
+ } else if (angular.isString(viewValue)) {
1478
+ var date = dateParser.parse(viewValue, dateFormat) || new Date(viewValue);
1479
+ if (isNaN(date)) {
1480
+ ngModel.$setValidity('date', false);
1481
+ return undefined;
1482
+ } else {
1483
+ ngModel.$setValidity('date', true);
1484
+ return date;
1485
+ }
1486
+ } else {
1487
+ ngModel.$setValidity('date', false);
1488
+ return undefined;
1489
+ }
1490
+ }
1491
+ ngModel.$parsers.unshift(parseDate);
1492
+
1493
+ // Inner change
1494
+ scope.dateSelection = function(dt) {
1495
+ if (angular.isDefined(dt)) {
1496
+ scope.date = dt;
1497
+ }
1498
+ ngModel.$setViewValue(scope.date);
1499
+ ngModel.$render();
1500
+
1501
+ if ( closeOnDateSelection ) {
1502
+ scope.isOpen = false;
1503
+ element[0].focus();
1504
+ }
1505
+ };
1506
+
1507
+ element.bind('input change keyup', function() {
1508
+ scope.$apply(function() {
1509
+ scope.date = ngModel.$modelValue;
1510
+ });
1511
+ });
1512
+
1513
+ // Outter change
1514
+ ngModel.$render = function() {
1515
+ var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
1516
+ element.val(date);
1517
+ scope.date = parseDate( ngModel.$modelValue );
1518
+ };
1519
+
1520
+ var documentClickBind = function(event) {
1521
+ if (scope.isOpen && event.target !== element[0]) {
1522
+ scope.$apply(function() {
1523
+ scope.isOpen = false;
1524
+ });
1525
+ }
1526
+ };
1527
+
1528
+ var keydown = function(evt, noApply) {
1529
+ scope.keydown(evt);
1530
+ };
1531
+ element.bind('keydown', keydown);
1532
+
1533
+ scope.keydown = function(evt) {
1534
+ if (evt.which === 27) {
1535
+ evt.preventDefault();
1536
+ evt.stopPropagation();
1537
+ scope.close();
1538
+ } else if (evt.which === 40 && !scope.isOpen) {
1539
+ scope.isOpen = true;
1540
+ }
1541
+ };
1542
+
1543
+ scope.$watch('isOpen', function(value) {
1544
+ if (value) {
1545
+ scope.$broadcast('datepicker.focus');
1546
+ scope.position = appendToBody ? $position.offset(element) : $position.position(element);
1547
+ scope.position.top = scope.position.top + element.prop('offsetHeight');
1548
+
1549
+ $document.bind('click', documentClickBind);
1550
+ } else {
1551
+ $document.unbind('click', documentClickBind);
1552
+ }
1553
+ });
1554
+
1555
+ scope.select = function( date ) {
1556
+ if (date === 'today') {
1557
+ var today = new Date();
1558
+ if (angular.isDate(ngModel.$modelValue)) {
1559
+ date = new Date(ngModel.$modelValue);
1560
+ date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
1561
+ } else {
1562
+ date = new Date(today.setHours(0, 0, 0, 0));
1563
+ }
1564
+ }
1565
+ scope.dateSelection( date );
1566
+ };
1567
+
1568
+ scope.close = function() {
1569
+ scope.isOpen = false;
1570
+ element[0].focus();
1571
+ };
1572
+
1573
+ var $popup = $compile(popupEl)(scope);
1574
+ if ( appendToBody ) {
1575
+ $document.find('body').append($popup);
1576
+ } else {
1577
+ element.after($popup);
1578
+ }
1579
+
1580
+ scope.$on('$destroy', function() {
1581
+ $popup.remove();
1582
+ element.unbind('keydown', keydown);
1583
+ $document.unbind('click', documentClickBind);
1584
+ });
1585
+ }
1586
+ };
1587
+ }])
1588
+
1589
+ .directive('datepickerPopupWrap', function() {
1590
+ return {
1591
+ restrict:'EA',
1592
+ replace: true,
1593
+ transclude: true,
1594
+ templateUrl: 'template/datepicker/popup.html',
1595
+ link:function (scope, element, attrs) {
1596
+ element.bind('click', function(event) {
1597
+ event.preventDefault();
1598
+ event.stopPropagation();
1599
+ });
1600
+ }
1601
+ };
1602
+ });
1603
+
1604
+ angular.module('ui.bootstrap.dropdown', [])
1605
+
1606
+ .constant('dropdownConfig', {
1607
+ openClass: 'open'
1608
+ })
1609
+
1610
+ .service('dropdownService', ['$document', function($document) {
1611
+ var openScope = null;
1612
+
1613
+ this.open = function( dropdownScope ) {
1614
+ if ( !openScope ) {
1615
+ $document.bind('click', closeDropdown);
1616
+ $document.bind('keydown', escapeKeyBind);
1617
+ }
1618
+
1619
+ if ( openScope && openScope !== dropdownScope ) {
1620
+ openScope.isOpen = false;
1621
+ }
1622
+
1623
+ openScope = dropdownScope;
1624
+ };
1625
+
1626
+ this.close = function( dropdownScope ) {
1627
+ if ( openScope === dropdownScope ) {
1628
+ openScope = null;
1629
+ $document.unbind('click', closeDropdown);
1630
+ $document.unbind('keydown', escapeKeyBind);
1631
+ }
1632
+ };
1633
+
1634
+ var closeDropdown = function( evt ) {
1635
+ if (evt && evt.isDefaultPrevented()) {
1636
+ return;
1637
+ }
1638
+
1639
+ openScope.$apply(function() {
1640
+ openScope.isOpen = false;
1641
+ });
1642
+ };
1643
+
1644
+ var escapeKeyBind = function( evt ) {
1645
+ if ( evt.which === 27 ) {
1646
+ openScope.focusToggleElement();
1647
+ closeDropdown();
1648
+ }
1649
+ };
1650
+ }])
1651
+
1652
+ .controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) {
1653
+ var self = this,
1654
+ scope = $scope.$new(), // create a child scope so we are not polluting original one
1655
+ openClass = dropdownConfig.openClass,
1656
+ getIsOpen,
1657
+ setIsOpen = angular.noop,
1658
+ toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop;
1659
+
1660
+ this.init = function( element ) {
1661
+ self.$element = element;
1662
+
1663
+ if ( $attrs.isOpen ) {
1664
+ getIsOpen = $parse($attrs.isOpen);
1665
+ setIsOpen = getIsOpen.assign;
1666
+
1667
+ $scope.$watch(getIsOpen, function(value) {
1668
+ scope.isOpen = !!value;
1669
+ });
1670
+ }
1671
+ };
1672
+
1673
+ this.toggle = function( open ) {
1674
+ return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
1675
+ };
1676
+
1677
+ // Allow other directives to watch status
1678
+ this.isOpen = function() {
1679
+ return scope.isOpen;
1680
+ };
1681
+
1682
+ scope.focusToggleElement = function() {
1683
+ if ( self.toggleElement ) {
1684
+ self.toggleElement[0].focus();
1685
+ }
1686
+ };
1687
+
1688
+ scope.$watch('isOpen', function( isOpen, wasOpen ) {
1689
+ $animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass);
1690
+
1691
+ if ( isOpen ) {
1692
+ scope.focusToggleElement();
1693
+ dropdownService.open( scope );
1694
+ } else {
1695
+ dropdownService.close( scope );
1696
+ }
1697
+
1698
+ setIsOpen($scope, isOpen);
1699
+ if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
1700
+ toggleInvoker($scope, { open: !!isOpen });
1701
+ }
1702
+ });
1703
+
1704
+ $scope.$on('$locationChangeSuccess', function() {
1705
+ scope.isOpen = false;
1706
+ });
1707
+
1708
+ $scope.$on('$destroy', function() {
1709
+ scope.$destroy();
1710
+ });
1711
+ }])
1712
+
1713
+ .directive('dropdown', function() {
1714
+ return {
1715
+ restrict: 'CA',
1716
+ controller: 'DropdownController',
1717
+ link: function(scope, element, attrs, dropdownCtrl) {
1718
+ dropdownCtrl.init( element );
1719
+ }
1720
+ };
1721
+ })
1722
+
1723
+ .directive('dropdownToggle', function() {
1724
+ return {
1725
+ restrict: 'CA',
1726
+ require: '?^dropdown',
1727
+ link: function(scope, element, attrs, dropdownCtrl) {
1728
+ if ( !dropdownCtrl ) {
1729
+ return;
1730
+ }
1731
+
1732
+ dropdownCtrl.toggleElement = element;
1733
+
1734
+ var toggleDropdown = function(event) {
1735
+ event.preventDefault();
1736
+
1737
+ if ( !element.hasClass('disabled') && !attrs.disabled ) {
1738
+ scope.$apply(function() {
1739
+ dropdownCtrl.toggle();
1740
+ });
1741
+ }
1742
+ };
1743
+
1744
+ element.bind('click', toggleDropdown);
1745
+
1746
+ // WAI-ARIA
1747
+ element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
1748
+ scope.$watch(dropdownCtrl.isOpen, function( isOpen ) {
1749
+ element.attr('aria-expanded', !!isOpen);
1750
+ });
1751
+
1752
+ scope.$on('$destroy', function() {
1753
+ element.unbind('click', toggleDropdown);
1754
+ });
1755
+ }
1756
+ };
1757
+ });
1758
+
1759
+ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
1760
+
1761
+ /**
1762
+ * A helper, internal data structure that acts as a map but also allows getting / removing
1763
+ * elements in the LIFO order
1764
+ */
1765
+ .factory('$$stackedMap', function () {
1766
+ return {
1767
+ createNew: function () {
1768
+ var stack = [];
1769
+
1770
+ return {
1771
+ add: function (key, value) {
1772
+ stack.push({
1773
+ key: key,
1774
+ value: value
1775
+ });
1776
+ },
1777
+ get: function (key) {
1778
+ for (var i = 0; i < stack.length; i++) {
1779
+ if (key == stack[i].key) {
1780
+ return stack[i];
1781
+ }
1782
+ }
1783
+ },
1784
+ keys: function() {
1785
+ var keys = [];
1786
+ for (var i = 0; i < stack.length; i++) {
1787
+ keys.push(stack[i].key);
1788
+ }
1789
+ return keys;
1790
+ },
1791
+ top: function () {
1792
+ return stack[stack.length - 1];
1793
+ },
1794
+ remove: function (key) {
1795
+ var idx = -1;
1796
+ for (var i = 0; i < stack.length; i++) {
1797
+ if (key == stack[i].key) {
1798
+ idx = i;
1799
+ break;
1800
+ }
1801
+ }
1802
+ return stack.splice(idx, 1)[0];
1803
+ },
1804
+ removeTop: function () {
1805
+ return stack.splice(stack.length - 1, 1)[0];
1806
+ },
1807
+ length: function () {
1808
+ return stack.length;
1809
+ }
1810
+ };
1811
+ }
1812
+ };
1813
+ })
1814
+
1815
+ /**
1816
+ * A helper directive for the $modal service. It creates a backdrop element.
1817
+ */
1818
+ .directive('modalBackdrop', ['$timeout', function ($timeout) {
1819
+ return {
1820
+ restrict: 'EA',
1821
+ replace: true,
1822
+ templateUrl: 'template/modal/backdrop.html',
1823
+ link: function (scope) {
1824
+
1825
+ scope.animate = false;
1826
+
1827
+ //trigger CSS transitions
1828
+ $timeout(function () {
1829
+ scope.animate = true;
1830
+ });
1831
+ }
1832
+ };
1833
+ }])
1834
+
1835
+ .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
1836
+ return {
1837
+ restrict: 'EA',
1838
+ scope: {
1839
+ index: '@',
1840
+ animate: '='
1841
+ },
1842
+ replace: true,
1843
+ transclude: true,
1844
+ templateUrl: function(tElement, tAttrs) {
1845
+ return tAttrs.templateUrl || 'template/modal/window.html';
1846
+ },
1847
+ link: function (scope, element, attrs) {
1848
+ element.addClass(attrs.windowClass || '');
1849
+ scope.size = attrs.size;
1850
+
1851
+ $timeout(function () {
1852
+ // trigger CSS transitions
1853
+ scope.animate = true;
1854
+ // focus a freshly-opened modal
1855
+ element[0].focus();
1856
+ });
1857
+
1858
+ scope.close = function (evt) {
1859
+ var modal = $modalStack.getTop();
1860
+ if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
1861
+ evt.preventDefault();
1862
+ evt.stopPropagation();
1863
+ $modalStack.dismiss(modal.key, 'backdrop click');
1864
+ }
1865
+ };
1866
+ }
1867
+ };
1868
+ }])
1869
+
1870
+ .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
1871
+ function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) {
1872
+
1873
+ var OPENED_MODAL_CLASS = 'modal-open';
1874
+
1875
+ var backdropDomEl, backdropScope;
1876
+ var openedWindows = $$stackedMap.createNew();
1877
+ var $modalStack = {};
1878
+
1879
+ function backdropIndex() {
1880
+ var topBackdropIndex = -1;
1881
+ var opened = openedWindows.keys();
1882
+ for (var i = 0; i < opened.length; i++) {
1883
+ if (openedWindows.get(opened[i]).value.backdrop) {
1884
+ topBackdropIndex = i;
1885
+ }
1886
+ }
1887
+ return topBackdropIndex;
1888
+ }
1889
+
1890
+ $rootScope.$watch(backdropIndex, function(newBackdropIndex){
1891
+ if (backdropScope) {
1892
+ backdropScope.index = newBackdropIndex;
1893
+ }
1894
+ });
1895
+
1896
+ function removeModalWindow(modalInstance) {
1897
+
1898
+ var body = $document.find('body').eq(0);
1899
+ var modalWindow = openedWindows.get(modalInstance).value;
1900
+
1901
+ //clean up the stack
1902
+ openedWindows.remove(modalInstance);
1903
+
1904
+ //remove window DOM element
1905
+ removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, function() {
1906
+ modalWindow.modalScope.$destroy();
1907
+ body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
1908
+ checkRemoveBackdrop();
1909
+ });
1910
+ }
1911
+
1912
+ function checkRemoveBackdrop() {
1913
+ //remove backdrop if no longer needed
1914
+ if (backdropDomEl && backdropIndex() == -1) {
1915
+ var backdropScopeRef = backdropScope;
1916
+ removeAfterAnimate(backdropDomEl, backdropScope, 150, function () {
1917
+ backdropScopeRef.$destroy();
1918
+ backdropScopeRef = null;
1919
+ });
1920
+ backdropDomEl = undefined;
1921
+ backdropScope = undefined;
1922
+ }
1923
+ }
1924
+
1925
+ function removeAfterAnimate(domEl, scope, emulateTime, done) {
1926
+ // Closing animation
1927
+ scope.animate = false;
1928
+
1929
+ var transitionEndEventName = $transition.transitionEndEventName;
1930
+ if (transitionEndEventName) {
1931
+ // transition out
1932
+ var timeout = $timeout(afterAnimating, emulateTime);
1933
+
1934
+ domEl.bind(transitionEndEventName, function () {
1935
+ $timeout.cancel(timeout);
1936
+ afterAnimating();
1937
+ scope.$apply();
1938
+ });
1939
+ } else {
1940
+ // Ensure this call is async
1941
+ $timeout(afterAnimating, 0);
1942
+ }
1943
+
1944
+ function afterAnimating() {
1945
+ if (afterAnimating.done) {
1946
+ return;
1947
+ }
1948
+ afterAnimating.done = true;
1949
+
1950
+ domEl.remove();
1951
+ if (done) {
1952
+ done();
1953
+ }
1954
+ }
1955
+ }
1956
+
1957
+ $document.bind('keydown', function (evt) {
1958
+ var modal;
1959
+
1960
+ if (evt.which === 27) {
1961
+ modal = openedWindows.top();
1962
+ if (modal && modal.value.keyboard) {
1963
+ evt.preventDefault();
1964
+ $rootScope.$apply(function () {
1965
+ $modalStack.dismiss(modal.key, 'escape key press');
1966
+ });
1967
+ }
1968
+ }
1969
+ });
1970
+
1971
+ $modalStack.open = function (modalInstance, modal) {
1972
+
1973
+ openedWindows.add(modalInstance, {
1974
+ deferred: modal.deferred,
1975
+ modalScope: modal.scope,
1976
+ backdrop: modal.backdrop,
1977
+ keyboard: modal.keyboard
1978
+ });
1979
+
1980
+ var body = $document.find('body').eq(0),
1981
+ currBackdropIndex = backdropIndex();
1982
+
1983
+ if (currBackdropIndex >= 0 && !backdropDomEl) {
1984
+ backdropScope = $rootScope.$new(true);
1985
+ backdropScope.index = currBackdropIndex;
1986
+ backdropDomEl = $compile('<div modal-backdrop></div>')(backdropScope);
1987
+ body.append(backdropDomEl);
1988
+ }
1989
+
1990
+ var angularDomEl = angular.element('<div modal-window></div>');
1991
+ angularDomEl.attr({
1992
+ 'template-url': modal.windowTemplateUrl,
1993
+ 'window-class': modal.windowClass,
1994
+ 'size': modal.size,
1995
+ 'index': openedWindows.length() - 1,
1996
+ 'animate': 'animate'
1997
+ }).html(modal.content);
1998
+
1999
+ var modalDomEl = $compile(angularDomEl)(modal.scope);
2000
+ openedWindows.top().value.modalDomEl = modalDomEl;
2001
+ body.append(modalDomEl);
2002
+ body.addClass(OPENED_MODAL_CLASS);
2003
+ };
2004
+
2005
+ $modalStack.close = function (modalInstance, result) {
2006
+ var modalWindow = openedWindows.get(modalInstance).value;
2007
+ if (modalWindow) {
2008
+ modalWindow.deferred.resolve(result);
2009
+ removeModalWindow(modalInstance);
2010
+ }
2011
+ };
2012
+
2013
+ $modalStack.dismiss = function (modalInstance, reason) {
2014
+ var modalWindow = openedWindows.get(modalInstance).value;
2015
+ if (modalWindow) {
2016
+ modalWindow.deferred.reject(reason);
2017
+ removeModalWindow(modalInstance);
2018
+ }
2019
+ };
2020
+
2021
+ $modalStack.dismissAll = function (reason) {
2022
+ var topModal = this.getTop();
2023
+ while (topModal) {
2024
+ this.dismiss(topModal.key, reason);
2025
+ topModal = this.getTop();
2026
+ }
2027
+ };
2028
+
2029
+ $modalStack.getTop = function () {
2030
+ return openedWindows.top();
2031
+ };
2032
+
2033
+ return $modalStack;
2034
+ }])
2035
+
2036
+ .provider('$modal', function () {
2037
+
2038
+ var $modalProvider = {
2039
+ options: {
2040
+ backdrop: true, //can be also false or 'static'
2041
+ keyboard: true
2042
+ },
2043
+ $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
2044
+ function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
2045
+
2046
+ var $modal = {};
2047
+
2048
+ function getTemplatePromise(options) {
2049
+ return options.template ? $q.when(options.template) :
2050
+ $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
2051
+ return result.data;
2052
+ });
2053
+ }
2054
+
2055
+ function getResolvePromises(resolves) {
2056
+ var promisesArr = [];
2057
+ angular.forEach(resolves, function (value, key) {
2058
+ if (angular.isFunction(value) || angular.isArray(value)) {
2059
+ promisesArr.push($q.when($injector.invoke(value)));
2060
+ }
2061
+ });
2062
+ return promisesArr;
2063
+ }
2064
+
2065
+ $modal.open = function (modalOptions) {
2066
+
2067
+ var modalResultDeferred = $q.defer();
2068
+ var modalOpenedDeferred = $q.defer();
2069
+
2070
+ //prepare an instance of a modal to be injected into controllers and returned to a caller
2071
+ var modalInstance = {
2072
+ result: modalResultDeferred.promise,
2073
+ opened: modalOpenedDeferred.promise,
2074
+ close: function (result) {
2075
+ $modalStack.close(modalInstance, result);
2076
+ },
2077
+ dismiss: function (reason) {
2078
+ $modalStack.dismiss(modalInstance, reason);
2079
+ }
2080
+ };
2081
+
2082
+ //merge and clean up options
2083
+ modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
2084
+ modalOptions.resolve = modalOptions.resolve || {};
2085
+
2086
+ //verify options
2087
+ if (!modalOptions.template && !modalOptions.templateUrl) {
2088
+ throw new Error('One of template or templateUrl options is required.');
2089
+ }
2090
+
2091
+ var templateAndResolvePromise =
2092
+ $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
2093
+
2094
+
2095
+ templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
2096
+
2097
+ var modalScope = (modalOptions.scope || $rootScope).$new();
2098
+ modalScope.$close = modalInstance.close;
2099
+ modalScope.$dismiss = modalInstance.dismiss;
2100
+
2101
+ var ctrlInstance, ctrlLocals = {};
2102
+ var resolveIter = 1;
2103
+
2104
+ //controllers
2105
+ if (modalOptions.controller) {
2106
+ ctrlLocals.$scope = modalScope;
2107
+ ctrlLocals.$modalInstance = modalInstance;
2108
+ angular.forEach(modalOptions.resolve, function (value, key) {
2109
+ ctrlLocals[key] = tplAndVars[resolveIter++];
2110
+ });
2111
+
2112
+ ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
2113
+ }
2114
+
2115
+ $modalStack.open(modalInstance, {
2116
+ scope: modalScope,
2117
+ deferred: modalResultDeferred,
2118
+ content: tplAndVars[0],
2119
+ backdrop: modalOptions.backdrop,
2120
+ keyboard: modalOptions.keyboard,
2121
+ windowClass: modalOptions.windowClass,
2122
+ windowTemplateUrl: modalOptions.windowTemplateUrl,
2123
+ size: modalOptions.size
2124
+ });
2125
+
2126
+ }, function resolveError(reason) {
2127
+ modalResultDeferred.reject(reason);
2128
+ });
2129
+
2130
+ templateAndResolvePromise.then(function () {
2131
+ modalOpenedDeferred.resolve(true);
2132
+ }, function () {
2133
+ modalOpenedDeferred.reject(false);
2134
+ });
2135
+
2136
+ return modalInstance;
2137
+ };
2138
+
2139
+ return $modal;
2140
+ }]
2141
+ };
2142
+
2143
+ return $modalProvider;
2144
+ });
2145
+
2146
+ angular.module('ui.bootstrap.pagination', [])
2147
+
2148
+ .controller('PaginationController', ['$scope', '$attrs', '$parse', function ($scope, $attrs, $parse) {
2149
+ var self = this,
2150
+ ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
2151
+ setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
2152
+
2153
+ this.init = function(ngModelCtrl_, config) {
2154
+ ngModelCtrl = ngModelCtrl_;
2155
+ this.config = config;
2156
+
2157
+ ngModelCtrl.$render = function() {
2158
+ self.render();
2159
+ };
2160
+
2161
+ if ($attrs.itemsPerPage) {
2162
+ $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
2163
+ self.itemsPerPage = parseInt(value, 10);
2164
+ $scope.totalPages = self.calculateTotalPages();
2165
+ });
2166
+ } else {
2167
+ this.itemsPerPage = config.itemsPerPage;
2168
+ }
2169
+ };
2170
+
2171
+ this.calculateTotalPages = function() {
2172
+ var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
2173
+ return Math.max(totalPages || 0, 1);
2174
+ };
2175
+
2176
+ this.render = function() {
2177
+ $scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1;
2178
+ };
2179
+
2180
+ $scope.selectPage = function(page) {
2181
+ if ( $scope.page !== page && page > 0 && page <= $scope.totalPages) {
2182
+ ngModelCtrl.$setViewValue(page);
2183
+ ngModelCtrl.$render();
2184
+ }
2185
+ };
2186
+
2187
+ $scope.getText = function( key ) {
2188
+ return $scope[key + 'Text'] || self.config[key + 'Text'];
2189
+ };
2190
+ $scope.noPrevious = function() {
2191
+ return $scope.page === 1;
2192
+ };
2193
+ $scope.noNext = function() {
2194
+ return $scope.page === $scope.totalPages;
2195
+ };
2196
+
2197
+ $scope.$watch('totalItems', function() {
2198
+ $scope.totalPages = self.calculateTotalPages();
2199
+ });
2200
+
2201
+ $scope.$watch('totalPages', function(value) {
2202
+ setNumPages($scope.$parent, value); // Readonly variable
2203
+
2204
+ if ( $scope.page > value ) {
2205
+ $scope.selectPage(value);
2206
+ } else {
2207
+ ngModelCtrl.$render();
2208
+ }
2209
+ });
2210
+ }])
2211
+
2212
+ .constant('paginationConfig', {
2213
+ itemsPerPage: 10,
2214
+ boundaryLinks: false,
2215
+ directionLinks: true,
2216
+ firstText: 'First',
2217
+ previousText: 'Previous',
2218
+ nextText: 'Next',
2219
+ lastText: 'Last',
2220
+ rotate: true
2221
+ })
2222
+
2223
+ .directive('pagination', ['$parse', 'paginationConfig', function($parse, paginationConfig) {
2224
+ return {
2225
+ restrict: 'EA',
2226
+ scope: {
2227
+ totalItems: '=',
2228
+ firstText: '@',
2229
+ previousText: '@',
2230
+ nextText: '@',
2231
+ lastText: '@'
2232
+ },
2233
+ require: ['pagination', '?ngModel'],
2234
+ controller: 'PaginationController',
2235
+ templateUrl: 'template/pagination/pagination.html',
2236
+ replace: true,
2237
+ link: function(scope, element, attrs, ctrls) {
2238
+ var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
2239
+
2240
+ if (!ngModelCtrl) {
2241
+ return; // do nothing if no ng-model
2242
+ }
2243
+
2244
+ // Setup configuration parameters
2245
+ var maxSize = angular.isDefined(attrs.maxSize) ? scope.$parent.$eval(attrs.maxSize) : paginationConfig.maxSize,
2246
+ rotate = angular.isDefined(attrs.rotate) ? scope.$parent.$eval(attrs.rotate) : paginationConfig.rotate;
2247
+ scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
2248
+ scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : paginationConfig.directionLinks;
2249
+
2250
+ paginationCtrl.init(ngModelCtrl, paginationConfig);
2251
+
2252
+ if (attrs.maxSize) {
2253
+ scope.$parent.$watch($parse(attrs.maxSize), function(value) {
2254
+ maxSize = parseInt(value, 10);
2255
+ paginationCtrl.render();
2256
+ });
2257
+ }
2258
+
2259
+ // Create page object used in template
2260
+ function makePage(number, text, isActive) {
2261
+ return {
2262
+ number: number,
2263
+ text: text,
2264
+ active: isActive
2265
+ };
2266
+ }
2267
+
2268
+ function getPages(currentPage, totalPages) {
2269
+ var pages = [];
2270
+
2271
+ // Default page limits
2272
+ var startPage = 1, endPage = totalPages;
2273
+ var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages );
2274
+
2275
+ // recompute if maxSize
2276
+ if ( isMaxSized ) {
2277
+ if ( rotate ) {
2278
+ // Current page is displayed in the middle of the visible ones
2279
+ startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
2280
+ endPage = startPage + maxSize - 1;
2281
+
2282
+ // Adjust if limit is exceeded
2283
+ if (endPage > totalPages) {
2284
+ endPage = totalPages;
2285
+ startPage = endPage - maxSize + 1;
2286
+ }
2287
+ } else {
2288
+ // Visible pages are paginated with maxSize
2289
+ startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
2290
+
2291
+ // Adjust last page if limit is exceeded
2292
+ endPage = Math.min(startPage + maxSize - 1, totalPages);
2293
+ }
2294
+ }
2295
+
2296
+ // Add page number links
2297
+ for (var number = startPage; number <= endPage; number++) {
2298
+ var page = makePage(number, number, number === currentPage);
2299
+ pages.push(page);
2300
+ }
2301
+
2302
+ // Add links to move between page sets
2303
+ if ( isMaxSized && ! rotate ) {
2304
+ if ( startPage > 1 ) {
2305
+ var previousPageSet = makePage(startPage - 1, '...', false);
2306
+ pages.unshift(previousPageSet);
2307
+ }
2308
+
2309
+ if ( endPage < totalPages ) {
2310
+ var nextPageSet = makePage(endPage + 1, '...', false);
2311
+ pages.push(nextPageSet);
2312
+ }
2313
+ }
2314
+
2315
+ return pages;
2316
+ }
2317
+
2318
+ var originalRender = paginationCtrl.render;
2319
+ paginationCtrl.render = function() {
2320
+ originalRender();
2321
+ if (scope.page > 0 && scope.page <= scope.totalPages) {
2322
+ scope.pages = getPages(scope.page, scope.totalPages);
2323
+ }
2324
+ };
2325
+ }
2326
+ };
2327
+ }])
2328
+
2329
+ .constant('pagerConfig', {
2330
+ itemsPerPage: 10,
2331
+ previousText: '« Previous',
2332
+ nextText: 'Next »',
2333
+ align: true
2334
+ })
2335
+
2336
+ .directive('pager', ['pagerConfig', function(pagerConfig) {
2337
+ return {
2338
+ restrict: 'EA',
2339
+ scope: {
2340
+ totalItems: '=',
2341
+ previousText: '@',
2342
+ nextText: '@'
2343
+ },
2344
+ require: ['pager', '?ngModel'],
2345
+ controller: 'PaginationController',
2346
+ templateUrl: 'template/pagination/pager.html',
2347
+ replace: true,
2348
+ link: function(scope, element, attrs, ctrls) {
2349
+ var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
2350
+
2351
+ if (!ngModelCtrl) {
2352
+ return; // do nothing if no ng-model
2353
+ }
2354
+
2355
+ scope.align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : pagerConfig.align;
2356
+ paginationCtrl.init(ngModelCtrl, pagerConfig);
2357
+ }
2358
+ };
2359
+ }]);
2360
+
2361
+ /**
2362
+ * The following features are still outstanding: animation as a
2363
+ * function, placement as a function, inside, support for more triggers than
2364
+ * just mouse enter/leave, html tooltips, and selector delegation.
2365
+ */
2366
+ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] )
2367
+
2368
+ /**
2369
+ * The $tooltip service creates tooltip- and popover-like directives as well as
2370
+ * houses global options for them.
2371
+ */
2372
+ .provider( '$tooltip', function () {
2373
+ // The default options tooltip and popover.
2374
+ var defaultOptions = {
2375
+ placement: 'top',
2376
+ animation: true,
2377
+ popupDelay: 0
2378
+ };
2379
+
2380
+ // Default hide triggers for each show trigger
2381
+ var triggerMap = {
2382
+ 'mouseenter': 'mouseleave',
2383
+ 'click': 'click',
2384
+ 'focus': 'blur'
2385
+ };
2386
+
2387
+ // The options specified to the provider globally.
2388
+ var globalOptions = {};
2389
+
2390
+ /**
2391
+ * `options({})` allows global configuration of all tooltips in the
2392
+ * application.
2393
+ *
2394
+ * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
2395
+ * // place tooltips left instead of top by default
2396
+ * $tooltipProvider.options( { placement: 'left' } );
2397
+ * });
2398
+ */
2399
+ this.options = function( value ) {
2400
+ angular.extend( globalOptions, value );
2401
+ };
2402
+
2403
+ /**
2404
+ * This allows you to extend the set of trigger mappings available. E.g.:
2405
+ *
2406
+ * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
2407
+ */
2408
+ this.setTriggers = function setTriggers ( triggers ) {
2409
+ angular.extend( triggerMap, triggers );
2410
+ };
2411
+
2412
+ /**
2413
+ * This is a helper function for translating camel-case to snake-case.
2414
+ */
2415
+ function snake_case(name){
2416
+ var regexp = /[A-Z]/g;
2417
+ var separator = '-';
2418
+ return name.replace(regexp, function(letter, pos) {
2419
+ return (pos ? separator : '') + letter.toLowerCase();
2420
+ });
2421
+ }
2422
+
2423
+ /**
2424
+ * Returns the actual instance of the $tooltip service.
2425
+ * TODO support multiple triggers
2426
+ */
2427
+ this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) {
2428
+ return function $tooltip ( type, prefix, defaultTriggerShow ) {
2429
+ var options = angular.extend( {}, defaultOptions, globalOptions );
2430
+
2431
+ /**
2432
+ * Returns an object of show and hide triggers.
2433
+ *
2434
+ * If a trigger is supplied,
2435
+ * it is used to show the tooltip; otherwise, it will use the `trigger`
2436
+ * option passed to the `$tooltipProvider.options` method; else it will
2437
+ * default to the trigger supplied to this directive factory.
2438
+ *
2439
+ * The hide trigger is based on the show trigger. If the `trigger` option
2440
+ * was passed to the `$tooltipProvider.options` method, it will use the
2441
+ * mapped trigger from `triggerMap` or the passed trigger if the map is
2442
+ * undefined; otherwise, it uses the `triggerMap` value of the show
2443
+ * trigger; else it will just use the show trigger.
2444
+ */
2445
+ function getTriggers ( trigger ) {
2446
+ var show = trigger || options.trigger || defaultTriggerShow;
2447
+ var hide = triggerMap[show] || show;
2448
+ return {
2449
+ show: show,
2450
+ hide: hide
2451
+ };
2452
+ }
2453
+
2454
+ var directiveName = snake_case( type );
2455
+
2456
+ var startSym = $interpolate.startSymbol();
2457
+ var endSym = $interpolate.endSymbol();
2458
+ var template =
2459
+ '<div '+ directiveName +'-popup '+
2460
+ 'title="'+startSym+'tt_title'+endSym+'" '+
2461
+ 'content="'+startSym+'tt_content'+endSym+'" '+
2462
+ 'placement="'+startSym+'tt_placement'+endSym+'" '+
2463
+ 'animation="tt_animation" '+
2464
+ 'is-open="tt_isOpen"'+
2465
+ '>'+
2466
+ '</div>';
2467
+
2468
+ return {
2469
+ restrict: 'EA',
2470
+ scope: true,
2471
+ compile: function (tElem, tAttrs) {
2472
+ var tooltipLinker = $compile( template );
2473
+
2474
+ return function link ( scope, element, attrs ) {
2475
+ var tooltip;
2476
+ var transitionTimeout;
2477
+ var popupTimeout;
2478
+ var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
2479
+ var triggers = getTriggers( undefined );
2480
+ var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']);
2481
+
2482
+ var positionTooltip = function () {
2483
+
2484
+ var ttPosition = $position.positionElements(element, tooltip, scope.tt_placement, appendToBody);
2485
+ ttPosition.top += 'px';
2486
+ ttPosition.left += 'px';
2487
+
2488
+ // Now set the calculated positioning.
2489
+ tooltip.css( ttPosition );
2490
+ };
2491
+
2492
+ // By default, the tooltip is not open.
2493
+ // TODO add ability to start tooltip opened
2494
+ scope.tt_isOpen = false;
2495
+
2496
+ function toggleTooltipBind () {
2497
+ if ( ! scope.tt_isOpen ) {
2498
+ showTooltipBind();
2499
+ } else {
2500
+ hideTooltipBind();
2501
+ }
2502
+ }
2503
+
2504
+ // Show the tooltip with delay if specified, otherwise show it immediately
2505
+ function showTooltipBind() {
2506
+ if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) {
2507
+ return;
2508
+ }
2509
+ if ( scope.tt_popupDelay ) {
2510
+ // Do nothing if the tooltip was already scheduled to pop-up.
2511
+ // This happens if show is triggered multiple times before any hide is triggered.
2512
+ if (!popupTimeout) {
2513
+ popupTimeout = $timeout( show, scope.tt_popupDelay, false );
2514
+ popupTimeout.then(function(reposition){reposition();});
2515
+ }
2516
+ } else {
2517
+ show()();
2518
+ }
2519
+ }
2520
+
2521
+ function hideTooltipBind () {
2522
+ scope.$apply(function () {
2523
+ hide();
2524
+ });
2525
+ }
2526
+
2527
+ // Show the tooltip popup element.
2528
+ function show() {
2529
+
2530
+ popupTimeout = null;
2531
+
2532
+ // If there is a pending remove transition, we must cancel it, lest the
2533
+ // tooltip be mysteriously removed.
2534
+ if ( transitionTimeout ) {
2535
+ $timeout.cancel( transitionTimeout );
2536
+ transitionTimeout = null;
2537
+ }
2538
+
2539
+ // Don't show empty tooltips.
2540
+ if ( ! scope.tt_content ) {
2541
+ return angular.noop;
2542
+ }
2543
+
2544
+ createTooltip();
2545
+
2546
+ // Set the initial positioning.
2547
+ tooltip.css({ top: 0, left: 0, display: 'block' });
2548
+
2549
+ // Now we add it to the DOM because need some info about it. But it's not
2550
+ // visible yet anyway.
2551
+ if ( appendToBody ) {
2552
+ $document.find( 'body' ).append( tooltip );
2553
+ } else {
2554
+ element.after( tooltip );
2555
+ }
2556
+
2557
+ positionTooltip();
2558
+
2559
+ // And show the tooltip.
2560
+ scope.tt_isOpen = true;
2561
+ scope.$digest(); // digest required as $apply is not called
2562
+
2563
+ // Return positioning function as promise callback for correct
2564
+ // positioning after draw.
2565
+ return positionTooltip;
2566
+ }
2567
+
2568
+ // Hide the tooltip popup element.
2569
+ function hide() {
2570
+ // First things first: we don't show it anymore.
2571
+ scope.tt_isOpen = false;
2572
+
2573
+ //if tooltip is going to be shown after delay, we must cancel this
2574
+ $timeout.cancel( popupTimeout );
2575
+ popupTimeout = null;
2576
+
2577
+ // And now we remove it from the DOM. However, if we have animation, we
2578
+ // need to wait for it to expire beforehand.
2579
+ // FIXME: this is a placeholder for a port of the transitions library.
2580
+ if ( scope.tt_animation ) {
2581
+ if (!transitionTimeout) {
2582
+ transitionTimeout = $timeout(removeTooltip, 500);
2583
+ }
2584
+ } else {
2585
+ removeTooltip();
2586
+ }
2587
+ }
2588
+
2589
+ function createTooltip() {
2590
+ // There can only be one tooltip element per directive shown at once.
2591
+ if (tooltip) {
2592
+ removeTooltip();
2593
+ }
2594
+ tooltip = tooltipLinker(scope, function () {});
2595
+
2596
+ // Get contents rendered into the tooltip
2597
+ scope.$digest();
2598
+ }
2599
+
2600
+ function removeTooltip() {
2601
+ transitionTimeout = null;
2602
+ if (tooltip) {
2603
+ tooltip.remove();
2604
+ tooltip = null;
2605
+ }
2606
+ }
2607
+
2608
+ /**
2609
+ * Observe the relevant attributes.
2610
+ */
2611
+ attrs.$observe( type, function ( val ) {
2612
+ scope.tt_content = val;
2613
+
2614
+ if (!val && scope.tt_isOpen ) {
2615
+ hide();
2616
+ }
2617
+ });
2618
+
2619
+ attrs.$observe( prefix+'Title', function ( val ) {
2620
+ scope.tt_title = val;
2621
+ });
2622
+
2623
+ attrs.$observe( prefix+'Placement', function ( val ) {
2624
+ scope.tt_placement = angular.isDefined( val ) ? val : options.placement;
2625
+ });
2626
+
2627
+ attrs.$observe( prefix+'PopupDelay', function ( val ) {
2628
+ var delay = parseInt( val, 10 );
2629
+ scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
2630
+ });
2631
+
2632
+ var unregisterTriggers = function () {
2633
+ element.unbind(triggers.show, showTooltipBind);
2634
+ element.unbind(triggers.hide, hideTooltipBind);
2635
+ };
2636
+
2637
+ attrs.$observe( prefix+'Trigger', function ( val ) {
2638
+ unregisterTriggers();
2639
+
2640
+ triggers = getTriggers( val );
2641
+
2642
+ if ( triggers.show === triggers.hide ) {
2643
+ element.bind( triggers.show, toggleTooltipBind );
2644
+ } else {
2645
+ element.bind( triggers.show, showTooltipBind );
2646
+ element.bind( triggers.hide, hideTooltipBind );
2647
+ }
2648
+ });
2649
+
2650
+ var animation = scope.$eval(attrs[prefix + 'Animation']);
2651
+ scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation;
2652
+
2653
+ attrs.$observe( prefix+'AppendToBody', function ( val ) {
2654
+ appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody;
2655
+ });
2656
+
2657
+ // if a tooltip is attached to <body> we need to remove it on
2658
+ // location change as its parent scope will probably not be destroyed
2659
+ // by the change.
2660
+ if ( appendToBody ) {
2661
+ scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () {
2662
+ if ( scope.tt_isOpen ) {
2663
+ hide();
2664
+ }
2665
+ });
2666
+ }
2667
+
2668
+ // Make sure tooltip is destroyed and removed.
2669
+ scope.$on('$destroy', function onDestroyTooltip() {
2670
+ $timeout.cancel( transitionTimeout );
2671
+ $timeout.cancel( popupTimeout );
2672
+ unregisterTriggers();
2673
+ removeTooltip();
2674
+ });
2675
+ };
2676
+ }
2677
+ };
2678
+ };
2679
+ }];
2680
+ })
2681
+
2682
+ .directive( 'tooltipPopup', function () {
2683
+ return {
2684
+ restrict: 'EA',
2685
+ replace: true,
2686
+ scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
2687
+ templateUrl: 'template/tooltip/tooltip-popup.html'
2688
+ };
2689
+ })
2690
+
2691
+ .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) {
2692
+ return $tooltip( 'tooltip', 'tooltip', 'mouseenter' );
2693
+ }])
2694
+
2695
+ .directive( 'tooltipHtmlUnsafePopup', function () {
2696
+ return {
2697
+ restrict: 'EA',
2698
+ replace: true,
2699
+ scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
2700
+ templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html'
2701
+ };
2702
+ })
2703
+
2704
+ .directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) {
2705
+ return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' );
2706
+ }]);
2707
+
2708
+ /**
2709
+ * The following features are still outstanding: popup delay, animation as a
2710
+ * function, placement as a function, inside, support for more triggers than
2711
+ * just mouse enter/leave, html popovers, and selector delegatation.
2712
+ */
2713
+ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
2714
+
2715
+ .directive( 'popoverPopup', function () {
2716
+ return {
2717
+ restrict: 'EA',
2718
+ replace: true,
2719
+ scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
2720
+ templateUrl: 'template/popover/popover.html'
2721
+ };
2722
+ })
2723
+
2724
+ .directive( 'popover', [ '$tooltip', function ( $tooltip ) {
2725
+ return $tooltip( 'popover', 'popover', 'click' );
2726
+ }]);
2727
+
2728
+ angular.module('ui.bootstrap.progressbar', [])
2729
+
2730
+ .constant('progressConfig', {
2731
+ animate: true,
2732
+ max: 100
2733
+ })
2734
+
2735
+ .controller('ProgressController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) {
2736
+ var self = this,
2737
+ animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
2738
+
2739
+ this.bars = [];
2740
+ $scope.max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max;
2741
+
2742
+ this.addBar = function(bar, element) {
2743
+ if ( !animate ) {
2744
+ element.css({'transition': 'none'});
2745
+ }
2746
+
2747
+ this.bars.push(bar);
2748
+
2749
+ bar.$watch('value', function( value ) {
2750
+ bar.percent = +(100 * value / $scope.max).toFixed(2);
2751
+ });
2752
+
2753
+ bar.$on('$destroy', function() {
2754
+ element = null;
2755
+ self.removeBar(bar);
2756
+ });
2757
+ };
2758
+
2759
+ this.removeBar = function(bar) {
2760
+ this.bars.splice(this.bars.indexOf(bar), 1);
2761
+ };
2762
+ }])
2763
+
2764
+ .directive('progress', function() {
2765
+ return {
2766
+ restrict: 'EA',
2767
+ replace: true,
2768
+ transclude: true,
2769
+ controller: 'ProgressController',
2770
+ require: 'progress',
2771
+ scope: {},
2772
+ templateUrl: 'template/progressbar/progress.html'
2773
+ };
2774
+ })
2775
+
2776
+ .directive('bar', function() {
2777
+ return {
2778
+ restrict: 'EA',
2779
+ replace: true,
2780
+ transclude: true,
2781
+ require: '^progress',
2782
+ scope: {
2783
+ value: '=',
2784
+ type: '@'
2785
+ },
2786
+ templateUrl: 'template/progressbar/bar.html',
2787
+ link: function(scope, element, attrs, progressCtrl) {
2788
+ progressCtrl.addBar(scope, element);
2789
+ }
2790
+ };
2791
+ })
2792
+
2793
+ .directive('progressbar', function() {
2794
+ return {
2795
+ restrict: 'EA',
2796
+ replace: true,
2797
+ transclude: true,
2798
+ controller: 'ProgressController',
2799
+ scope: {
2800
+ value: '=',
2801
+ type: '@'
2802
+ },
2803
+ templateUrl: 'template/progressbar/progressbar.html',
2804
+ link: function(scope, element, attrs, progressCtrl) {
2805
+ progressCtrl.addBar(scope, angular.element(element.children()[0]));
2806
+ }
2807
+ };
2808
+ });
2809
+ angular.module('ui.bootstrap.rating', [])
2810
+
2811
+ .constant('ratingConfig', {
2812
+ max: 5,
2813
+ stateOn: null,
2814
+ stateOff: null
2815
+ })
2816
+
2817
+ .controller('RatingController', ['$scope', '$attrs', 'ratingConfig', function($scope, $attrs, ratingConfig) {
2818
+ var ngModelCtrl = { $setViewValue: angular.noop };
2819
+
2820
+ this.init = function(ngModelCtrl_) {
2821
+ ngModelCtrl = ngModelCtrl_;
2822
+ ngModelCtrl.$render = this.render;
2823
+
2824
+ this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
2825
+ this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
2826
+
2827
+ var ratingStates = angular.isDefined($attrs.ratingStates) ? $scope.$parent.$eval($attrs.ratingStates) :
2828
+ new Array( angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max );
2829
+ $scope.range = this.buildTemplateObjects(ratingStates);
2830
+ };
2831
+
2832
+ this.buildTemplateObjects = function(states) {
2833
+ for (var i = 0, n = states.length; i < n; i++) {
2834
+ states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff }, states[i]);
2835
+ }
2836
+ return states;
2837
+ };
2838
+
2839
+ $scope.rate = function(value) {
2840
+ if ( !$scope.readonly && value >= 0 && value <= $scope.range.length ) {
2841
+ ngModelCtrl.$setViewValue(value);
2842
+ ngModelCtrl.$render();
2843
+ }
2844
+ };
2845
+
2846
+ $scope.enter = function(value) {
2847
+ if ( !$scope.readonly ) {
2848
+ $scope.value = value;
2849
+ }
2850
+ $scope.onHover({value: value});
2851
+ };
2852
+
2853
+ $scope.reset = function() {
2854
+ $scope.value = ngModelCtrl.$viewValue;
2855
+ $scope.onLeave();
2856
+ };
2857
+
2858
+ $scope.onKeydown = function(evt) {
2859
+ if (/(37|38|39|40)/.test(evt.which)) {
2860
+ evt.preventDefault();
2861
+ evt.stopPropagation();
2862
+ $scope.rate( $scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1) );
2863
+ }
2864
+ };
2865
+
2866
+ this.render = function() {
2867
+ $scope.value = ngModelCtrl.$viewValue;
2868
+ };
2869
+ }])
2870
+
2871
+ .directive('rating', function() {
2872
+ return {
2873
+ restrict: 'EA',
2874
+ require: ['rating', 'ngModel'],
2875
+ scope: {
2876
+ readonly: '=?',
2877
+ onHover: '&',
2878
+ onLeave: '&'
2879
+ },
2880
+ controller: 'RatingController',
2881
+ templateUrl: 'template/rating/rating.html',
2882
+ replace: true,
2883
+ link: function(scope, element, attrs, ctrls) {
2884
+ var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
2885
+
2886
+ if ( ngModelCtrl ) {
2887
+ ratingCtrl.init( ngModelCtrl );
2888
+ }
2889
+ }
2890
+ };
2891
+ });
2892
+
2893
+ /**
2894
+ * @ngdoc overview
2895
+ * @name ui.bootstrap.tabs
2896
+ *
2897
+ * @description
2898
+ * AngularJS version of the tabs directive.
2899
+ */
2900
+
2901
+ angular.module('ui.bootstrap.tabs', [])
2902
+
2903
+ .controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
2904
+ var ctrl = this,
2905
+ tabs = ctrl.tabs = $scope.tabs = [];
2906
+
2907
+ ctrl.select = function(selectedTab) {
2908
+ angular.forEach(tabs, function(tab) {
2909
+ if (tab.active && tab !== selectedTab) {
2910
+ tab.active = false;
2911
+ tab.onDeselect();
2912
+ }
2913
+ });
2914
+ selectedTab.active = true;
2915
+ selectedTab.onSelect();
2916
+ };
2917
+
2918
+ ctrl.addTab = function addTab(tab) {
2919
+ tabs.push(tab);
2920
+ // we can't run the select function on the first tab
2921
+ // since that would select it twice
2922
+ if (tabs.length === 1) {
2923
+ tab.active = true;
2924
+ } else if (tab.active) {
2925
+ ctrl.select(tab);
2926
+ }
2927
+ };
2928
+
2929
+ ctrl.removeTab = function removeTab(tab) {
2930
+ var index = tabs.indexOf(tab);
2931
+ //Select a new tab if the tab to be removed is selected
2932
+ if (tab.active && tabs.length > 1) {
2933
+ //If this is the last tab, select the previous tab. else, the next tab.
2934
+ var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
2935
+ ctrl.select(tabs[newActiveIndex]);
2936
+ }
2937
+ tabs.splice(index, 1);
2938
+ };
2939
+ }])
2940
+
2941
+ /**
2942
+ * @ngdoc directive
2943
+ * @name ui.bootstrap.tabs.directive:tabset
2944
+ * @restrict EA
2945
+ *
2946
+ * @description
2947
+ * Tabset is the outer container for the tabs directive
2948
+ *
2949
+ * @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
2950
+ * @param {boolean=} justified Whether or not to use justified styling for the tabs.
2951
+ *
2952
+ * @example
2953
+ <example module="ui.bootstrap">
2954
+ <file name="index.html">
2955
+ <tabset>
2956
+ <tab heading="Tab 1"><b>First</b> Content!</tab>
2957
+ <tab heading="Tab 2"><i>Second</i> Content!</tab>
2958
+ </tabset>
2959
+ <hr />
2960
+ <tabset vertical="true">
2961
+ <tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
2962
+ <tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
2963
+ </tabset>
2964
+ <tabset justified="true">
2965
+ <tab heading="Justified Tab 1"><b>First</b> Justified Content!</tab>
2966
+ <tab heading="Justified Tab 2"><i>Second</i> Justified Content!</tab>
2967
+ </tabset>
2968
+ </file>
2969
+ </example>
2970
+ */
2971
+ .directive('tabset', function() {
2972
+ return {
2973
+ restrict: 'EA',
2974
+ transclude: true,
2975
+ replace: true,
2976
+ scope: {
2977
+ type: '@'
2978
+ },
2979
+ controller: 'TabsetController',
2980
+ templateUrl: 'template/tabs/tabset.html',
2981
+ link: function(scope, element, attrs) {
2982
+ scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
2983
+ scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
2984
+ }
2985
+ };
2986
+ })
2987
+
2988
+ /**
2989
+ * @ngdoc directive
2990
+ * @name ui.bootstrap.tabs.directive:tab
2991
+ * @restrict EA
2992
+ *
2993
+ * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
2994
+ * @param {string=} select An expression to evaluate when the tab is selected.
2995
+ * @param {boolean=} active A binding, telling whether or not this tab is selected.
2996
+ * @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
2997
+ *
2998
+ * @description
2999
+ * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
3000
+ *
3001
+ * @example
3002
+ <example module="ui.bootstrap">
3003
+ <file name="index.html">
3004
+ <div ng-controller="TabsDemoCtrl">
3005
+ <button class="btn btn-small" ng-click="items[0].active = true">
3006
+ Select item 1, using active binding
3007
+ </button>
3008
+ <button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
3009
+ Enable/disable item 2, using disabled binding
3010
+ </button>
3011
+ <br />
3012
+ <tabset>
3013
+ <tab heading="Tab 1">First Tab</tab>
3014
+ <tab select="alertMe()">
3015
+ <tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
3016
+ Second Tab, with alert callback and html heading!
3017
+ </tab>
3018
+ <tab ng-repeat="item in items"
3019
+ heading="{{item.title}}"
3020
+ disabled="item.disabled"
3021
+ active="item.active">
3022
+ {{item.content}}
3023
+ </tab>
3024
+ </tabset>
3025
+ </div>
3026
+ </file>
3027
+ <file name="script.js">
3028
+ function TabsDemoCtrl($scope) {
3029
+ $scope.items = [
3030
+ { title:"Dynamic Title 1", content:"Dynamic Item 0" },
3031
+ { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
3032
+ ];
3033
+
3034
+ $scope.alertMe = function() {
3035
+ setTimeout(function() {
3036
+ alert("You've selected the alert tab!");
3037
+ });
3038
+ };
3039
+ };
3040
+ </file>
3041
+ </example>
3042
+ */
3043
+
3044
+ /**
3045
+ * @ngdoc directive
3046
+ * @name ui.bootstrap.tabs.directive:tabHeading
3047
+ * @restrict EA
3048
+ *
3049
+ * @description
3050
+ * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
3051
+ *
3052
+ * @example
3053
+ <example module="ui.bootstrap">
3054
+ <file name="index.html">
3055
+ <tabset>
3056
+ <tab>
3057
+ <tab-heading><b>HTML</b> in my titles?!</tab-heading>
3058
+ And some content, too!
3059
+ </tab>
3060
+ <tab>
3061
+ <tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
3062
+ That's right.
3063
+ </tab>
3064
+ </tabset>
3065
+ </file>
3066
+ </example>
3067
+ */
3068
+ .directive('tab', ['$parse', function($parse) {
3069
+ return {
3070
+ require: '^tabset',
3071
+ restrict: 'EA',
3072
+ replace: true,
3073
+ templateUrl: 'template/tabs/tab.html',
3074
+ transclude: true,
3075
+ scope: {
3076
+ active: '=?',
3077
+ heading: '@',
3078
+ onSelect: '&select', //This callback is called in contentHeadingTransclude
3079
+ //once it inserts the tab's content into the dom
3080
+ onDeselect: '&deselect'
3081
+ },
3082
+ controller: function() {
3083
+ //Empty controller so other directives can require being 'under' a tab
3084
+ },
3085
+ compile: function(elm, attrs, transclude) {
3086
+ return function postLink(scope, elm, attrs, tabsetCtrl) {
3087
+ scope.$watch('active', function(active) {
3088
+ if (active) {
3089
+ tabsetCtrl.select(scope);
3090
+ }
3091
+ });
3092
+
3093
+ scope.disabled = false;
3094
+ if ( attrs.disabled ) {
3095
+ scope.$parent.$watch($parse(attrs.disabled), function(value) {
3096
+ scope.disabled = !! value;
3097
+ });
3098
+ }
3099
+
3100
+ scope.select = function() {
3101
+ if ( !scope.disabled ) {
3102
+ scope.active = true;
3103
+ }
3104
+ };
3105
+
3106
+ tabsetCtrl.addTab(scope);
3107
+ scope.$on('$destroy', function() {
3108
+ tabsetCtrl.removeTab(scope);
3109
+ });
3110
+
3111
+ //We need to transclude later, once the content container is ready.
3112
+ //when this link happens, we're inside a tab heading.
3113
+ scope.$transcludeFn = transclude;
3114
+ };
3115
+ }
3116
+ };
3117
+ }])
3118
+
3119
+ .directive('tabHeadingTransclude', [function() {
3120
+ return {
3121
+ restrict: 'A',
3122
+ require: '^tab',
3123
+ link: function(scope, elm, attrs, tabCtrl) {
3124
+ scope.$watch('headingElement', function updateHeadingElement(heading) {
3125
+ if (heading) {
3126
+ elm.html('');
3127
+ elm.append(heading);
3128
+ }
3129
+ });
3130
+ }
3131
+ };
3132
+ }])
3133
+
3134
+ .directive('tabContentTransclude', function() {
3135
+ return {
3136
+ restrict: 'A',
3137
+ require: '^tabset',
3138
+ link: function(scope, elm, attrs) {
3139
+ var tab = scope.$eval(attrs.tabContentTransclude);
3140
+
3141
+ //Now our tab is ready to be transcluded: both the tab heading area
3142
+ //and the tab content area are loaded. Transclude 'em both.
3143
+ tab.$transcludeFn(tab.$parent, function(contents) {
3144
+ angular.forEach(contents, function(node) {
3145
+ if (isTabHeading(node)) {
3146
+ //Let tabHeadingTransclude know.
3147
+ tab.headingElement = node;
3148
+ } else {
3149
+ elm.append(node);
3150
+ }
3151
+ });
3152
+ });
3153
+ }
3154
+ };
3155
+ function isTabHeading(node) {
3156
+ return node.tagName && (
3157
+ node.hasAttribute('tab-heading') ||
3158
+ node.hasAttribute('data-tab-heading') ||
3159
+ node.tagName.toLowerCase() === 'tab-heading' ||
3160
+ node.tagName.toLowerCase() === 'data-tab-heading'
3161
+ );
3162
+ }
3163
+ })
3164
+
3165
+ ;
3166
+
3167
+ angular.module('ui.bootstrap.timepicker', [])
3168
+
3169
+ .constant('timepickerConfig', {
3170
+ hourStep: 1,
3171
+ minuteStep: 1,
3172
+ showMeridian: true,
3173
+ meridians: null,
3174
+ readonlyInput: false,
3175
+ mousewheel: true
3176
+ })
3177
+
3178
+ .controller('TimepickerController', ['$scope', '$attrs', '$parse', '$log', '$locale', 'timepickerConfig', function($scope, $attrs, $parse, $log, $locale, timepickerConfig) {
3179
+ var selected = new Date(),
3180
+ ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
3181
+ meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
3182
+
3183
+ this.init = function( ngModelCtrl_, inputs ) {
3184
+ ngModelCtrl = ngModelCtrl_;
3185
+ ngModelCtrl.$render = this.render;
3186
+
3187
+ var hoursInputEl = inputs.eq(0),
3188
+ minutesInputEl = inputs.eq(1);
3189
+
3190
+ var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
3191
+ if ( mousewheel ) {
3192
+ this.setupMousewheelEvents( hoursInputEl, minutesInputEl );
3193
+ }
3194
+
3195
+ $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
3196
+ this.setupInputEvents( hoursInputEl, minutesInputEl );
3197
+ };
3198
+
3199
+ var hourStep = timepickerConfig.hourStep;
3200
+ if ($attrs.hourStep) {
3201
+ $scope.$parent.$watch($parse($attrs.hourStep), function(value) {
3202
+ hourStep = parseInt(value, 10);
3203
+ });
3204
+ }
3205
+
3206
+ var minuteStep = timepickerConfig.minuteStep;
3207
+ if ($attrs.minuteStep) {
3208
+ $scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
3209
+ minuteStep = parseInt(value, 10);
3210
+ });
3211
+ }
3212
+
3213
+ // 12H / 24H mode
3214
+ $scope.showMeridian = timepickerConfig.showMeridian;
3215
+ if ($attrs.showMeridian) {
3216
+ $scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
3217
+ $scope.showMeridian = !!value;
3218
+
3219
+ if ( ngModelCtrl.$error.time ) {
3220
+ // Evaluate from template
3221
+ var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
3222
+ if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
3223
+ selected.setHours( hours );
3224
+ refresh();
3225
+ }
3226
+ } else {
3227
+ updateTemplate();
3228
+ }
3229
+ });
3230
+ }
3231
+
3232
+ // Get $scope.hours in 24H mode if valid
3233
+ function getHoursFromTemplate ( ) {
3234
+ var hours = parseInt( $scope.hours, 10 );
3235
+ var valid = ( $scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
3236
+ if ( !valid ) {
3237
+ return undefined;
3238
+ }
3239
+
3240
+ if ( $scope.showMeridian ) {
3241
+ if ( hours === 12 ) {
3242
+ hours = 0;
3243
+ }
3244
+ if ( $scope.meridian === meridians[1] ) {
3245
+ hours = hours + 12;
3246
+ }
3247
+ }
3248
+ return hours;
3249
+ }
3250
+
3251
+ function getMinutesFromTemplate() {
3252
+ var minutes = parseInt($scope.minutes, 10);
3253
+ return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
3254
+ }
3255
+
3256
+ function pad( value ) {
3257
+ return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
3258
+ }
3259
+
3260
+ // Respond on mousewheel spin
3261
+ this.setupMousewheelEvents = function( hoursInputEl, minutesInputEl ) {
3262
+ var isScrollingUp = function(e) {
3263
+ if (e.originalEvent) {
3264
+ e = e.originalEvent;
3265
+ }
3266
+ //pick correct delta variable depending on event
3267
+ var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
3268
+ return (e.detail || delta > 0);
3269
+ };
3270
+
3271
+ hoursInputEl.bind('mousewheel wheel', function(e) {
3272
+ $scope.$apply( (isScrollingUp(e)) ? $scope.incrementHours() : $scope.decrementHours() );
3273
+ e.preventDefault();
3274
+ });
3275
+
3276
+ minutesInputEl.bind('mousewheel wheel', function(e) {
3277
+ $scope.$apply( (isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes() );
3278
+ e.preventDefault();
3279
+ });
3280
+
3281
+ };
3282
+
3283
+ this.setupInputEvents = function( hoursInputEl, minutesInputEl ) {
3284
+ if ( $scope.readonlyInput ) {
3285
+ $scope.updateHours = angular.noop;
3286
+ $scope.updateMinutes = angular.noop;
3287
+ return;
3288
+ }
3289
+
3290
+ var invalidate = function(invalidHours, invalidMinutes) {
3291
+ ngModelCtrl.$setViewValue( null );
3292
+ ngModelCtrl.$setValidity('time', false);
3293
+ if (angular.isDefined(invalidHours)) {
3294
+ $scope.invalidHours = invalidHours;
3295
+ }
3296
+ if (angular.isDefined(invalidMinutes)) {
3297
+ $scope.invalidMinutes = invalidMinutes;
3298
+ }
3299
+ };
3300
+
3301
+ $scope.updateHours = function() {
3302
+ var hours = getHoursFromTemplate();
3303
+
3304
+ if ( angular.isDefined(hours) ) {
3305
+ selected.setHours( hours );
3306
+ refresh( 'h' );
3307
+ } else {
3308
+ invalidate(true);
3309
+ }
3310
+ };
3311
+
3312
+ hoursInputEl.bind('blur', function(e) {
3313
+ if ( !$scope.invalidHours && $scope.hours < 10) {
3314
+ $scope.$apply( function() {
3315
+ $scope.hours = pad( $scope.hours );
3316
+ });
3317
+ }
3318
+ });
3319
+
3320
+ $scope.updateMinutes = function() {
3321
+ var minutes = getMinutesFromTemplate();
3322
+
3323
+ if ( angular.isDefined(minutes) ) {
3324
+ selected.setMinutes( minutes );
3325
+ refresh( 'm' );
3326
+ } else {
3327
+ invalidate(undefined, true);
3328
+ }
3329
+ };
3330
+
3331
+ minutesInputEl.bind('blur', function(e) {
3332
+ if ( !$scope.invalidMinutes && $scope.minutes < 10 ) {
3333
+ $scope.$apply( function() {
3334
+ $scope.minutes = pad( $scope.minutes );
3335
+ });
3336
+ }
3337
+ });
3338
+
3339
+ };
3340
+
3341
+ this.render = function() {
3342
+ var date = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : null;
3343
+
3344
+ if ( isNaN(date) ) {
3345
+ ngModelCtrl.$setValidity('time', false);
3346
+ $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
3347
+ } else {
3348
+ if ( date ) {
3349
+ selected = date;
3350
+ }
3351
+ makeValid();
3352
+ updateTemplate();
3353
+ }
3354
+ };
3355
+
3356
+ // Call internally when we know that model is valid.
3357
+ function refresh( keyboardChange ) {
3358
+ makeValid();
3359
+ ngModelCtrl.$setViewValue( new Date(selected) );
3360
+ updateTemplate( keyboardChange );
3361
+ }
3362
+
3363
+ function makeValid() {
3364
+ ngModelCtrl.$setValidity('time', true);
3365
+ $scope.invalidHours = false;
3366
+ $scope.invalidMinutes = false;
3367
+ }
3368
+
3369
+ function updateTemplate( keyboardChange ) {
3370
+ var hours = selected.getHours(), minutes = selected.getMinutes();
3371
+
3372
+ if ( $scope.showMeridian ) {
3373
+ hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
3374
+ }
3375
+
3376
+ $scope.hours = keyboardChange === 'h' ? hours : pad(hours);
3377
+ $scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
3378
+ $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
3379
+ }
3380
+
3381
+ function addMinutes( minutes ) {
3382
+ var dt = new Date( selected.getTime() + minutes * 60000 );
3383
+ selected.setHours( dt.getHours(), dt.getMinutes() );
3384
+ refresh();
3385
+ }
3386
+
3387
+ $scope.incrementHours = function() {
3388
+ addMinutes( hourStep * 60 );
3389
+ };
3390
+ $scope.decrementHours = function() {
3391
+ addMinutes( - hourStep * 60 );
3392
+ };
3393
+ $scope.incrementMinutes = function() {
3394
+ addMinutes( minuteStep );
3395
+ };
3396
+ $scope.decrementMinutes = function() {
3397
+ addMinutes( - minuteStep );
3398
+ };
3399
+ $scope.toggleMeridian = function() {
3400
+ addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
3401
+ };
3402
+ }])
3403
+
3404
+ .directive('timepicker', function () {
3405
+ return {
3406
+ restrict: 'EA',
3407
+ require: ['timepicker', '?^ngModel'],
3408
+ controller:'TimepickerController',
3409
+ replace: true,
3410
+ scope: {},
3411
+ templateUrl: 'template/timepicker/timepicker.html',
3412
+ link: function(scope, element, attrs, ctrls) {
3413
+ var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
3414
+
3415
+ if ( ngModelCtrl ) {
3416
+ timepickerCtrl.init( ngModelCtrl, element.find('input') );
3417
+ }
3418
+ }
3419
+ };
3420
+ });
3421
+
3422
+ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
3423
+
3424
+ /**
3425
+ * A helper service that can parse typeahead's syntax (string provided by users)
3426
+ * Extracted to a separate service for ease of unit testing
3427
+ */
3428
+ .factory('typeaheadParser', ['$parse', function ($parse) {
3429
+
3430
+ // 00000111000000000000022200000000000000003333333333333330000000000044000
3431
+ var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;
3432
+
3433
+ return {
3434
+ parse:function (input) {
3435
+
3436
+ var match = input.match(TYPEAHEAD_REGEXP);
3437
+ if (!match) {
3438
+ throw new Error(
3439
+ 'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
3440
+ ' but got "' + input + '".');
3441
+ }
3442
+
3443
+ return {
3444
+ itemName:match[3],
3445
+ source:$parse(match[4]),
3446
+ viewMapper:$parse(match[2] || match[1]),
3447
+ modelMapper:$parse(match[1])
3448
+ };
3449
+ }
3450
+ };
3451
+ }])
3452
+
3453
+ .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser',
3454
+ function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) {
3455
+
3456
+ var HOT_KEYS = [9, 13, 27, 38, 40];
3457
+
3458
+ return {
3459
+ require:'ngModel',
3460
+ link:function (originalScope, element, attrs, modelCtrl) {
3461
+
3462
+ //SUPPORTED ATTRIBUTES (OPTIONS)
3463
+
3464
+ //minimal no of characters that needs to be entered before typeahead kicks-in
3465
+ var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
3466
+
3467
+ //minimal wait time after last character typed before typehead kicks-in
3468
+ var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
3469
+
3470
+ //should it restrict model values to the ones selected from the popup only?
3471
+ var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
3472
+
3473
+ //binding to a variable that indicates if matches are being retrieved asynchronously
3474
+ var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
3475
+
3476
+ //a callback executed when a match is selected
3477
+ var onSelectCallback = $parse(attrs.typeaheadOnSelect);
3478
+
3479
+ var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
3480
+
3481
+ var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
3482
+
3483
+ //INTERNAL VARIABLES
3484
+
3485
+ //model setter executed upon match selection
3486
+ var $setModelValue = $parse(attrs.ngModel).assign;
3487
+
3488
+ //expressions used by typeahead
3489
+ var parserResult = typeaheadParser.parse(attrs.typeahead);
3490
+
3491
+ var hasFocus;
3492
+
3493
+ //create a child scope for the typeahead directive so we are not polluting original scope
3494
+ //with typeahead-specific data (matches, query etc.)
3495
+ var scope = originalScope.$new();
3496
+ originalScope.$on('$destroy', function(){
3497
+ scope.$destroy();
3498
+ });
3499
+
3500
+ // WAI-ARIA
3501
+ var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
3502
+ element.attr({
3503
+ 'aria-autocomplete': 'list',
3504
+ 'aria-expanded': false,
3505
+ 'aria-owns': popupId
3506
+ });
3507
+
3508
+ //pop-up element used to display matches
3509
+ var popUpEl = angular.element('<div typeahead-popup></div>');
3510
+ popUpEl.attr({
3511
+ id: popupId,
3512
+ matches: 'matches',
3513
+ active: 'activeIdx',
3514
+ select: 'select(activeIdx)',
3515
+ query: 'query',
3516
+ position: 'position'
3517
+ });
3518
+ //custom item template
3519
+ if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
3520
+ popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
3521
+ }
3522
+
3523
+ var resetMatches = function() {
3524
+ scope.matches = [];
3525
+ scope.activeIdx = -1;
3526
+ element.attr('aria-expanded', false);
3527
+ };
3528
+
3529
+ var getMatchId = function(index) {
3530
+ return popupId + '-option-' + index;
3531
+ };
3532
+
3533
+ // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
3534
+ // This attribute is added or removed automatically when the `activeIdx` changes.
3535
+ scope.$watch('activeIdx', function(index) {
3536
+ if (index < 0) {
3537
+ element.removeAttr('aria-activedescendant');
3538
+ } else {
3539
+ element.attr('aria-activedescendant', getMatchId(index));
3540
+ }
3541
+ });
3542
+
3543
+ var getMatchesAsync = function(inputValue) {
3544
+
3545
+ var locals = {$viewValue: inputValue};
3546
+ isLoadingSetter(originalScope, true);
3547
+ $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
3548
+
3549
+ //it might happen that several async queries were in progress if a user were typing fast
3550
+ //but we are interested only in responses that correspond to the current view value
3551
+ var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
3552
+ if (onCurrentRequest && hasFocus) {
3553
+ if (matches.length > 0) {
3554
+
3555
+ scope.activeIdx = 0;
3556
+ scope.matches.length = 0;
3557
+
3558
+ //transform labels
3559
+ for(var i=0; i<matches.length; i++) {
3560
+ locals[parserResult.itemName] = matches[i];
3561
+ scope.matches.push({
3562
+ id: getMatchId(i),
3563
+ label: parserResult.viewMapper(scope, locals),
3564
+ model: matches[i]
3565
+ });
3566
+ }
3567
+
3568
+ scope.query = inputValue;
3569
+ //position pop-up with matches - we need to re-calculate its position each time we are opening a window
3570
+ //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
3571
+ //due to other elements being rendered
3572
+ scope.position = appendToBody ? $position.offset(element) : $position.position(element);
3573
+ scope.position.top = scope.position.top + element.prop('offsetHeight');
3574
+
3575
+ element.attr('aria-expanded', true);
3576
+ } else {
3577
+ resetMatches();
3578
+ }
3579
+ }
3580
+ if (onCurrentRequest) {
3581
+ isLoadingSetter(originalScope, false);
3582
+ }
3583
+ }, function(){
3584
+ resetMatches();
3585
+ isLoadingSetter(originalScope, false);
3586
+ });
3587
+ };
3588
+
3589
+ resetMatches();
3590
+
3591
+ //we need to propagate user's query so we can higlight matches
3592
+ scope.query = undefined;
3593
+
3594
+ //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
3595
+ var timeoutPromise;
3596
+
3597
+ //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
3598
+ //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
3599
+ modelCtrl.$parsers.unshift(function (inputValue) {
3600
+
3601
+ hasFocus = true;
3602
+
3603
+ if (inputValue && inputValue.length >= minSearch) {
3604
+ if (waitTime > 0) {
3605
+ if (timeoutPromise) {
3606
+ $timeout.cancel(timeoutPromise);//cancel previous timeout
3607
+ }
3608
+ timeoutPromise = $timeout(function () {
3609
+ getMatchesAsync(inputValue);
3610
+ }, waitTime);
3611
+ } else {
3612
+ getMatchesAsync(inputValue);
3613
+ }
3614
+ } else {
3615
+ isLoadingSetter(originalScope, false);
3616
+ resetMatches();
3617
+ }
3618
+
3619
+ if (isEditable) {
3620
+ return inputValue;
3621
+ } else {
3622
+ if (!inputValue) {
3623
+ // Reset in case user had typed something previously.
3624
+ modelCtrl.$setValidity('editable', true);
3625
+ return inputValue;
3626
+ } else {
3627
+ modelCtrl.$setValidity('editable', false);
3628
+ return undefined;
3629
+ }
3630
+ }
3631
+ });
3632
+
3633
+ modelCtrl.$formatters.push(function (modelValue) {
3634
+
3635
+ var candidateViewValue, emptyViewValue;
3636
+ var locals = {};
3637
+
3638
+ if (inputFormatter) {
3639
+
3640
+ locals['$model'] = modelValue;
3641
+ return inputFormatter(originalScope, locals);
3642
+
3643
+ } else {
3644
+
3645
+ //it might happen that we don't have enough info to properly render input value
3646
+ //we need to check for this situation and simply return model value if we can't apply custom formatting
3647
+ locals[parserResult.itemName] = modelValue;
3648
+ candidateViewValue = parserResult.viewMapper(originalScope, locals);
3649
+ locals[parserResult.itemName] = undefined;
3650
+ emptyViewValue = parserResult.viewMapper(originalScope, locals);
3651
+
3652
+ return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
3653
+ }
3654
+ });
3655
+
3656
+ scope.select = function (activeIdx) {
3657
+ //called from within the $digest() cycle
3658
+ var locals = {};
3659
+ var model, item;
3660
+
3661
+ locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
3662
+ model = parserResult.modelMapper(originalScope, locals);
3663
+ $setModelValue(originalScope, model);
3664
+ modelCtrl.$setValidity('editable', true);
3665
+
3666
+ onSelectCallback(originalScope, {
3667
+ $item: item,
3668
+ $model: model,
3669
+ $label: parserResult.viewMapper(originalScope, locals)
3670
+ });
3671
+
3672
+ resetMatches();
3673
+
3674
+ //return focus to the input element if a match was selected via a mouse click event
3675
+ // use timeout to avoid $rootScope:inprog error
3676
+ $timeout(function() { element[0].focus(); }, 0, false);
3677
+ };
3678
+
3679
+ //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
3680
+ element.bind('keydown', function (evt) {
3681
+
3682
+ //typeahead is open and an "interesting" key was pressed
3683
+ if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
3684
+ return;
3685
+ }
3686
+
3687
+ evt.preventDefault();
3688
+
3689
+ if (evt.which === 40) {
3690
+ scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
3691
+ scope.$digest();
3692
+
3693
+ } else if (evt.which === 38) {
3694
+ scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1;
3695
+ scope.$digest();
3696
+
3697
+ } else if (evt.which === 13 || evt.which === 9) {
3698
+ scope.$apply(function () {
3699
+ scope.select(scope.activeIdx);
3700
+ });
3701
+
3702
+ } else if (evt.which === 27) {
3703
+ evt.stopPropagation();
3704
+
3705
+ resetMatches();
3706
+ scope.$digest();
3707
+ }
3708
+ });
3709
+
3710
+ element.bind('blur', function (evt) {
3711
+ hasFocus = false;
3712
+ });
3713
+
3714
+ // Keep reference to click handler to unbind it.
3715
+ var dismissClickHandler = function (evt) {
3716
+ if (element[0] !== evt.target) {
3717
+ resetMatches();
3718
+ scope.$digest();
3719
+ }
3720
+ };
3721
+
3722
+ $document.bind('click', dismissClickHandler);
3723
+
3724
+ originalScope.$on('$destroy', function(){
3725
+ $document.unbind('click', dismissClickHandler);
3726
+ });
3727
+
3728
+ var $popup = $compile(popUpEl)(scope);
3729
+ if ( appendToBody ) {
3730
+ $document.find('body').append($popup);
3731
+ } else {
3732
+ element.after($popup);
3733
+ }
3734
+ }
3735
+ };
3736
+
3737
+ }])
3738
+
3739
+ .directive('typeaheadPopup', function () {
3740
+ return {
3741
+ restrict:'EA',
3742
+ scope:{
3743
+ matches:'=',
3744
+ query:'=',
3745
+ active:'=',
3746
+ position:'=',
3747
+ select:'&'
3748
+ },
3749
+ replace:true,
3750
+ templateUrl:'template/typeahead/typeahead-popup.html',
3751
+ link:function (scope, element, attrs) {
3752
+
3753
+ scope.templateUrl = attrs.templateUrl;
3754
+
3755
+ scope.isOpen = function () {
3756
+ return scope.matches.length > 0;
3757
+ };
3758
+
3759
+ scope.isActive = function (matchIdx) {
3760
+ return scope.active == matchIdx;
3761
+ };
3762
+
3763
+ scope.selectActive = function (matchIdx) {
3764
+ scope.active = matchIdx;
3765
+ };
3766
+
3767
+ scope.selectMatch = function (activeIdx) {
3768
+ scope.select({activeIdx:activeIdx});
3769
+ };
3770
+ }
3771
+ };
3772
+ })
3773
+
3774
+ .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) {
3775
+ return {
3776
+ restrict:'EA',
3777
+ scope:{
3778
+ index:'=',
3779
+ match:'=',
3780
+ query:'='
3781
+ },
3782
+ link:function (scope, element, attrs) {
3783
+ var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html';
3784
+ $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){
3785
+ element.replaceWith($compile(tplContent.trim())(scope));
3786
+ });
3787
+ }
3788
+ };
3789
+ }])
3790
+
3791
+ .filter('typeaheadHighlight', function() {
3792
+
3793
+ function escapeRegexp(queryToEscape) {
3794
+ return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
3795
+ }
3796
+
3797
+ return function(matchItem, query) {
3798
+ return query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
3799
+ };
3800
+ });
3801
+
3802
+ angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
3803
+ $templateCache.put("template/accordion/accordion-group.html",
3804
+ "<div class=\"panel panel-default\">\n" +
3805
+ " <div class=\"panel-heading\">\n" +
3806
+ " <h4 class=\"panel-title\">\n" +
3807
+ " <a class=\"accordion-toggle\" ng-click=\"toggleOpen()\" accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
3808
+ " </h4>\n" +
3809
+ " </div>\n" +
3810
+ " <div class=\"panel-collapse\" collapse=\"!isOpen\">\n" +
3811
+ " <div class=\"panel-body\" ng-transclude></div>\n" +
3812
+ " </div>\n" +
3813
+ "</div>");
3814
+ }]);
3815
+
3816
+ angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
3817
+ $templateCache.put("template/accordion/accordion.html",
3818
+ "<div class=\"panel-group\" ng-transclude></div>");
3819
+ }]);
3820
+
3821
+ angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
3822
+ $templateCache.put("template/alert/alert.html",
3823
+ "<div class=\"alert\" ng-class=\"{'alert-{{type || 'warning'}}': true, 'alert-dismissable': closeable}\" role=\"alert\">\n" +
3824
+ " <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close()\">\n" +
3825
+ " <span aria-hidden=\"true\">&times;</span>\n" +
3826
+ " <span class=\"sr-only\">Close</span>\n" +
3827
+ " </button>\n" +
3828
+ " <div ng-transclude></div>\n" +
3829
+ "</div>\n" +
3830
+ "");
3831
+ }]);
3832
+
3833
+ angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
3834
+ $templateCache.put("template/carousel/carousel.html",
3835
+ "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
3836
+ " <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
3837
+ " <li ng-repeat=\"slide in slides track by $index\" ng-class=\"{active: isActive(slide)}\" ng-click=\"select(slide)\"></li>\n" +
3838
+ " </ol>\n" +
3839
+ " <div class=\"carousel-inner\" ng-transclude></div>\n" +
3840
+ " <a class=\"left carousel-control\" ng-click=\"prev()\" ng-show=\"slides.length > 1\"><span class=\"glyphicon glyphicon-chevron-left\"></span></a>\n" +
3841
+ " <a class=\"right carousel-control\" ng-click=\"next()\" ng-show=\"slides.length > 1\"><span class=\"glyphicon glyphicon-chevron-right\"></span></a>\n" +
3842
+ "</div>\n" +
3843
+ "");
3844
+ }]);
3845
+
3846
+ angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
3847
+ $templateCache.put("template/carousel/slide.html",
3848
+ "<div ng-class=\"{\n" +
3849
+ " 'active': leaving || (active && !entering),\n" +
3850
+ " 'prev': (next || active) && direction=='prev',\n" +
3851
+ " 'next': (next || active) && direction=='next',\n" +
3852
+ " 'right': direction=='prev',\n" +
3853
+ " 'left': direction=='next'\n" +
3854
+ " }\" class=\"item text-center\" ng-transclude></div>\n" +
3855
+ "");
3856
+ }]);
3857
+
3858
+ angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
3859
+ $templateCache.put("template/datepicker/datepicker.html",
3860
+ "<div ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
3861
+ " <daypicker ng-switch-when=\"day\" tabindex=\"0\"></daypicker>\n" +
3862
+ " <monthpicker ng-switch-when=\"month\" tabindex=\"0\"></monthpicker>\n" +
3863
+ " <yearpicker ng-switch-when=\"year\" tabindex=\"0\"></yearpicker>\n" +
3864
+ "</div>");
3865
+ }]);
3866
+
3867
+ angular.module("template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
3868
+ $templateCache.put("template/datepicker/day.html",
3869
+ "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
3870
+ " <thead>\n" +
3871
+ " <tr>\n" +
3872
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
3873
+ " <th colspan=\"{{5 + showWeeks}}\"><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
3874
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
3875
+ " </tr>\n" +
3876
+ " <tr>\n" +
3877
+ " <th ng-show=\"showWeeks\" class=\"text-center\"></th>\n" +
3878
+ " <th ng-repeat=\"label in labels track by $index\" class=\"text-center\"><small aria-label=\"{{label.full}}\">{{label.abbr}}</small></th>\n" +
3879
+ " </tr>\n" +
3880
+ " </thead>\n" +
3881
+ " <tbody>\n" +
3882
+ " <tr ng-repeat=\"row in rows track by $index\">\n" +
3883
+ " <td ng-show=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
3884
+ " <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
3885
+ " <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default btn-sm\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-muted': dt.secondary, 'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
3886
+ " </td>\n" +
3887
+ " </tr>\n" +
3888
+ " </tbody>\n" +
3889
+ "</table>\n" +
3890
+ "");
3891
+ }]);
3892
+
3893
+ angular.module("template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
3894
+ $templateCache.put("template/datepicker/month.html",
3895
+ "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
3896
+ " <thead>\n" +
3897
+ " <tr>\n" +
3898
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
3899
+ " <th><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
3900
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
3901
+ " </tr>\n" +
3902
+ " </thead>\n" +
3903
+ " <tbody>\n" +
3904
+ " <tr ng-repeat=\"row in rows track by $index\">\n" +
3905
+ " <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
3906
+ " <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
3907
+ " </td>\n" +
3908
+ " </tr>\n" +
3909
+ " </tbody>\n" +
3910
+ "</table>\n" +
3911
+ "");
3912
+ }]);
3913
+
3914
+ angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
3915
+ $templateCache.put("template/datepicker/popup.html",
3916
+ "<ul class=\"dropdown-menu\" ng-style=\"{display: (isOpen && 'block') || 'none', top: position.top+'px', left: position.left+'px'}\" ng-keydown=\"keydown($event)\">\n" +
3917
+ " <li ng-transclude></li>\n" +
3918
+ " <li ng-if=\"showButtonBar\" style=\"padding:10px 9px 2px\">\n" +
3919
+ " <span class=\"btn-group\">\n" +
3920
+ " <button type=\"button\" class=\"btn btn-sm btn-info\" ng-click=\"select('today')\">{{ getText('current') }}</button>\n" +
3921
+ " <button type=\"button\" class=\"btn btn-sm btn-danger\" ng-click=\"select(null)\">{{ getText('clear') }}</button>\n" +
3922
+ " </span>\n" +
3923
+ " <button type=\"button\" class=\"btn btn-sm btn-success pull-right\" ng-click=\"close()\">{{ getText('close') }}</button>\n" +
3924
+ " </li>\n" +
3925
+ "</ul>\n" +
3926
+ "");
3927
+ }]);
3928
+
3929
+ angular.module("template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
3930
+ $templateCache.put("template/datepicker/year.html",
3931
+ "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
3932
+ " <thead>\n" +
3933
+ " <tr>\n" +
3934
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
3935
+ " <th colspan=\"3\"><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
3936
+ " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
3937
+ " </tr>\n" +
3938
+ " </thead>\n" +
3939
+ " <tbody>\n" +
3940
+ " <tr ng-repeat=\"row in rows track by $index\">\n" +
3941
+ " <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
3942
+ " <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
3943
+ " </td>\n" +
3944
+ " </tr>\n" +
3945
+ " </tbody>\n" +
3946
+ "</table>\n" +
3947
+ "");
3948
+ }]);
3949
+
3950
+ angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
3951
+ $templateCache.put("template/modal/backdrop.html",
3952
+ "<div class=\"modal-backdrop fade\"\n" +
3953
+ " ng-class=\"{in: animate}\"\n" +
3954
+ " ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
3955
+ "></div>\n" +
3956
+ "");
3957
+ }]);
3958
+
3959
+ angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
3960
+ $templateCache.put("template/modal/window.html",
3961
+ "<div tabindex=\"-1\" role=\"dialog\" class=\"modal fade\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" +
3962
+ " <div class=\"modal-dialog\" ng-class=\"{'modal-sm': size == 'sm', 'modal-lg': size == 'lg'}\"><div class=\"modal-content\" ng-transclude></div></div>\n" +
3963
+ "</div>");
3964
+ }]);
3965
+
3966
+ angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
3967
+ $templateCache.put("template/pagination/pager.html",
3968
+ "<ul class=\"pager\">\n" +
3969
+ " <li ng-class=\"{disabled: noPrevious(), previous: align}\"><a href ng-click=\"selectPage(page - 1)\">{{getText('previous')}}</a></li>\n" +
3970
+ " <li ng-class=\"{disabled: noNext(), next: align}\"><a href ng-click=\"selectPage(page + 1)\">{{getText('next')}}</a></li>\n" +
3971
+ "</ul>");
3972
+ }]);
3973
+
3974
+ angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
3975
+ $templateCache.put("template/pagination/pagination.html",
3976
+ "<ul class=\"pagination\">\n" +
3977
+ " <li ng-if=\"boundaryLinks\" ng-class=\"{disabled: noPrevious()}\"><a href ng-click=\"selectPage(1)\">{{getText('first')}}</a></li>\n" +
3978
+ " <li ng-if=\"directionLinks\" ng-class=\"{disabled: noPrevious()}\"><a href ng-click=\"selectPage(page - 1)\">{{getText('previous')}}</a></li>\n" +
3979
+ " <li ng-repeat=\"page in pages track by $index\" ng-class=\"{active: page.active}\"><a href ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>\n" +
3980
+ " <li ng-if=\"directionLinks\" ng-class=\"{disabled: noNext()}\"><a href ng-click=\"selectPage(page + 1)\">{{getText('next')}}</a></li>\n" +
3981
+ " <li ng-if=\"boundaryLinks\" ng-class=\"{disabled: noNext()}\"><a href ng-click=\"selectPage(totalPages)\">{{getText('last')}}</a></li>\n" +
3982
+ "</ul>");
3983
+ }]);
3984
+
3985
+ angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) {
3986
+ $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html",
3987
+ "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
3988
+ " <div class=\"tooltip-arrow\"></div>\n" +
3989
+ " <div class=\"tooltip-inner\" bind-html-unsafe=\"content\"></div>\n" +
3990
+ "</div>\n" +
3991
+ "");
3992
+ }]);
3993
+
3994
+ angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
3995
+ $templateCache.put("template/tooltip/tooltip-popup.html",
3996
+ "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
3997
+ " <div class=\"tooltip-arrow\"></div>\n" +
3998
+ " <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
3999
+ "</div>\n" +
4000
+ "");
4001
+ }]);
4002
+
4003
+ angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
4004
+ $templateCache.put("template/popover/popover.html",
4005
+ "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
4006
+ " <div class=\"arrow\"></div>\n" +
4007
+ "\n" +
4008
+ " <div class=\"popover-inner\">\n" +
4009
+ " <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
4010
+ " <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
4011
+ " </div>\n" +
4012
+ "</div>\n" +
4013
+ "");
4014
+ }]);
4015
+
4016
+ angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
4017
+ $templateCache.put("template/progressbar/bar.html",
4018
+ "<div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: percent + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" ng-transclude></div>");
4019
+ }]);
4020
+
4021
+ angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
4022
+ $templateCache.put("template/progressbar/progress.html",
4023
+ "<div class=\"progress\" ng-transclude></div>");
4024
+ }]);
4025
+
4026
+ angular.module("template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
4027
+ $templateCache.put("template/progressbar/progressbar.html",
4028
+ "<div class=\"progress\">\n" +
4029
+ " <div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: percent + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" ng-transclude></div>\n" +
4030
+ "</div>");
4031
+ }]);
4032
+
4033
+ angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
4034
+ $templateCache.put("template/rating/rating.html",
4035
+ "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\">\n" +
4036
+ " <i ng-repeat=\"r in range track by $index\" ng-mouseenter=\"enter($index + 1)\" ng-click=\"rate($index + 1)\" class=\"glyphicon\" ng-class=\"$index < value && (r.stateOn || 'glyphicon-star') || (r.stateOff || 'glyphicon-star-empty')\">\n" +
4037
+ " <span class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
4038
+ " </i>\n" +
4039
+ "</span>");
4040
+ }]);
4041
+
4042
+ angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
4043
+ $templateCache.put("template/tabs/tab.html",
4044
+ "<li ng-class=\"{active: active, disabled: disabled}\">\n" +
4045
+ " <a ng-click=\"select()\" tab-heading-transclude>{{heading}}</a>\n" +
4046
+ "</li>\n" +
4047
+ "");
4048
+ }]);
4049
+
4050
+ angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) {
4051
+ $templateCache.put("template/tabs/tabset-titles.html",
4052
+ "<ul class=\"nav {{type && 'nav-' + type}}\" ng-class=\"{'nav-stacked': vertical}\">\n" +
4053
+ "</ul>\n" +
4054
+ "");
4055
+ }]);
4056
+
4057
+ angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
4058
+ $templateCache.put("template/tabs/tabset.html",
4059
+ "\n" +
4060
+ "<div>\n" +
4061
+ " <ul class=\"nav nav-{{type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
4062
+ " <div class=\"tab-content\">\n" +
4063
+ " <div class=\"tab-pane\" \n" +
4064
+ " ng-repeat=\"tab in tabs\" \n" +
4065
+ " ng-class=\"{active: tab.active}\"\n" +
4066
+ " tab-content-transclude=\"tab\">\n" +
4067
+ " </div>\n" +
4068
+ " </div>\n" +
4069
+ "</div>\n" +
4070
+ "");
4071
+ }]);
4072
+
4073
+ angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
4074
+ $templateCache.put("template/timepicker/timepicker.html",
4075
+ "<table>\n" +
4076
+ " <tbody>\n" +
4077
+ " <tr class=\"text-center\">\n" +
4078
+ " <td><a ng-click=\"incrementHours()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
4079
+ " <td>&nbsp;</td>\n" +
4080
+ " <td><a ng-click=\"incrementMinutes()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
4081
+ " <td ng-show=\"showMeridian\"></td>\n" +
4082
+ " </tr>\n" +
4083
+ " <tr>\n" +
4084
+ " <td style=\"width:50px;\" class=\"form-group\" ng-class=\"{'has-error': invalidHours}\">\n" +
4085
+ " <input type=\"text\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"form-control text-center\" ng-mousewheel=\"incrementHours()\" ng-readonly=\"readonlyInput\" maxlength=\"2\">\n" +
4086
+ " </td>\n" +
4087
+ " <td>:</td>\n" +
4088
+ " <td style=\"width:50px;\" class=\"form-group\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
4089
+ " <input type=\"text\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"form-control text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\">\n" +
4090
+ " </td>\n" +
4091
+ " <td ng-show=\"showMeridian\"><button type=\"button\" class=\"btn btn-default text-center\" ng-click=\"toggleMeridian()\">{{meridian}}</button></td>\n" +
4092
+ " </tr>\n" +
4093
+ " <tr class=\"text-center\">\n" +
4094
+ " <td><a ng-click=\"decrementHours()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
4095
+ " <td>&nbsp;</td>\n" +
4096
+ " <td><a ng-click=\"decrementMinutes()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
4097
+ " <td ng-show=\"showMeridian\"></td>\n" +
4098
+ " </tr>\n" +
4099
+ " </tbody>\n" +
4100
+ "</table>\n" +
4101
+ "");
4102
+ }]);
4103
+
4104
+ angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
4105
+ $templateCache.put("template/typeahead/typeahead-match.html",
4106
+ "<a tabindex=\"-1\" bind-html-unsafe=\"match.label | typeaheadHighlight:query\"></a>");
4107
+ }]);
4108
+
4109
+ angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
4110
+ $templateCache.put("template/typeahead/typeahead-popup.html",
4111
+ "<ul class=\"dropdown-menu\" ng-if=\"isOpen()\" ng-style=\"{top: position.top+'px', left: position.left+'px'}\" style=\"display: block;\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
4112
+ " <li ng-repeat=\"match in matches track by $index\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index)\" role=\"option\" id=\"{{match.id}}\">\n" +
4113
+ " <div typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
4114
+ " </li>\n" +
4115
+ "</ul>");
4116
+ }]);