bastion 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. checksums.yaml +15 -0
  2. data/.jshintrc +35 -0
  3. data/Gruntfile.js +24 -0
  4. data/LICENSE +339 -0
  5. data/README.md +8 -0
  6. data/Rakefile +53 -0
  7. data/app/assets/javascripts/bastion/auth/auth.module.js +87 -0
  8. data/app/assets/javascripts/bastion/auth/authorization.service.js +48 -0
  9. data/app/assets/javascripts/bastion/bastion-bootstrap.js +32 -0
  10. data/app/assets/javascripts/bastion/bastion-resource.factory.js +39 -0
  11. data/app/assets/javascripts/bastion/bastion.js +52 -0
  12. data/app/assets/javascripts/bastion/bastion.module.js +213 -0
  13. data/app/assets/javascripts/bastion/i18n/README +9 -0
  14. data/app/assets/javascripts/bastion/i18n/i18n.module.js +24 -0
  15. data/app/assets/javascripts/bastion/i18n/katello.pot +968 -0
  16. data/app/assets/javascripts/bastion/i18n/locale/README +1 -0
  17. data/app/assets/javascripts/bastion/i18n/translate.service.js +14 -0
  18. data/app/assets/javascripts/bastion/i18n/translations.js +3 -0
  19. data/app/assets/javascripts/bastion/i18n/zanata.xml +28 -0
  20. data/app/assets/javascripts/bastion/incubator/alch-alert.directive.js +67 -0
  21. data/app/assets/javascripts/bastion/incubator/alch-container-scroll.directive.js +44 -0
  22. data/app/assets/javascripts/bastion/incubator/alch-dropdown.directive.js +28 -0
  23. data/app/assets/javascripts/bastion/incubator/alch-edit.directive.js +361 -0
  24. data/app/assets/javascripts/bastion/incubator/alch-flyout.directive.js +19 -0
  25. data/app/assets/javascripts/bastion/incubator/alch-form-buttons.directive.js +60 -0
  26. data/app/assets/javascripts/bastion/incubator/alch-form-group.directive.js +87 -0
  27. data/app/assets/javascripts/bastion/incubator/alch-infinite-scroll.directive.js +84 -0
  28. data/app/assets/javascripts/bastion/incubator/alch-menu.directive.js +56 -0
  29. data/app/assets/javascripts/bastion/incubator/alch-modal.directive.js +80 -0
  30. data/app/assets/javascripts/bastion/incubator/alch-save-control.directive.js +42 -0
  31. data/app/assets/javascripts/bastion/incubator/alch-table.directive.js +295 -0
  32. data/app/assets/javascripts/bastion/incubator/format/alch-format.module.js +21 -0
  33. data/app/assets/javascripts/bastion/incubator/format/array-to-string.filter.js +30 -0
  34. data/app/assets/javascripts/bastion/incubator/format/boolean-to-yes-no.filter.js +34 -0
  35. data/app/assets/javascripts/bastion/incubator/format/capitalize.filter.js +32 -0
  36. data/app/assets/javascripts/bastion/incubator/format/key-value-to-string.filter.js +40 -0
  37. data/app/assets/javascripts/bastion/incubator/format/unlimitedFilter.filter.js +35 -0
  38. data/app/assets/javascripts/bastion/incubator/stylesheets/alch-edit.scss +34 -0
  39. data/app/assets/javascripts/bastion/incubator/stylesheets/header.scss +207 -0
  40. data/app/assets/javascripts/bastion/incubator/views/alch-alert.html +6 -0
  41. data/app/assets/javascripts/bastion/incubator/views/alch-dropdown.html +19 -0
  42. data/app/assets/javascripts/bastion/incubator/views/alch-edit-add-item.html +21 -0
  43. data/app/assets/javascripts/bastion/incubator/views/alch-edit-add-remove-cancel.html +28 -0
  44. data/app/assets/javascripts/bastion/incubator/views/alch-edit-checkbox.html +6 -0
  45. data/app/assets/javascripts/bastion/incubator/views/alch-edit-custom.html +8 -0
  46. data/app/assets/javascripts/bastion/incubator/views/alch-edit-multiselect.html +17 -0
  47. data/app/assets/javascripts/bastion/incubator/views/alch-edit-save-cancel.html +20 -0
  48. data/app/assets/javascripts/bastion/incubator/views/alch-edit-select.html +10 -0
  49. data/app/assets/javascripts/bastion/incubator/views/alch-edit-text.html +6 -0
  50. data/app/assets/javascripts/bastion/incubator/views/alch-edit-textarea.html +6 -0
  51. data/app/assets/javascripts/bastion/incubator/views/alch-edit.html +18 -0
  52. data/app/assets/javascripts/bastion/incubator/views/alch-flyout.html +10 -0
  53. data/app/assets/javascripts/bastion/incubator/views/alch-form-buttons.html +10 -0
  54. data/app/assets/javascripts/bastion/incubator/views/alch-form-group.html +9 -0
  55. data/app/assets/javascripts/bastion/incubator/views/alch-menu.html +18 -0
  56. data/app/assets/javascripts/bastion/incubator/views/alch-modal-remove.html +13 -0
  57. data/app/assets/javascripts/bastion/incubator/views/alch-save-control.html +18 -0
  58. data/app/assets/javascripts/bastion/layouts/details-nutupane.html +73 -0
  59. data/app/assets/javascripts/bastion/layouts/nutupane.html +63 -0
  60. data/app/assets/javascripts/bastion/layouts/select-all-results.html +9 -0
  61. data/app/assets/javascripts/bastion/menu/menu-expander.service.js +51 -0
  62. data/app/assets/javascripts/bastion/menu/menu.module.js +26 -0
  63. data/app/assets/javascripts/bastion/utils/as.filter.js +33 -0
  64. data/app/assets/javascripts/bastion/utils/form-utils.service.js +53 -0
  65. data/app/assets/javascripts/bastion/utils/utils.module.js +21 -0
  66. data/app/assets/javascripts/bastion/widgets/current-tasks.directive.js +67 -0
  67. data/app/assets/javascripts/bastion/widgets/nutupane-table.directive.js +59 -0
  68. data/app/assets/javascripts/bastion/widgets/nutupane.factory.js +316 -0
  69. data/app/assets/javascripts/bastion/widgets/page-title.directive.js +61 -0
  70. data/app/assets/javascripts/bastion/widgets/page-title.service.js +42 -0
  71. data/app/assets/javascripts/bastion/widgets/path-selector.directive.js +109 -0
  72. data/app/assets/javascripts/bastion/widgets/views/current-tasks.html +23 -0
  73. data/app/assets/javascripts/bastion/widgets/views/path-selector.html +11 -0
  74. data/app/assets/javascripts/bastion/widgets/widgets.module.js +24 -0
  75. data/app/assets/stylesheets/bastion/animations.less +15 -0
  76. data/app/assets/stylesheets/bastion/bastion.less +160 -0
  77. data/app/assets/stylesheets/bastion/forms.less +41 -0
  78. data/app/assets/stylesheets/bastion/gpg-keys.less +36 -0
  79. data/app/assets/stylesheets/bastion/helpers.less +6 -0
  80. data/app/assets/stylesheets/bastion/mixins.less +15 -0
  81. data/app/assets/stylesheets/bastion/nutupane.less +382 -0
  82. data/app/assets/stylesheets/bastion/overrides.less +54 -0
  83. data/app/assets/stylesheets/bastion/path-selector.less +123 -0
  84. data/app/assets/stylesheets/bastion/systems.less +35 -0
  85. data/app/assets/stylesheets/bastion/tasks.less +23 -0
  86. data/app/assets/stylesheets/bastion/typography.less +31 -0
  87. data/app/assets/stylesheets/bastion/variables.less +3 -0
  88. data/app/controllers/bastion/bastion_controller.rb +24 -0
  89. data/app/views/bastion/layouts/application.html.erb +32 -0
  90. data/app/views/bastion/layouts/application_ie.html.erb +5 -0
  91. data/bastion.js +26 -0
  92. data/bower.json +94 -0
  93. data/config/routes.rb +25 -0
  94. data/config/routes/mount_engine.rb +3 -0
  95. data/grunt/bower.js +20 -0
  96. data/grunt/htmlhint.js +15 -0
  97. data/grunt/jshint.js +9 -0
  98. data/grunt/karma.js +83 -0
  99. data/lib/bastion.rb +17 -0
  100. data/lib/bastion/engine.rb +37 -0
  101. data/lib/bastion/version.rb +3 -0
  102. data/package.json +29 -0
  103. data/test/auth/authorization.service.test.js +63 -0
  104. data/test/bastion/bastion-resource.factory.test.js +31 -0
  105. data/test/bastion/test-constants.js +30 -0
  106. data/test/i18n/translate.service.test.js +31 -0
  107. data/test/incubator/alch-alert.directive.test.js +84 -0
  108. data/test/incubator/alch-container-scroll.directive.test.js +68 -0
  109. data/test/incubator/alch-dropdown.directive.test.js +113 -0
  110. data/test/incubator/alch-edit.directive.test.js +320 -0
  111. data/test/incubator/alch-flyout.directive.test.js +73 -0
  112. data/test/incubator/alch-form-buttons.directive.test.js +55 -0
  113. data/test/incubator/alch-form-group.directive.test.js +76 -0
  114. data/test/incubator/alch-infinite-scroll.directive.test.js +123 -0
  115. data/test/incubator/alch-menu.directive.test.js +94 -0
  116. data/test/incubator/alch-modal.directive.test.js +81 -0
  117. data/test/incubator/alch-table.directive.test.js +270 -0
  118. data/test/incubator/format/array-to-string.filter.test.js +38 -0
  119. data/test/incubator/format/boolean-to-yes-no.filter.test.js +41 -0
  120. data/test/incubator/format/capitalize.filter.test.js +35 -0
  121. data/test/incubator/format/key-value-to-string.filter.test.js +60 -0
  122. data/test/incubator/format/unlimited-filter.filter.test.js +31 -0
  123. data/test/incubator/nutupane-table.directive.test.js +69 -0
  124. data/test/incubator/nutupane.factory.test.js +307 -0
  125. data/test/menu/menu-expander.service.test.js +74 -0
  126. data/test/test-mocks.module.js +268 -0
  127. data/test/utils/as.filter.test.js +33 -0
  128. data/test/utils/form-utils.service.test.js +52 -0
  129. data/test/widgets/page-title.directive.test.js +54 -0
  130. data/test/widgets/page-title.service.test.js +51 -0
  131. data/test/widgets/path-selector.directive.test.js +136 -0
  132. data/vendor/assets/fonts/bastion/bootstrap/glyphicons-halflings-regular.eot +0 -0
  133. data/vendor/assets/fonts/bastion/bootstrap/glyphicons-halflings-regular.svg +229 -0
  134. data/vendor/assets/fonts/bastion/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  135. data/vendor/assets/fonts/bastion/bootstrap/glyphicons-halflings-regular.woff +0 -0
  136. data/vendor/assets/fonts/bastion/font-awesome/FontAwesome.otf +0 -0
  137. data/vendor/assets/fonts/bastion/font-awesome/fontawesome-webfont.eot +0 -0
  138. data/vendor/assets/fonts/bastion/font-awesome/fontawesome-webfont.svg +399 -0
  139. data/vendor/assets/fonts/bastion/font-awesome/fontawesome-webfont.ttf +0 -0
  140. data/vendor/assets/fonts/bastion/font-awesome/fontawesome-webfont.woff +0 -0
  141. data/vendor/assets/fonts/bastion/rcue/OpenSans-Bold-webfont.eot +0 -0
  142. data/vendor/assets/fonts/bastion/rcue/OpenSans-Bold-webfont.svg +146 -0
  143. data/vendor/assets/fonts/bastion/rcue/OpenSans-Bold-webfont.ttf +0 -0
  144. data/vendor/assets/fonts/bastion/rcue/OpenSans-Bold-webfont.woff +0 -0
  145. data/vendor/assets/fonts/bastion/rcue/OpenSans-BoldItalic-webfont.eot +0 -0
  146. data/vendor/assets/fonts/bastion/rcue/OpenSans-BoldItalic-webfont.svg +146 -0
  147. data/vendor/assets/fonts/bastion/rcue/OpenSans-BoldItalic-webfont.ttf +0 -0
  148. data/vendor/assets/fonts/bastion/rcue/OpenSans-BoldItalic-webfont.woff +0 -0
  149. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBold-webfont.eot +0 -0
  150. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBold-webfont.svg +146 -0
  151. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBold-webfont.ttf +0 -0
  152. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBold-webfont.woff +0 -0
  153. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBoldItalic-webfont.eot +0 -0
  154. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBoldItalic-webfont.svg +146 -0
  155. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBoldItalic-webfont.ttf +0 -0
  156. data/vendor/assets/fonts/bastion/rcue/OpenSans-ExtraBoldItalic-webfont.woff +0 -0
  157. data/vendor/assets/fonts/bastion/rcue/OpenSans-Italic-webfont.eot +0 -0
  158. data/vendor/assets/fonts/bastion/rcue/OpenSans-Italic-webfont.svg +146 -0
  159. data/vendor/assets/fonts/bastion/rcue/OpenSans-Italic-webfont.ttf +0 -0
  160. data/vendor/assets/fonts/bastion/rcue/OpenSans-Italic-webfont.woff +0 -0
  161. data/vendor/assets/fonts/bastion/rcue/OpenSans-Light-webfont.eot +0 -0
  162. data/vendor/assets/fonts/bastion/rcue/OpenSans-Light-webfont.svg +146 -0
  163. data/vendor/assets/fonts/bastion/rcue/OpenSans-Light-webfont.ttf +0 -0
  164. data/vendor/assets/fonts/bastion/rcue/OpenSans-Light-webfont.woff +0 -0
  165. data/vendor/assets/fonts/bastion/rcue/OpenSans-LightItalic-webfont.eot +0 -0
  166. data/vendor/assets/fonts/bastion/rcue/OpenSans-LightItalic-webfont.svg +146 -0
  167. data/vendor/assets/fonts/bastion/rcue/OpenSans-LightItalic-webfont.ttf +0 -0
  168. data/vendor/assets/fonts/bastion/rcue/OpenSans-LightItalic-webfont.woff +0 -0
  169. data/vendor/assets/fonts/bastion/rcue/OpenSans-Regular-webfont.eot +0 -0
  170. data/vendor/assets/fonts/bastion/rcue/OpenSans-Regular-webfont.svg +146 -0
  171. data/vendor/assets/fonts/bastion/rcue/OpenSans-Regular-webfont.ttf +0 -0
  172. data/vendor/assets/fonts/bastion/rcue/OpenSans-Regular-webfont.woff +0 -0
  173. data/vendor/assets/fonts/bastion/rcue/OpenSans-Semibold-webfont.eot +0 -0
  174. data/vendor/assets/fonts/bastion/rcue/OpenSans-Semibold-webfont.svg +146 -0
  175. data/vendor/assets/fonts/bastion/rcue/OpenSans-Semibold-webfont.ttf +0 -0
  176. data/vendor/assets/fonts/bastion/rcue/OpenSans-Semibold-webfont.woff +0 -0
  177. data/vendor/assets/fonts/bastion/rcue/OpenSans-SemiboldItalic-webfont.eot +0 -0
  178. data/vendor/assets/fonts/bastion/rcue/OpenSans-SemiboldItalic-webfont.svg +146 -0
  179. data/vendor/assets/fonts/bastion/rcue/OpenSans-SemiboldItalic-webfont.ttf +0 -0
  180. data/vendor/assets/fonts/bastion/rcue/OpenSans-SemiboldItalic-webfont.woff +0 -0
  181. data/vendor/assets/fonts/bastion/rcue/Overpass-Bold-webfont.eot +0 -0
  182. data/vendor/assets/fonts/bastion/rcue/Overpass-Bold-webfont.svg +454 -0
  183. data/vendor/assets/fonts/bastion/rcue/Overpass-Bold-webfont.ttf +0 -0
  184. data/vendor/assets/fonts/bastion/rcue/Overpass-Bold-webfont.woff +0 -0
  185. data/vendor/assets/fonts/bastion/rcue/Overpass-Regular-webfont.eot +0 -0
  186. data/vendor/assets/fonts/bastion/rcue/Overpass-Regular-webfont.svg +454 -0
  187. data/vendor/assets/fonts/bastion/rcue/Overpass-Regular-webfont.ttf +0 -0
  188. data/vendor/assets/fonts/bastion/rcue/Overpass-Regular-webfont.woff +0 -0
  189. data/vendor/assets/javascripts/bastion/alchemy/alchemy.js +20 -0
  190. data/vendor/assets/javascripts/bastion/angular-animate/angular-animate.js +1226 -0
  191. data/vendor/assets/javascripts/bastion/angular-blocks/angular-blocks.js +79 -0
  192. data/vendor/assets/javascripts/bastion/angular-bootstrap/ui-bootstrap-tpls.js +3677 -0
  193. data/vendor/assets/javascripts/bastion/angular-bootstrap/ui-bootstrap.js +3427 -0
  194. data/vendor/assets/javascripts/bastion/angular-gettext/angular-gettext.js +345 -0
  195. data/vendor/assets/javascripts/bastion/angular-resource/angular-resource.js +594 -0
  196. data/vendor/assets/javascripts/bastion/angular-route/angular-route.js +920 -0
  197. data/vendor/assets/javascripts/bastion/angular-sanitize/angular-sanitize.js +622 -0
  198. data/vendor/assets/javascripts/bastion/angular-ui-bootstrap/datepicker.js +447 -0
  199. data/vendor/assets/javascripts/bastion/angular-ui-bootstrap/timepicker.js +232 -0
  200. data/vendor/assets/javascripts/bastion/angular-ui-router/angular-ui-router.js +3223 -0
  201. data/vendor/assets/javascripts/bastion/angular-uuid4/angular-uuid4.js +21 -0
  202. data/vendor/assets/javascripts/bastion/angular/angular.js +20560 -0
  203. data/vendor/assets/javascripts/bastion/es5-shim/es5-shim.js +1216 -0
  204. data/vendor/assets/javascripts/bastion/json3/json3.js +861 -0
  205. data/vendor/assets/javascripts/bastion/ngUpload/ng-upload.js +205 -0
  206. data/vendor/assets/javascripts/bastion/underscore/underscore.js +1276 -0
  207. data/vendor/assets/stylesheets/bastion/alchemy/_colors.scss +99 -0
  208. data/vendor/assets/stylesheets/bastion/alchemy/_media_object.scss +22 -0
  209. data/vendor/assets/stylesheets/bastion/alchemy/_mixins.scss +24 -0
  210. data/vendor/assets/stylesheets/bastion/alchemy/_normalize.scss +396 -0
  211. data/vendor/assets/stylesheets/bastion/alchemy/_vars.scss +31 -0
  212. data/vendor/assets/stylesheets/bastion/alchemy/alchemy.scss +8 -0
  213. data/vendor/assets/stylesheets/bastion/bootstrap/alerts.less +67 -0
  214. data/vendor/assets/stylesheets/bastion/bootstrap/badges.less +51 -0
  215. data/vendor/assets/stylesheets/bastion/bootstrap/bootstrap.less +49 -0
  216. data/vendor/assets/stylesheets/bastion/bootstrap/breadcrumbs.less +23 -0
  217. data/vendor/assets/stylesheets/bastion/bootstrap/button-groups.less +227 -0
  218. data/vendor/assets/stylesheets/bastion/bootstrap/buttons.less +155 -0
  219. data/vendor/assets/stylesheets/bastion/bootstrap/carousel.less +232 -0
  220. data/vendor/assets/stylesheets/bastion/bootstrap/close.less +33 -0
  221. data/vendor/assets/stylesheets/bastion/bootstrap/code.less +53 -0
  222. data/vendor/assets/stylesheets/bastion/bootstrap/component-animations.less +29 -0
  223. data/vendor/assets/stylesheets/bastion/bootstrap/dropdowns.less +187 -0
  224. data/vendor/assets/stylesheets/bastion/bootstrap/forms.less +375 -0
  225. data/vendor/assets/stylesheets/bastion/bootstrap/glyphicons.less +237 -0
  226. data/vendor/assets/stylesheets/bastion/bootstrap/grid.less +79 -0
  227. data/vendor/assets/stylesheets/bastion/bootstrap/input-groups.less +136 -0
  228. data/vendor/assets/stylesheets/bastion/bootstrap/jumbotron.less +46 -0
  229. data/vendor/assets/stylesheets/bastion/bootstrap/labels.less +64 -0
  230. data/vendor/assets/stylesheets/bastion/bootstrap/list-group.less +88 -0
  231. data/vendor/assets/stylesheets/bastion/bootstrap/media.less +56 -0
  232. data/vendor/assets/stylesheets/bastion/bootstrap/mixins.less +845 -0
  233. data/vendor/assets/stylesheets/bastion/bootstrap/modals.less +129 -0
  234. data/vendor/assets/stylesheets/bastion/bootstrap/navbar.less +612 -0
  235. data/vendor/assets/stylesheets/bastion/bootstrap/navs.less +242 -0
  236. data/vendor/assets/stylesheets/bastion/bootstrap/normalize.less +406 -0
  237. data/vendor/assets/stylesheets/bastion/bootstrap/pager.less +55 -0
  238. data/vendor/assets/stylesheets/bastion/bootstrap/pagination.less +85 -0
  239. data/vendor/assets/stylesheets/bastion/bootstrap/panels.less +182 -0
  240. data/vendor/assets/stylesheets/bastion/bootstrap/popovers.less +133 -0
  241. data/vendor/assets/stylesheets/bastion/bootstrap/print.less +105 -0
  242. data/vendor/assets/stylesheets/bastion/bootstrap/progress-bars.less +80 -0
  243. data/vendor/assets/stylesheets/bastion/bootstrap/responsive-utilities.less +209 -0
  244. data/vendor/assets/stylesheets/bastion/bootstrap/scaffolding.less +119 -0
  245. data/vendor/assets/stylesheets/bastion/bootstrap/tables.less +231 -0
  246. data/vendor/assets/stylesheets/bastion/bootstrap/theme.less +247 -0
  247. data/vendor/assets/stylesheets/bastion/bootstrap/thumbnails.less +36 -0
  248. data/vendor/assets/stylesheets/bastion/bootstrap/tooltip.less +95 -0
  249. data/vendor/assets/stylesheets/bastion/bootstrap/type.less +281 -0
  250. data/vendor/assets/stylesheets/bastion/bootstrap/utilities.less +56 -0
  251. data/vendor/assets/stylesheets/bastion/bootstrap/variables.less +642 -0
  252. data/vendor/assets/stylesheets/bastion/bootstrap/wells.less +29 -0
  253. data/vendor/assets/stylesheets/bastion/font-awesome/less/bootstrap.less +84 -0
  254. data/vendor/assets/stylesheets/bastion/font-awesome/less/core.less +129 -0
  255. data/vendor/assets/stylesheets/bastion/font-awesome/less/extras.less +93 -0
  256. data/vendor/assets/stylesheets/bastion/font-awesome/less/font-awesome-ie7.less +1953 -0
  257. data/vendor/assets/stylesheets/bastion/font-awesome/less/font-awesome.less +33 -0
  258. data/vendor/assets/stylesheets/bastion/font-awesome/less/icons.less +381 -0
  259. data/vendor/assets/stylesheets/bastion/font-awesome/less/mixins.less +48 -0
  260. data/vendor/assets/stylesheets/bastion/font-awesome/less/path.less +14 -0
  261. data/vendor/assets/stylesheets/bastion/font-awesome/less/variables.less +735 -0
  262. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_bootstrap.scss +84 -0
  263. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_core.scss +129 -0
  264. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_extras.scss +93 -0
  265. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_icons.scss +381 -0
  266. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_mixins.scss +48 -0
  267. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_path.scss +14 -0
  268. data/vendor/assets/stylesheets/bastion/font-awesome/scss/_variables.scss +734 -0
  269. data/vendor/assets/stylesheets/bastion/font-awesome/scss/font-awesome-ie7.scss +1953 -0
  270. data/vendor/assets/stylesheets/bastion/font-awesome/scss/font-awesome.scss +33 -0
  271. data/vendor/assets/stylesheets/bastion/rcue/buttons.less +44 -0
  272. data/vendor/assets/stylesheets/bastion/rcue/fonts.less +52 -0
  273. data/vendor/assets/stylesheets/bastion/rcue/forms.less +19 -0
  274. data/vendor/assets/stylesheets/bastion/rcue/mixins.less +50 -0
  275. data/vendor/assets/stylesheets/bastion/rcue/navbar.less +481 -0
  276. data/vendor/assets/stylesheets/bastion/rcue/rcue.less +15 -0
  277. data/vendor/assets/stylesheets/bastion/rcue/variables.less +47 -0
  278. metadata +376 -0
