sw2at-ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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>');