sw2at-ui 0.0.1

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