@@ -0,0 +1,447 @@
1
+ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
2
+
3
+ .constant('datepickerConfig', {
4
+ dayFormat: 'dd',
5
+ monthFormat: 'MMMM',
6
+ yearFormat: 'yyyy',
7
+ dayHeaderFormat: 'EEE',
8
+ dayTitleFormat: 'MMMM yyyy',
9
+ monthTitleFormat: 'yyyy',
10
+ showWeeks: true,
11
+ startingDay: 0,
12
+ yearRange: 20,
13
+ minDate: null,
14
+ maxDate: null
15
+ })
16
+
17
+ .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
18
+ var format = {
19
+ day: getValue($attrs.dayFormat, dtConfig.dayFormat),
20
+ month: getValue($attrs.monthFormat, dtConfig.monthFormat),
21
+ year: getValue($attrs.yearFormat, dtConfig.yearFormat),
22
+ dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
23
+ dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
24
+ monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat)
25
+ },
26
+ startingDay = getValue($attrs.startingDay, dtConfig.startingDay),
27
+ yearRange = getValue($attrs.yearRange, dtConfig.yearRange);
28
+
29
+ this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null;
30
+ this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null;
31
+
32
+ function getValue(value, defaultValue) {
33
+ return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
34
+ }
35
+
36
+ function getDaysInMonth( year, month ) {
37
+ return new Date(year, month, 0).getDate();
38
+ }
39
+
40
+ function getDates(startDate, n) {
41
+ var dates = new Array(n);
42
+ var current = startDate, i = 0;
43
+ while (i < n) {
44
+ dates[i++] = new Date(current);
45
+ current.setDate( current.getDate() + 1 );
46
+ }
47
+ return dates;
48
+ }
49
+
50
+ function makeDate(date, format, isSelected, isSecondary) {
51
+ return { date: date, label: dateFilter(date, format), selected: !!isSelected, secondary: !!isSecondary };
52
+ }
53
+
54
+ this.modes = [
55
+ {
56
+ name: 'day',
57
+ getVisibleDates: function(date, selected) {
58
+ var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1);
59
+ var difference = startingDay - firstDayOfMonth.getDay(),
60
+ numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
61
+ firstDate = new Date(firstDayOfMonth), numDates = 0;
62
+
63
+ if ( numDisplayedFromPreviousMonth > 0 ) {
64
+ firstDate.setDate( - numDisplayedFromPreviousMonth + 1 );
65
+ numDates += numDisplayedFromPreviousMonth; // Previous
66
+ }
67
+ numDates += getDaysInMonth(year, month + 1); // Current
68
+ numDates += (7 - numDates % 7) % 7; // Next
69
+
70
+ var days = getDates(firstDate, numDates), labels = new Array(7);
71
+ for (var i = 0; i < numDates; i ++) {
72
+ var dt = new Date(days[i]);
73
+ days[i] = makeDate(dt, format.day, (selected && selected.getDate() === dt.getDate() && selected.getMonth() === dt.getMonth() && selected.getFullYear() === dt.getFullYear()), dt.getMonth() !== month);
74
+ }
75
+ for (var j = 0; j < 7; j++) {
76
+ labels[j] = dateFilter(days[j].date, format.dayHeader);
77
+ }
78
+ return { objects: days, title: dateFilter(date, format.dayTitle), labels: labels };
79
+ },
80
+ compare: function(date1, date2) {
81
+ return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) );
82
+ },
83
+ split: 7,
84
+ step: { months: 1 }
85
+ },
86
+ {
87
+ name: 'month',
88
+ getVisibleDates: function(date, selected) {
89
+ var months = new Array(12), year = date.getFullYear();
90
+ for ( var i = 0; i < 12; i++ ) {
91
+ var dt = new Date(year, i, 1);
92
+ months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year));
93
+ }
94
+ return { objects: months, title: dateFilter(date, format.monthTitle) };
95
+ },
96
+ compare: function(date1, date2) {
97
+ return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
98
+ },
99
+ split: 3,
100
+ step: { years: 1 }
101
+ },
102
+ {
103
+ name: 'year',
104
+ getVisibleDates: function(date, selected) {
105
+ var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1;
106
+ for ( var i = 0; i < yearRange; i++ ) {
107
+ var dt = new Date(startYear + i, 0, 1);
108
+ years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear()));
109
+ }
110
+ return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') };
111
+ },
112
+ compare: function(date1, date2) {
113
+ return date1.getFullYear() - date2.getFullYear();
114
+ },
115
+ split: 5,
116
+ step: { years: yearRange }
117
+ }
118
+ ];
119
+
120
+ this.isDisabled = function(date, mode) {
121
+ var currentMode = this.modes[mode || 0];
122
+ return ((this.minDate && currentMode.compare(date, this.minDate) < 0) || (this.maxDate && currentMode.compare(date, this.maxDate) > 0) || ($scope.dateDisabled && $scope.dateDisabled({date: date, mode: currentMode.name})));
123
+ };
124
+ }])
125
+
126
+ .directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', '$log', function (dateFilter, $parse, datepickerConfig, $log) {
127
+ return {
128
+ restrict: 'EA',
129
+ replace: true,
130
+ templateUrl: 'template/datepicker/datepicker.html',
131
+ scope: {
132
+ dateDisabled: '&'
133
+ },
134
+ require: ['datepicker', '?^ngModel'],
135
+ controller: 'DatepickerController',
136
+ link: function(scope, element, attrs, ctrls) {
137
+ var datepickerCtrl = ctrls[0], ngModel = ctrls[1];
138
+
139
+ if (!ngModel) {
140
+ return; // do nothing if no ng-model
141
+ }
142
+
143
+ // Configuration parameters
144
+ var mode = 0, selected = new Date(), showWeeks = datepickerConfig.showWeeks;
145
+
146
+ if (attrs.showWeeks) {
147
+ scope.$parent.$watch($parse(attrs.showWeeks), function(value) {
148
+ showWeeks = !! value;
149
+ updateShowWeekNumbers();
150
+ });
151
+ } else {
152
+ updateShowWeekNumbers();
153
+ }
154
+
155
+ if (attrs.min) {
156
+ scope.$parent.$watch($parse(attrs.min), function(value) {
157
+ datepickerCtrl.minDate = value ? new Date(value) : null;
158
+ refill();
159
+ });
160
+ }
161
+ if (attrs.max) {
162
+ scope.$parent.$watch($parse(attrs.max), function(value) {
163
+ datepickerCtrl.maxDate = value ? new Date(value) : null;
164
+ refill();
165
+ });
166
+ }
167
+
168
+ function updateShowWeekNumbers() {
169
+ scope.showWeekNumbers = mode === 0 && showWeeks;
170
+ }
171
+
172
+ // Split array into smaller arrays
173
+ function split(arr, size) {
174
+ var arrays = [];
175
+ while (arr.length > 0) {
176
+ arrays.push(arr.splice(0, size));
177
+ }
178
+ return arrays;
179
+ }
180
+
181
+ function refill( updateSelected ) {
182
+ var date = null, valid = true;
183
+
184
+ if ( ngModel.$modelValue ) {
185
+ date = new Date( ngModel.$modelValue );
186
+
187
+ if ( isNaN(date) ) {
188
+ valid = false;
189
+ $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.');
190
+ } else if ( updateSelected ) {
191
+ selected = date;
192
+ }
193
+ }
194
+ ngModel.$setValidity('date', valid);
195
+
196
+ var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date);
197
+ angular.forEach(data.objects, function(obj) {
198
+ obj.disabled = datepickerCtrl.isDisabled(obj.date, mode);
199
+ });
200
+
201
+ ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date)));
202
+
203
+ scope.rows = split(data.objects, currentMode.split);
204
+ scope.labels = data.labels || [];
205
+ scope.title = data.title;
206
+ }
207
+
208
+ function setMode(value) {
209
+ mode = value;
210
+ updateShowWeekNumbers();
211
+ refill();
212
+ }
213
+
214
+ ngModel.$render = function() {
215
+ refill( true );
216
+ };
217
+
218
+ scope.select = function( date ) {
219
+ if ( mode === 0 ) {
220
+ var dt = new Date( ngModel.$modelValue );
221
+ dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() );
222
+ ngModel.$setViewValue( dt );
223
+ refill( true );
224
+ } else {
225
+ selected = date;
226
+ setMode( mode - 1 );
227
+ }
228
+ };
229
+ scope.move = function(direction) {
230
+ var step = datepickerCtrl.modes[mode].step;
231
+ selected.setMonth( selected.getMonth() + direction * (step.months || 0) );
232
+ selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) );
233
+ refill();
234
+ };
235
+ scope.toggleMode = function() {
236
+ setMode( (mode + 1) % datepickerCtrl.modes.length );
237
+ };
238
+ scope.getWeekNumber = function(row) {
239
+ return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null;
240
+ };
241
+
242
+ function getISO8601WeekNumber(date) {
243
+ var checkDate = new Date(date);
244
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
245
+ var time = checkDate.getTime();
246
+ checkDate.setMonth(0); // Compare with Jan 1
247
+ checkDate.setDate(1);
248
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
249
+ }
250
+ }
251
+ };
252
+ }])
253
+
254
+ .constant('datepickerPopupConfig', {
255
+ dateFormat: 'yyyy-MM-dd',
256
+ closeOnDateSelection: true
257
+ })
258
+
259
+ .directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig',
260
+ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig) {
261
+ return {
262
+ restrict: 'EA',
263
+ require: 'ngModel',
264
+ link: function(originalScope, element, attrs, ngModel) {
265
+
266
+ var closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
267
+ var dateFormat = attrs.datepickerPopup || datepickerPopupConfig.dateFormat;
268
+
269
+ // create a child scope for the datepicker directive so we are not polluting original scope
270
+ var scope = originalScope.$new();
271
+ originalScope.$on('$destroy', function() {
272
+ scope.$destroy();
273
+ });
274
+
275
+ var getIsOpen, setIsOpen;
276
+ if ( attrs.isOpen ) {
277
+ getIsOpen = $parse(attrs.isOpen);
278
+ setIsOpen = getIsOpen.assign;
279
+
280
+ originalScope.$watch(getIsOpen, function updateOpen(value) {
281
+ scope.isOpen = !! value;
282
+ });
283
+ }
284
+ scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state
285
+
286
+ function setOpen( value ) {
287
+ if (setIsOpen) {
288
+ setIsOpen(originalScope, !!value);
289
+ } else {
290
+ scope.isOpen = !!value;
291
+ }
292
+ }
293
+
294
+ var documentClickBind = function(event) {
295
+ if (scope.isOpen && event.target !== element[0]) {
296
+ scope.$apply(function() {
297
+ setOpen(false);
298
+ });
299
+ }
300
+ };
301
+
302
+ var elementFocusBind = function() {
303
+ scope.$apply(function() {
304
+ setOpen( true );
305
+ });
306
+ };
307
+
308
+ // popup element used to display calendar
309
+ var popupEl = angular.element('<datepicker-popup-wrap><datepicker></datepicker></datepicker-popup-wrap>');
310
+ popupEl.attr({
311
+ 'ng-model': 'date',
312
+ 'ng-change': 'dateSelection()'
313
+ });
314
+ var datepickerEl = popupEl.find('datepicker');
315
+ if (attrs.datepickerOptions) {
316
+ datepickerEl.attr(angular.extend({}, originalScope.$eval(attrs.datepickerOptions)));
317
+ }
318
+
319
+ // TODO: reverse from dateFilter string to Date object
320
+ function parseDate(viewValue) {
321
+ if (!viewValue) {
322
+ ngModel.$setValidity('date', true);
323
+ return null;
324
+ } else if (angular.isDate(viewValue)) {
325
+ ngModel.$setValidity('date', true);
326
+ return viewValue;
327
+ } else if (angular.isString(viewValue)) {
328
+ var date = new Date(viewValue);
329
+ if (isNaN(date)) {
330
+ ngModel.$setValidity('date', false);
331
+ return undefined;
332
+ } else {
333
+ ngModel.$setValidity('date', true);
334
+ return date;
335
+ }
336
+ } else {
337
+ ngModel.$setValidity('date', false);
338
+ return undefined;
339
+ }
340
+ }
341
+ ngModel.$parsers.unshift(parseDate);
342
+
343
+ // Inner change
344
+ scope.dateSelection = function() {
345
+ ngModel.$setViewValue(scope.date);
346
+ ngModel.$render();
347
+
348
+ if (closeOnDateSelection) {
349
+ setOpen( false );
350
+ }
351
+ };
352
+
353
+ element.bind('input change keyup', function() {
354
+ scope.$apply(function() {
355
+ updateCalendar();
356
+ });
357
+ });
358
+
359
+ // Outter change
360
+ ngModel.$render = function() {
361
+ var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
362
+ element.val(date);
363
+
364
+ updateCalendar();
365
+ };
366
+
367
+ function updateCalendar() {
368
+ scope.date = ngModel.$modelValue;
369
+ updatePosition();
370
+ }
371
+
372
+ function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) {
373
+ if (attribute) {
374
+ originalScope.$watch($parse(attribute), function(value){
375
+ scope[scopeProperty] = value;
376
+ });
377
+ datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty);
378
+ }
379
+ }
380
+ addWatchableAttribute(attrs.min, 'min');
381
+ addWatchableAttribute(attrs.max, 'max');
382
+ if (attrs.showWeeks) {
383
+ addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks');
384
+ } else {
385
+ scope.showWeeks = true;
386
+ datepickerEl.attr('show-weeks', 'showWeeks');
387
+ }
388
+ if (attrs.dateDisabled) {
389
+ datepickerEl.attr('date-disabled', attrs.dateDisabled);
390
+ }
391
+
392
+ function updatePosition() {
393
+ scope.position = $position.position(element);
394
+ scope.position.top = scope.position.top + element.prop('offsetHeight');
395
+ }
396
+
397
+ var documentBindingInitialized = false, elementFocusInitialized = false;
398
+ scope.$watch('isOpen', function(value) {
399
+ if (value) {
400
+ updatePosition();
401
+ $document.bind('click', documentClickBind);
402
+ if(elementFocusInitialized) {
403
+ element.unbind('focus', elementFocusBind);
404
+ }
405
+ element[0].focus();
406
+ documentBindingInitialized = true;
407
+ } else {
408
+ if(documentBindingInitialized) {
409
+ $document.unbind('click', documentClickBind);
410
+ }
411
+ element.bind('focus', elementFocusBind);
412
+ elementFocusInitialized = true;
413
+ }
414
+
415
+ if ( setIsOpen ) {
416
+ setIsOpen(originalScope, value);
417
+ }
418
+ });
419
+
420
+ var $setModelValue = $parse(attrs.ngModel).assign;
421
+
422
+ scope.today = function() {
423
+ $setModelValue(originalScope, new Date());
424
+ };
425
+ scope.clear = function() {
426
+ $setModelValue(originalScope, null);
427
+ };
428
+
429
+ element.after($compile(popupEl)(scope));
430
+ }
431
+ };
432
+ }])
433
+
434
+ .directive('datepickerPopupWrap', [function() {
435
+ return {
436
+ restrict:'E',
437
+ replace: true,
438
+ transclude: true,
439
+ templateUrl: 'template/datepicker/popup.html',
440
+ link:function (scope, element, attrs) {
441
+ element.bind('click', function(event) {
442
+ event.preventDefault();
443
+ event.stopPropagation();
444
+ });
445
+ }
446
+ };
447
+ }]);
@@ -0,0 +1,232 @@
1
+ angular.module('ui.bootstrap.timepicker', [])
2
+
3
+ .constant('timepickerConfig', {
4
+ hourStep: 1,
5
+ minuteStep: 1,
6
+ showMeridian: true,
7
+ meridians: ['AM', 'PM'],
8
+ readonlyInput: false,
9
+ mousewheel: true
10
+ })
11
+
12
+ .directive('timepicker', ['$parse', '$log', 'timepickerConfig', function ($parse, $log, timepickerConfig) {
13
+ return {
14
+ restrict: 'EA',
15
+ require:'?^ngModel',
16
+ replace: true,
17
+ scope: {},
18
+ templateUrl: 'template/timepicker/timepicker.html',
19
+ link: function(scope, element, attrs, ngModel) {
20
+ if ( !ngModel ) {
21
+ return; // do nothing if no ng-model
22
+ }
23
+
24
+ var selected = new Date(), meridians = timepickerConfig.meridians;
25
+
26
+ var hourStep = timepickerConfig.hourStep;
27
+ if (attrs.hourStep) {
28
+ scope.$parent.$watch($parse(attrs.hourStep), function(value) {
29
+ hourStep = parseInt(value, 10);
30
+ });
31
+ }
32
+
33
+ var minuteStep = timepickerConfig.minuteStep;
34
+ if (attrs.minuteStep) {
35
+ scope.$parent.$watch($parse(attrs.minuteStep), function(value) {
36
+ minuteStep = parseInt(value, 10);
37
+ });
38
+ }
39
+
40
+ // 12H / 24H mode
41
+ scope.showMeridian = timepickerConfig.showMeridian;
42
+ if (attrs.showMeridian) {
43
+ scope.$parent.$watch($parse(attrs.showMeridian), function(value) {
44
+ scope.showMeridian = !!value;
45
+
46
+ if ( ngModel.$error.time ) {
47
+ // Evaluate from template
48
+ var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
49
+ if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
50
+ selected.setHours( hours );
51
+ refresh();
52
+ }
53
+ } else {
54
+ updateTemplate();
55
+ }
56
+ });
57
+ }
58
+
59
+ // Get scope.hours in 24H mode if valid
60
+ function getHoursFromTemplate ( ) {
61
+ var hours = parseInt( scope.hours, 10 );
62
+ var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
63
+ if ( !valid ) {
64
+ return undefined;
65
+ }
66
+
67
+ if ( scope.showMeridian ) {
68
+ if ( hours === 12 ) {
69
+ hours = 0;
70
+ }
71
+ if ( scope.meridian === meridians[1] ) {
72
+ hours = hours + 12;
73
+ }
74
+ }
75
+ return hours;
76
+ }
77
+
78
+ function getMinutesFromTemplate() {
79
+ var minutes = parseInt(scope.minutes, 10);
80
+ return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
81
+ }
82
+
83
+ function pad( value ) {
84
+ return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
85
+ }
86
+
87
+ // Input elements
88
+ var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1);
89
+
90
+ // Respond on mousewheel spin
91
+ var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel;
92
+ if ( mousewheel ) {
93
+
94
+ var isScrollingUp = function(e) {
95
+ if (e.originalEvent) {
96
+ e = e.originalEvent;
97
+ }
98
+ //pick correct delta variable depending on event
99
+ var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
100
+ return (e.detail || delta > 0);
101
+ };
102
+
103
+ hoursInputEl.bind('mousewheel wheel', function(e) {
104
+ scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() );
105
+ e.preventDefault();
106
+ });
107
+
108
+ minutesInputEl.bind('mousewheel wheel', function(e) {
109
+ scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() );
110
+ e.preventDefault();
111
+ });
112
+ }
113
+
114
+ scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput;
115
+ if ( ! scope.readonlyInput ) {
116
+
117
+ var invalidate = function(invalidHours, invalidMinutes) {
118
+ ngModel.$setViewValue( null );
119
+ ngModel.$setValidity('time', false);
120
+ if (angular.isDefined(invalidHours)) {
121
+ scope.invalidHours = invalidHours;
122
+ }
123
+ if (angular.isDefined(invalidMinutes)) {
124
+ scope.invalidMinutes = invalidMinutes;
125
+ }
126
+ };
127
+
128
+ scope.updateHours = function() {
129
+ var hours = getHoursFromTemplate();
130
+
131
+ if ( angular.isDefined(hours) ) {
132
+ selected.setHours( hours );
133
+ refresh( 'h' );
134
+ } else {
135
+ invalidate(true);
136
+ }
137
+ };
138
+
139
+ hoursInputEl.bind('blur', function(e) {
140
+ if ( !scope.validHours && scope.hours < 10) {
141
+ scope.$apply( function() {
142
+ scope.hours = pad( scope.hours );
143
+ });
144
+ }
145
+ });
146
+
147
+ scope.updateMinutes = function() {
148
+ var minutes = getMinutesFromTemplate();
149
+
150
+ if ( angular.isDefined(minutes) ) {
151
+ selected.setMinutes( minutes );
152
+ refresh( 'm' );
153
+ } else {
154
+ invalidate(undefined, true);
155
+ }
156
+ };
157
+
158
+ minutesInputEl.bind('blur', function(e) {
159
+ if ( !scope.invalidMinutes && scope.minutes < 10 ) {
160
+ scope.$apply( function() {
161
+ scope.minutes = pad( scope.minutes );
162
+ });
163
+ }
164
+ });
165
+ } else {
166
+ scope.updateHours = angular.noop;
167
+ scope.updateMinutes = angular.noop;
168
+ }
169
+
170
+ ngModel.$render = function() {
171
+ var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null;
172
+
173
+ if ( isNaN(date) ) {
174
+ ngModel.$setValidity('time', false);
175
+ $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.');
176
+ } else {
177
+ if ( date ) {
178
+ selected = date;
179
+ }
180
+ makeValid();
181
+ updateTemplate();
182
+ }
183
+ };
184
+
185
+ // Call internally when we know that model is valid.
186
+ function refresh( keyboardChange ) {
187
+ makeValid();
188
+ ngModel.$setViewValue( new Date(selected) );
189
+ updateTemplate( keyboardChange );
190
+ }
191
+
192
+ function makeValid() {
193
+ ngModel.$setValidity('time', true);
194
+ scope.invalidHours = false;
195
+ scope.invalidMinutes = false;
196
+ }
197
+
198
+ function updateTemplate( keyboardChange ) {
199
+ var hours = selected.getHours(), minutes = selected.getMinutes();
200
+
201
+ if ( scope.showMeridian ) {
202
+ hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
203
+ }
204
+ scope.hours = keyboardChange === 'h' ? hours : pad(hours);
205
+ scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
206
+ scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
207
+ }
208
+
209
+ function addMinutes( minutes ) {
210
+ var dt = new Date( selected.getTime() + minutes * 60000 );
211
+ selected.setHours( dt.getHours(), dt.getMinutes() );
212
+ refresh();
213
+ }
214
+
215
+ scope.incrementHours = function() {
216
+ addMinutes( hourStep * 60 );
217
+ };
218
+ scope.decrementHours = function() {
219
+ addMinutes( - hourStep * 60 );
220
+ };
221
+ scope.incrementMinutes = function() {
222
+ addMinutes( minuteStep );
223
+ };
224
+ scope.decrementMinutes = function() {
225
+ addMinutes( - minuteStep );
226
+ };
227
+ scope.toggleMeridian = function() {
228
+ addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
229
+ };
230
+ }
231
+ };
232
+ }]);