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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/Gemfile +21 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/app/assets/images/swat/loading-green.gif +0 -0
- data/app/assets/javascripts/swat/.bowerrc +3 -0
- data/app/assets/javascripts/swat/app/app.coffee +38 -0
- data/app/assets/javascripts/swat/app/controllers/revision.coffee +25 -0
- data/app/assets/javascripts/swat/app/controllers/revisions.coffee +10 -0
- data/app/assets/javascripts/swat/app/controllers/root.coffee +8 -0
- data/app/assets/javascripts/swat/app/factories/response.coffee +9 -0
- data/app/assets/javascripts/swat/app/factories/revision_model.coffee +20 -0
- data/app/assets/javascripts/swat/app/services/revision.coffee +16 -0
- data/app/assets/javascripts/swat/app/services/test_case.coffee +8 -0
- data/app/assets/javascripts/swat/application.coffee +5 -0
- data/app/assets/javascripts/swat/bower.json +16 -0
- data/app/assets/javascripts/swat/bower_components/angular/angular-csp.css +21 -0
- data/app/assets/javascripts/swat/bower_components/angular/angular.js +28133 -0
- data/app/assets/javascripts/swat/bower_components/angular/angular.min.js +289 -0
- data/app/assets/javascripts/swat/bower_components/angular/index.js +2 -0
- data/app/assets/javascripts/swat/bower_components/angular-animate/angular-animate.js +2137 -0
- data/app/assets/javascripts/swat/bower_components/angular-animate/angular-animate.min.js +33 -0
- data/app/assets/javascripts/swat/bower_components/angular-aria/angular-aria.js +339 -0
- data/app/assets/javascripts/swat/bower_components/angular-aria/angular-aria.min.js +12 -0
- data/app/assets/javascripts/swat/bower_components/angular-bootstrap/ui-bootstrap-csp.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-bootstrap/ui-bootstrap-tpls.js +4840 -0
- data/app/assets/javascripts/swat/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js +10 -0
- data/app/assets/javascripts/swat/bower_components/angular-bootstrap/ui-bootstrap.js +4461 -0
- data/app/assets/javascripts/swat/bower_components/angular-bootstrap/ui-bootstrap.min.js +9 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/LICENSE.txt +21 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/angular-material.css +6228 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/angular-material.js +8602 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/angular-material.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/angular-material.min.js +277 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/default-theme.css +394 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/backdrop/backdrop-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/backdrop/backdrop.css +54 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/backdrop/backdrop.js +40 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/bottomSheet/bottomSheet-default-theme.css +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/bottomSheet/bottomSheet.css +161 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/bottomSheet/bottomSheet.js +263 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/button/button-default-theme.css +49 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/button/button.css +134 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/button/button.js +101 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/card/card-default-theme.css +10 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/card/card.css +26 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/card/card.js +60 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/checkbox/checkbox-default-theme.css +38 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/checkbox/checkbox.css +78 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/checkbox/checkbox.js +135 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/content/content-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/content/content.css +24 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/content/content.js +87 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/core/core.css +2736 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/core/core.js +3090 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/core/default-theme.js +1 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/dialog/dialog-default-theme.css +11 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/dialog/dialog.css +75 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/dialog/dialog.js +500 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/divider/divider-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/divider/divider.css +12 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/divider/divider.js +50 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/icon/icon.css +24 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/icon/icon.js +52 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/input/input-default-theme.css +39 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/input/input.css +113 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/input/input.js +355 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/list/list.css +56 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/list/list.js +96 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/menu/menu.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/menu/menu.js +29 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressCircular/progressCircular-default-theme.css +35 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressCircular/progressCircular.css +1395 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressCircular/progressCircular.js +129 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressLinear/progressLinear-default-theme.css +26 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressLinear/progressLinear.css +366 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/progressLinear/progressLinear.js +130 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/radioButton/radioButton-default-theme.css +39 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/radioButton/radioButton.css +66 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/radioButton/radioButton.js +302 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/sidenav/sidenav-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/sidenav/sidenav.css +86 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/sidenav/sidenav.js +320 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/slider/slider-default-theme.css +55 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/slider/slider.css +210 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/slider/slider.js +391 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/sticky/sticky.css +20 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/sticky/sticky.js +314 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/subheader/subheader-default-theme.css +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/subheader/subheader.css +62 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/subheader/subheader.js +89 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/swipe/swipe.js +79 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/switch/switch-default-theme.css +29 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/switch/switch.css +81 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/switch/switch.js +171 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tabs/tabs-default-theme.css +34 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tabs/tabs.css +171 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tabs/tabs.js +1009 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/textField/textField-default-theme.css +29 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/textField/textField.css +72 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/textField/textField.js +145 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toast/toast-default-theme.css +17 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toast/toast.css +110 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toast/toast.js +236 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toolbar/toolbar-default-theme.css +17 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toolbar/toolbar.css +69 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/toolbar/toolbar.js +161 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tooltip/tooltip-default-theme.css +10 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tooltip/tooltip.css +133 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/tooltip/tooltip.js +199 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/whiteframe/whiteframe.css +20 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/whiteframe/whiteframe.js +17 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/css/angular-material-layout.css +2582 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop.css +54 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop.js +38 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/backdrop.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/backdrop/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet-default-theme.css +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet.css +188 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet.js +293 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bottomSheet.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/bottomSheet/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button-default-theme.css +42 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button.css +132 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button.js +94 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/button/button.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card-default-theme.css +10 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card.css +31 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card.js +58 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/card/card.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox-default-theme.css +38 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox.css +79 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox.js +133 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/checkbox/checkbox.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content.css +24 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content.js +60 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/content/content.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/core.css +3067 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/core.js +2780 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/core.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/core.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/core/default-theme.js +1 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog-default-theme.css +11 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog.css +88 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog.js +495 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/dialog/dialog.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider.css +12 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider.js +48 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/divider/divider.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/icon/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/icon/icon.css +24 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/icon/icon.js +50 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/icon/icon.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/icon/icon.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input-default-theme.css +40 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input.css +102 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input.js +333 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/input/input.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/list/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/list/list.css +61 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/list/list.js +94 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/list/list.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/list/list.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/menu/bower.json +5 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/menu/menu.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/menu/menu.js +27 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/menu/menu.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/menu/menu.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular-default-theme.css +35 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular.css +1445 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular.js +127 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressCircular/progressCircular.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear-default-theme.css +28 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear.css +368 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear.js +128 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/progressLinear/progressLinear.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton-default-theme.css +39 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton.css +67 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton.js +296 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/radioButton/radioButton.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav-default-theme.css +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav.css +90 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav.js +302 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sidenav/sidenav.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider-default-theme.css +55 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider.css +218 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider.js +411 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/slider/slider.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sticky/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sticky/sticky.css +20 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sticky/sticky.js +309 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sticky/sticky.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/sticky/sticky.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader-default-theme.css +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader.css +61 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader.js +86 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/subheader/subheader.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/swipe/bower.json +5 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/swipe/swipe.js +213 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/swipe/swipe.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch-default-theme.css +29 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch.css +77 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch.js +144 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/switch/switch.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs-default-theme.css +34 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs.css +181 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs.js +992 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tabs/tabs.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField-default-theme.css +29 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField.css +76 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField.js +143 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/textField/textField.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/bower.json +9 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast-default-theme.css +17 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast.css +115 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast.js +235 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toast/toast.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/bower.json +8 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar-default-theme.css +17 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar.css +78 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar.js +158 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/toolbar/toolbar.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/bower.json +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip-default-theme.css +10 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip-default-theme.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip.css +136 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip.js +197 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/tooltip/tooltip.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/whiteframe/bower.json +5 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/whiteframe/whiteframe.css +20 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/whiteframe/whiteframe.js +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/whiteframe/whiteframe.min.css +6 -0
- data/app/assets/javascripts/swat/bower_components/angular-material/modules/js/whiteframe/whiteframe.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-resource/angular-resource.js +668 -0
- data/app/assets/javascripts/swat/bower_components/angular-resource/angular-resource.min.js +13 -0
- data/app/assets/javascripts/swat/bower_components/angular-resource/index.js +2 -0
- data/app/assets/javascripts/swat/bower_components/angular-route/angular-route.js +991 -0
- data/app/assets/javascripts/swat/bower_components/angular-route/angular-route.min.js +15 -0
- data/app/assets/javascripts/swat/bower_components/angular-route/index.js +2 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/LICENSE.txt +21 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/api/angular-ui-router.d.ts +126 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/release/angular-ui-router.js +4370 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/release/angular-ui-router.min.js +7 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/common.js +292 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/resolve.js +252 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/state.js +1465 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/stateDirectives.js +285 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/stateFilters.js +39 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/templateFactory.js +110 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/urlMatcherFactory.js +1050 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/urlRouter.js +427 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/view.js +71 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/viewDirective.js +303 -0
- data/app/assets/javascripts/swat/bower_components/angular-ui-router/src/viewScroll.js +52 -0
- data/app/assets/javascripts/swat/bower_components/lodash/lodash.js +12235 -0
- data/app/assets/javascripts/swat/bower_components/lodash/lodash.min.js +98 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/.editorconfig +10 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/.gitignore +3 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/Gruntfile.js +96 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/dest/ng-clip.min.js +2 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/example/bootstrap-tooltip.html +49 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/example/index.html +68 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/example/ng-repeat.html +44 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/npm-debug.log +145 -0
- data/app/assets/javascripts/swat/bower_components/ng-clip/src/ngClip.js +84 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/.jshintrc +70 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/ZeroClipboard.Core.js +2017 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/ZeroClipboard.Core.min.js +10 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/ZeroClipboard.js +2581 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/ZeroClipboard.min.js +10 -0
- data/app/assets/javascripts/swat/bower_components/zeroclipboard/dist/ZeroClipboard.swf +0 -0
- data/app/assets/javascripts/swat/bower_components.coffee +12 -0
- data/app/assets/stylesheets/swat/application.sass +59 -0
- data/app/assets/stylesheets/swat/default-theme.css +394 -0
- data/app/assets/stylesheets/swat/font-awesome.css +1801 -0
- data/app/assets/stylesheets/swat/fonts/FontAwesome.otf +0 -0
- data/app/assets/stylesheets/swat/fonts/fontawesome-webfont.eot +0 -0
- data/app/assets/stylesheets/swat/fonts/fontawesome-webfont.svg +565 -0
- data/app/assets/stylesheets/swat/fonts/fontawesome-webfont.ttf +0 -0
- data/app/assets/stylesheets/swat/fonts/fontawesome-webfont.woff +0 -0
- data/app/assets/stylesheets/swat/fonts/fontawesome-webfont.woff2 +0 -0
- data/app/assets/stylesheets/swat/swat_theme.sass +177 -0
- data/app/controllers/swat/api/revisions_controller.rb +27 -0
- data/app/controllers/swat/api/test_cases_controller.rb +20 -0
- data/app/controllers/swat/application_controller.rb +4 -0
- data/app/controllers/swat/info/states_controller.rb +12 -0
- data/app/controllers/swat/pages/base_pages_controller.rb +7 -0
- data/app/controllers/swat/pages/revisions_controller.rb +8 -0
- data/app/controllers/swat/revisions_controller.rb +4 -0
- data/app/helpers/swat/application_helper.rb +4 -0
- data/app/models/concerns/root_revision_ext.rb +14 -0
- data/app/models/full_revision.rb +88 -0
- data/app/models/revision.rb +84 -0
- data/app/models/revision_status_calculator.rb +98 -0
- data/app/models/test_case.rb +25 -0
- data/app/views/layouts/swat/application.slim +36 -0
- data/app/views/layouts/swat/page.slim +2 -0
- data/app/views/swat/application/index.slim +0 -0
- data/app/views/swat/pages/revisions/index.slim +25 -0
- data/app/views/swat/pages/revisions/show.slim +43 -0
- data/app/views/swat/shared/_footer.slim +5 -0
- data/app/views/swat/shared/_header.slim +9 -0
- data/bin/rails +12 -0
- data/config/routes.rb +38 -0
- data/fixtures/firebase_collection.rb +97 -0
- data/lib/sw2at-ui.rb +19 -0
- data/lib/swat/engine.rb +5 -0
- data/lib/swat/ui/config.rb +28 -0
- data/lib/swat/ui/rspec_commands.rb +191 -0
- data/lib/swat/ui/rspec_setup.rb +42 -0
- data/lib/swat/ui/stats_collector.rb +90 -0
- data/lib/swat/ui/version.rb +5 -0
- data/lib/tasks/swat_tasks.rake +36 -0
- data/spec/lib/commands_spec.rb +88 -0
- data/spec/models/calculator_spec.rb +130 -0
- data/spec/models/full_revision_spec.rb +263 -0
- data/spec/models/revision_spec.rb +59 -0
- data/spec/models/testcase_spec.rb +94 -0
- data/spec/spec_helper.rb +45 -0
- data/sw2at-ui.gemspec +465 -0
- data/test/helper.rb +34 -0
- data/test/test_sw2at-ui.rb +7 -0
- metadata +628 -0
data/app/assets/javascripts/swat/bower_components/angular-material/modules/closure/core/core.js
ADDED
|
@@ -0,0 +1,3090 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Angular Material Design
|
|
3
|
+
* https://github.com/angular/material
|
|
4
|
+
* @license MIT
|
|
5
|
+
* v0.7.1
|
|
6
|
+
*/
|
|
7
|
+
goog.provide('ng.material.core');
|
|
8
|
+
|
|
9
|
+
(function() {
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initialization function that validates environment
|
|
14
|
+
* requirements.
|
|
15
|
+
*/
|
|
16
|
+
angular
|
|
17
|
+
.module('material.core', ['material.core.theming'])
|
|
18
|
+
.config(MdCoreConfigure);
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function MdCoreConfigure($provide, $mdThemingProvider) {
|
|
22
|
+
$provide.decorator('$$rAF', ["$delegate", rAFDecorator]);
|
|
23
|
+
|
|
24
|
+
$mdThemingProvider.theme('default')
|
|
25
|
+
.primaryPalette('indigo')
|
|
26
|
+
.accentPalette('pink')
|
|
27
|
+
.warnPalette('red')
|
|
28
|
+
.backgroundPalette('grey');
|
|
29
|
+
}
|
|
30
|
+
MdCoreConfigure.$inject = ["$provide", "$mdThemingProvider"];
|
|
31
|
+
|
|
32
|
+
function rAFDecorator( $delegate ) {
|
|
33
|
+
/**
|
|
34
|
+
* Use this to throttle events that come in often.
|
|
35
|
+
* The throttled function will always use the *last* invocation before the
|
|
36
|
+
* coming frame.
|
|
37
|
+
*
|
|
38
|
+
* For example, window resize events that fire many times a second:
|
|
39
|
+
* If we set to use an raf-throttled callback on window resize, then
|
|
40
|
+
* our callback will only be fired once per frame, with the last resize
|
|
41
|
+
* event that happened before that frame.
|
|
42
|
+
*
|
|
43
|
+
* @param {function} callback function to debounce
|
|
44
|
+
*/
|
|
45
|
+
$delegate.throttle = function(cb) {
|
|
46
|
+
var queueArgs, alreadyQueued, queueCb, context;
|
|
47
|
+
return function debounced() {
|
|
48
|
+
queueArgs = arguments;
|
|
49
|
+
context = this;
|
|
50
|
+
queueCb = cb;
|
|
51
|
+
if (!alreadyQueued) {
|
|
52
|
+
alreadyQueued = true;
|
|
53
|
+
$delegate(function() {
|
|
54
|
+
queueCb.apply(context, queueArgs);
|
|
55
|
+
alreadyQueued = false;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
return $delegate;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
})();
|
|
64
|
+
|
|
65
|
+
(function() {
|
|
66
|
+
'use strict';
|
|
67
|
+
|
|
68
|
+
angular.module('material.core')
|
|
69
|
+
.factory('$mdConstant', MdConstantFactory);
|
|
70
|
+
|
|
71
|
+
function MdConstantFactory($$rAF, $sniffer) {
|
|
72
|
+
|
|
73
|
+
var webkit = /webkit/i.test($sniffer.vendorPrefix);
|
|
74
|
+
function vendorProperty(name) {
|
|
75
|
+
return webkit ? ('webkit' + name.charAt(0).toUpperCase() + name.substring(1)) : name;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
KEY_CODE: {
|
|
80
|
+
ENTER: 13,
|
|
81
|
+
ESCAPE: 27,
|
|
82
|
+
SPACE: 32,
|
|
83
|
+
LEFT_ARROW : 37,
|
|
84
|
+
UP_ARROW : 38,
|
|
85
|
+
RIGHT_ARROW : 39,
|
|
86
|
+
DOWN_ARROW : 40
|
|
87
|
+
},
|
|
88
|
+
CSS: {
|
|
89
|
+
/* Constants */
|
|
90
|
+
TRANSITIONEND: 'transitionend' + (webkit ? ' webkitTransitionEnd' : ''),
|
|
91
|
+
ANIMATIONEND: 'animationend' + (webkit ? ' webkitAnimationEnd' : ''),
|
|
92
|
+
|
|
93
|
+
TRANSFORM: vendorProperty('transform'),
|
|
94
|
+
TRANSITION: vendorProperty('transition'),
|
|
95
|
+
TRANSITION_DURATION: vendorProperty('transitionDuration'),
|
|
96
|
+
ANIMATION_PLAY_STATE: vendorProperty('animationPlayState'),
|
|
97
|
+
ANIMATION_DURATION: vendorProperty('animationDuration'),
|
|
98
|
+
ANIMATION_NAME: vendorProperty('animationName'),
|
|
99
|
+
ANIMATION_TIMING: vendorProperty('animationTimingFunction'),
|
|
100
|
+
ANIMATION_DIRECTION: vendorProperty('animationDirection')
|
|
101
|
+
},
|
|
102
|
+
MEDIA: {
|
|
103
|
+
'sm': '(max-width: 600px)',
|
|
104
|
+
'gt-sm': '(min-width: 600px)',
|
|
105
|
+
'md': '(min-width: 600px) and (max-width: 960px)',
|
|
106
|
+
'gt-md': '(min-width: 960px)',
|
|
107
|
+
'lg': '(min-width: 960px) and (max-width: 1200px)',
|
|
108
|
+
'gt-lg': '(min-width: 1200px)'
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
MdConstantFactory.$inject = ["$$rAF", "$sniffer"];
|
|
113
|
+
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
(function(){
|
|
117
|
+
|
|
118
|
+
angular
|
|
119
|
+
.module('material.core')
|
|
120
|
+
.config( ["$provide", function($provide){
|
|
121
|
+
$provide.decorator('$mdUtil', ['$delegate', function ($delegate){
|
|
122
|
+
/**
|
|
123
|
+
* Inject the iterator facade to easily support iteration and accessors
|
|
124
|
+
* @see iterator below
|
|
125
|
+
*/
|
|
126
|
+
$delegate.iterator = Iterator;
|
|
127
|
+
|
|
128
|
+
return $delegate;
|
|
129
|
+
}
|
|
130
|
+
]);
|
|
131
|
+
}]);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* iterator is a list facade to easily support iteration and accessors
|
|
135
|
+
*
|
|
136
|
+
* @param items Array list which this iterator will enumerate
|
|
137
|
+
* @param reloop Boolean enables iterator to consider the list as an endless reloop
|
|
138
|
+
*/
|
|
139
|
+
function Iterator(items, reloop) {
|
|
140
|
+
var trueFn = function() { return true; };
|
|
141
|
+
|
|
142
|
+
reloop = !!reloop;
|
|
143
|
+
var _items = items || [ ];
|
|
144
|
+
|
|
145
|
+
// Published API
|
|
146
|
+
return {
|
|
147
|
+
items: getItems,
|
|
148
|
+
count: count,
|
|
149
|
+
|
|
150
|
+
inRange: inRange,
|
|
151
|
+
contains: contains,
|
|
152
|
+
indexOf: indexOf,
|
|
153
|
+
itemAt: itemAt,
|
|
154
|
+
|
|
155
|
+
findBy: findBy,
|
|
156
|
+
|
|
157
|
+
add: add,
|
|
158
|
+
remove: remove,
|
|
159
|
+
|
|
160
|
+
first: first,
|
|
161
|
+
last: last,
|
|
162
|
+
next: angular.bind(null, findSubsequentItem, false),
|
|
163
|
+
previous: angular.bind(null, findSubsequentItem, true),
|
|
164
|
+
|
|
165
|
+
hasPrevious: hasPrevious,
|
|
166
|
+
hasNext: hasNext
|
|
167
|
+
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Publish copy of the enumerable set
|
|
172
|
+
* @returns {Array|*}
|
|
173
|
+
*/
|
|
174
|
+
function getItems() {
|
|
175
|
+
return [].concat(_items);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Determine length of the list
|
|
180
|
+
* @returns {Array.length|*|number}
|
|
181
|
+
*/
|
|
182
|
+
function count() {
|
|
183
|
+
return _items.length;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Is the index specified valid
|
|
188
|
+
* @param index
|
|
189
|
+
* @returns {Array.length|*|number|boolean}
|
|
190
|
+
*/
|
|
191
|
+
function inRange(index) {
|
|
192
|
+
return _items.length && ( index > -1 ) && (index < _items.length );
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Can the iterator proceed to the next item in the list; relative to
|
|
197
|
+
* the specified item.
|
|
198
|
+
*
|
|
199
|
+
* @param item
|
|
200
|
+
* @returns {Array.length|*|number|boolean}
|
|
201
|
+
*/
|
|
202
|
+
function hasNext(item) {
|
|
203
|
+
return item ? inRange(indexOf(item) + 1) : false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Can the iterator proceed to the previous item in the list; relative to
|
|
208
|
+
* the specified item.
|
|
209
|
+
*
|
|
210
|
+
* @param item
|
|
211
|
+
* @returns {Array.length|*|number|boolean}
|
|
212
|
+
*/
|
|
213
|
+
function hasPrevious(item) {
|
|
214
|
+
return item ? inRange(indexOf(item) - 1) : false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get item at specified index/position
|
|
219
|
+
* @param index
|
|
220
|
+
* @returns {*}
|
|
221
|
+
*/
|
|
222
|
+
function itemAt(index) {
|
|
223
|
+
return inRange(index) ? _items[index] : null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Find all elements matching the key/value pair
|
|
228
|
+
* otherwise return null
|
|
229
|
+
*
|
|
230
|
+
* @param val
|
|
231
|
+
* @param key
|
|
232
|
+
*
|
|
233
|
+
* @return array
|
|
234
|
+
*/
|
|
235
|
+
function findBy(key, val) {
|
|
236
|
+
return _items.filter(function(item) {
|
|
237
|
+
return item[key] === val;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Add item to list
|
|
243
|
+
* @param item
|
|
244
|
+
* @param index
|
|
245
|
+
* @returns {*}
|
|
246
|
+
*/
|
|
247
|
+
function add(item, index) {
|
|
248
|
+
if ( !item ) return -1;
|
|
249
|
+
|
|
250
|
+
if (!angular.isNumber(index)) {
|
|
251
|
+
index = _items.length;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
_items.splice(index, 0, item);
|
|
255
|
+
|
|
256
|
+
return indexOf(item);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Remove item from list...
|
|
261
|
+
* @param item
|
|
262
|
+
*/
|
|
263
|
+
function remove(item) {
|
|
264
|
+
if ( contains(item) ){
|
|
265
|
+
_items.splice(indexOf(item), 1);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Get the zero-based index of the target item
|
|
271
|
+
* @param item
|
|
272
|
+
* @returns {*}
|
|
273
|
+
*/
|
|
274
|
+
function indexOf(item) {
|
|
275
|
+
return _items.indexOf(item);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Boolean existence check
|
|
280
|
+
* @param item
|
|
281
|
+
* @returns {boolean}
|
|
282
|
+
*/
|
|
283
|
+
function contains(item) {
|
|
284
|
+
return item && (indexOf(item) > -1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Return first item in the list
|
|
289
|
+
* @returns {*}
|
|
290
|
+
*/
|
|
291
|
+
function first() {
|
|
292
|
+
return _items.length ? _items[0] : null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Return last item in the list...
|
|
297
|
+
* @returns {*}
|
|
298
|
+
*/
|
|
299
|
+
function last() {
|
|
300
|
+
return _items.length ? _items[_items.length - 1] : null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Find the next item. If reloop is true and at the end of the list, it will
|
|
305
|
+
* go back to the first item. If given ,the `validate` callback will be used
|
|
306
|
+
* determine whether the next item is valid. If not valid, it will try to find the
|
|
307
|
+
* next item again.
|
|
308
|
+
* @param item
|
|
309
|
+
* @param {optional} validate Validate function
|
|
310
|
+
* @param {optional} limit Recursion limit
|
|
311
|
+
* @returns {*}
|
|
312
|
+
*/
|
|
313
|
+
function findSubsequentItem(backwards, item, validate, limit) {
|
|
314
|
+
validate = validate || trueFn;
|
|
315
|
+
|
|
316
|
+
var curIndex = indexOf(item);
|
|
317
|
+
if (!inRange(curIndex)) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
var nextIndex = curIndex + (backwards ? -1 : 1);
|
|
322
|
+
var foundItem = null;
|
|
323
|
+
if (inRange(nextIndex)) {
|
|
324
|
+
foundItem = _items[nextIndex];
|
|
325
|
+
} else if (reloop) {
|
|
326
|
+
foundItem = backwards ? last() : first();
|
|
327
|
+
nextIndex = indexOf(foundItem);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if ((foundItem === null) || (nextIndex === limit)) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (angular.isUndefined(limit)) {
|
|
335
|
+
limit = nextIndex;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return validate(foundItem) ? foundItem : findSubsequentItem(backwards, foundItem, validate, limit);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
})();
|
|
343
|
+
|
|
344
|
+
angular.module('material.core')
|
|
345
|
+
.factory('$mdMedia', mdMediaFactory);
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Exposes a function on the '$mdMedia' service which will return true or false,
|
|
349
|
+
* whether the given media query matches. Re-evaluates on resize. Allows presets
|
|
350
|
+
* for 'sm', 'md', 'lg'.
|
|
351
|
+
*
|
|
352
|
+
* @example $mdMedia('sm') == true if device-width <= sm
|
|
353
|
+
* @example $mdMedia('(min-width: 1200px)') == true if device-width >= 1200px
|
|
354
|
+
* @example $mdMedia('max-width: 300px') == true if device-width <= 300px (sanitizes input, adding parens)
|
|
355
|
+
*/
|
|
356
|
+
function mdMediaFactory($mdConstant, $rootScope, $window) {
|
|
357
|
+
var queries = {};
|
|
358
|
+
var results = {};
|
|
359
|
+
|
|
360
|
+
return $mdMedia;
|
|
361
|
+
|
|
362
|
+
function $mdMedia(query) {
|
|
363
|
+
var validated = queries[query];
|
|
364
|
+
if (angular.isUndefined(validated)) {
|
|
365
|
+
validated = queries[query] = validate(query);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
var result = results[validated];
|
|
369
|
+
if (angular.isUndefined(result)) {
|
|
370
|
+
result = add(validated);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function validate(query) {
|
|
377
|
+
return $mdConstant.MEDIA[query] ||
|
|
378
|
+
((query.charAt(0) !== '(') ? ('(' + query + ')') : query);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function add(query) {
|
|
382
|
+
var result = $window.matchMedia(query);
|
|
383
|
+
result.addListener(onQueryChange);
|
|
384
|
+
return (results[result.media] = !!result.matches);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function onQueryChange() {
|
|
388
|
+
var query = this;
|
|
389
|
+
$rootScope.$evalAsync(function() {
|
|
390
|
+
results[query.media] = !!query.matches;
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
}
|
|
395
|
+
mdMediaFactory.$inject = ["$mdConstant", "$rootScope", "$window"];
|
|
396
|
+
|
|
397
|
+
(function() {
|
|
398
|
+
'use strict';
|
|
399
|
+
|
|
400
|
+
/*
|
|
401
|
+
* This var has to be outside the angular factory, otherwise when
|
|
402
|
+
* there are multiple material apps on the same page, each app
|
|
403
|
+
* will create its own instance of this array and the app's IDs
|
|
404
|
+
* will not be unique.
|
|
405
|
+
*/
|
|
406
|
+
var nextUniqueId = ['0','0','0'];
|
|
407
|
+
|
|
408
|
+
angular.module('material.core')
|
|
409
|
+
.factory('$mdUtil', ["$document", "$timeout", function($document, $timeout) {
|
|
410
|
+
var Util;
|
|
411
|
+
|
|
412
|
+
return Util = {
|
|
413
|
+
now: window.performance ? angular.bind(window.performance, window.performance.now) : Date.now,
|
|
414
|
+
|
|
415
|
+
elementRect: function(element, offsetParent) {
|
|
416
|
+
var node = element[0];
|
|
417
|
+
offsetParent = offsetParent || node.offsetParent || document.body;
|
|
418
|
+
offsetParent = offsetParent[0] || offsetParent;
|
|
419
|
+
var nodeRect = node.getBoundingClientRect();
|
|
420
|
+
var parentRect = offsetParent.getBoundingClientRect();
|
|
421
|
+
return {
|
|
422
|
+
left: nodeRect.left - parentRect.left + offsetParent.scrollLeft,
|
|
423
|
+
top: nodeRect.top - parentRect.top + offsetParent.scrollTop,
|
|
424
|
+
width: nodeRect.width,
|
|
425
|
+
height: nodeRect.height
|
|
426
|
+
};
|
|
427
|
+
},
|
|
428
|
+
|
|
429
|
+
fakeNgModel: function() {
|
|
430
|
+
return {
|
|
431
|
+
$fake: true,
|
|
432
|
+
$setViewValue: function(value) {
|
|
433
|
+
this.$viewValue = value;
|
|
434
|
+
this.$render(value);
|
|
435
|
+
this.$viewChangeListeners.forEach(function(cb) { cb(); });
|
|
436
|
+
},
|
|
437
|
+
$isEmpty: function(value) {
|
|
438
|
+
return (''+value).length === 0;
|
|
439
|
+
},
|
|
440
|
+
$parsers: [],
|
|
441
|
+
$formatters: [],
|
|
442
|
+
$viewChangeListeners: [],
|
|
443
|
+
$render: angular.noop
|
|
444
|
+
};
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
// Returns a function, that, as long as it continues to be invoked, will not
|
|
448
|
+
// be triggered. The function will be called after it stops being called for
|
|
449
|
+
// N milliseconds.
|
|
450
|
+
// @param wait Integer value of msecs to delay (since last debounce reset); default value 10 msecs
|
|
451
|
+
// @param invokeApply should the $timeout trigger $digest() dirty checking
|
|
452
|
+
debounce: function (func, wait, scope, invokeApply) {
|
|
453
|
+
var timer;
|
|
454
|
+
|
|
455
|
+
return function debounced() {
|
|
456
|
+
var context = scope,
|
|
457
|
+
args = Array.prototype.slice.call(arguments);
|
|
458
|
+
|
|
459
|
+
$timeout.cancel(timer);
|
|
460
|
+
timer = $timeout(function() {
|
|
461
|
+
|
|
462
|
+
timer = undefined;
|
|
463
|
+
func.apply(context, args);
|
|
464
|
+
|
|
465
|
+
}, wait || 10, invokeApply );
|
|
466
|
+
};
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
// Returns a function that can only be triggered every `delay` milliseconds.
|
|
470
|
+
// In other words, the function will not be called unless it has been more
|
|
471
|
+
// than `delay` milliseconds since the last call.
|
|
472
|
+
throttle: function throttle(func, delay) {
|
|
473
|
+
var recent;
|
|
474
|
+
return function throttled() {
|
|
475
|
+
var context = this;
|
|
476
|
+
var args = arguments;
|
|
477
|
+
var now = Util.now();
|
|
478
|
+
|
|
479
|
+
if (!recent || (now - recent > delay)) {
|
|
480
|
+
func.apply(context, args);
|
|
481
|
+
recent = now;
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* nextUid, from angular.js.
|
|
488
|
+
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
|
489
|
+
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
|
490
|
+
* the number string gets longer over time, and it can also overflow, where as the nextId
|
|
491
|
+
* will grow much slower, it is a string, and it will never overflow.
|
|
492
|
+
*
|
|
493
|
+
* @returns an unique alpha-numeric string
|
|
494
|
+
*/
|
|
495
|
+
nextUid: function() {
|
|
496
|
+
var index = nextUniqueId.length;
|
|
497
|
+
var digit;
|
|
498
|
+
|
|
499
|
+
while(index) {
|
|
500
|
+
index--;
|
|
501
|
+
digit = nextUniqueId[index].charCodeAt(0);
|
|
502
|
+
if (digit == 57 /*'9'*/) {
|
|
503
|
+
nextUniqueId[index] = 'A';
|
|
504
|
+
return nextUniqueId.join('');
|
|
505
|
+
}
|
|
506
|
+
if (digit == 90 /*'Z'*/) {
|
|
507
|
+
nextUniqueId[index] = '0';
|
|
508
|
+
} else {
|
|
509
|
+
nextUniqueId[index] = String.fromCharCode(digit + 1);
|
|
510
|
+
return nextUniqueId.join('');
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
nextUniqueId.unshift('0');
|
|
514
|
+
return nextUniqueId.join('');
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
// Stop watchers and events from firing on a scope without destroying it,
|
|
518
|
+
// by disconnecting it from its parent and its siblings' linked lists.
|
|
519
|
+
disconnectScope: function disconnectScope(scope) {
|
|
520
|
+
if (!scope) return;
|
|
521
|
+
|
|
522
|
+
// we can't destroy the root scope or a scope that has been already destroyed
|
|
523
|
+
if (scope.$root === scope) return;
|
|
524
|
+
if (scope.$$destroyed ) return;
|
|
525
|
+
|
|
526
|
+
var parent = scope.$parent;
|
|
527
|
+
scope.$$disconnected = true;
|
|
528
|
+
|
|
529
|
+
// See Scope.$destroy
|
|
530
|
+
if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling;
|
|
531
|
+
if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling;
|
|
532
|
+
if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling;
|
|
533
|
+
if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling;
|
|
534
|
+
|
|
535
|
+
scope.$$nextSibling = scope.$$prevSibling = null;
|
|
536
|
+
|
|
537
|
+
},
|
|
538
|
+
|
|
539
|
+
// Undo the effects of disconnectScope above.
|
|
540
|
+
reconnectScope: function reconnectScope(scope) {
|
|
541
|
+
if (!scope) return;
|
|
542
|
+
|
|
543
|
+
// we can't disconnect the root node or scope already disconnected
|
|
544
|
+
if (scope.$root === scope) return;
|
|
545
|
+
if (!scope.$$disconnected) return;
|
|
546
|
+
|
|
547
|
+
var child = scope;
|
|
548
|
+
|
|
549
|
+
var parent = child.$parent;
|
|
550
|
+
child.$$disconnected = false;
|
|
551
|
+
// See Scope.$new for this logic...
|
|
552
|
+
child.$$prevSibling = parent.$$childTail;
|
|
553
|
+
if (parent.$$childHead) {
|
|
554
|
+
parent.$$childTail.$$nextSibling = child;
|
|
555
|
+
parent.$$childTail = child;
|
|
556
|
+
} else {
|
|
557
|
+
parent.$$childHead = parent.$$childTail = child;
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
/*
|
|
561
|
+
* getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching nodeName
|
|
562
|
+
*
|
|
563
|
+
* @param el Element to start walking the DOM from
|
|
564
|
+
* @param tagName Tag name to find closest to el, such as 'form'
|
|
565
|
+
*/
|
|
566
|
+
getClosest: function getClosest(el, tagName) {
|
|
567
|
+
tagName = tagName.toUpperCase();
|
|
568
|
+
do {
|
|
569
|
+
if (el.nodeName === tagName) {
|
|
570
|
+
return el;
|
|
571
|
+
}
|
|
572
|
+
} while (el = el.parentNode);
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
}]);
|
|
578
|
+
|
|
579
|
+
/*
|
|
580
|
+
* Since removing jQuery from the demos, some code that uses `element.focus()` is broken.
|
|
581
|
+
*
|
|
582
|
+
* We need to add `element.focus()`, because it's testable unlike `element[0].focus`.
|
|
583
|
+
*
|
|
584
|
+
* TODO(ajoslin): This should be added in a better place later.
|
|
585
|
+
*/
|
|
586
|
+
|
|
587
|
+
angular.element.prototype.focus = angular.element.prototype.focus || function() {
|
|
588
|
+
if (this.length) {
|
|
589
|
+
this[0].focus();
|
|
590
|
+
}
|
|
591
|
+
return this;
|
|
592
|
+
};
|
|
593
|
+
angular.element.prototype.blur = angular.element.prototype.blur || function() {
|
|
594
|
+
if (this.length) {
|
|
595
|
+
this[0].blur();
|
|
596
|
+
}
|
|
597
|
+
return this;
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
})();
|
|
601
|
+
|
|
602
|
+
(function() {
|
|
603
|
+
'use strict';
|
|
604
|
+
|
|
605
|
+
angular.module('material.core')
|
|
606
|
+
.service('$mdAria', AriaService);
|
|
607
|
+
|
|
608
|
+
function AriaService($$rAF, $log, $window) {
|
|
609
|
+
|
|
610
|
+
return {
|
|
611
|
+
expect: expect,
|
|
612
|
+
expectAsync: expectAsync,
|
|
613
|
+
expectWithText: expectWithText
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Check if expected attribute has been specified on the target element or child
|
|
618
|
+
* @param element
|
|
619
|
+
* @param attrName
|
|
620
|
+
* @param {optional} defaultValue What to set the attr to if no value is found
|
|
621
|
+
*/
|
|
622
|
+
function expect(element, attrName, defaultValue) {
|
|
623
|
+
var node = element[0];
|
|
624
|
+
|
|
625
|
+
if (!node.hasAttribute(attrName) && !childHasAttribute(node, attrName)) {
|
|
626
|
+
|
|
627
|
+
defaultValue = angular.isString(defaultValue) && defaultValue.trim() || '';
|
|
628
|
+
if (defaultValue.length) {
|
|
629
|
+
element.attr(attrName, defaultValue);
|
|
630
|
+
} else {
|
|
631
|
+
$log.warn('ARIA: Attribute "', attrName, '", required for accessibility, is missing on node:', node);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function expectAsync(element, attrName, defaultValueGetter) {
|
|
638
|
+
// Problem: when retrieving the element's contents synchronously to find the label,
|
|
639
|
+
// the text may not be defined yet in the case of a binding.
|
|
640
|
+
// There is a higher chance that a binding will be defined if we wait one frame.
|
|
641
|
+
$$rAF(function() {
|
|
642
|
+
expect(element, attrName, defaultValueGetter());
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function expectWithText(element, attrName) {
|
|
647
|
+
expectAsync(element, attrName, function() {
|
|
648
|
+
return element.text().trim();
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function childHasAttribute(node, attrName) {
|
|
653
|
+
var hasChildren = node.hasChildNodes(),
|
|
654
|
+
hasAttr = false;
|
|
655
|
+
|
|
656
|
+
function isHidden(el) {
|
|
657
|
+
var style = el.currentStyle ? el.currentStyle : $window.getComputedStyle(el);
|
|
658
|
+
return (style.display === 'none');
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if(hasChildren) {
|
|
662
|
+
var children = node.childNodes;
|
|
663
|
+
for(var i=0; i<children.length; i++){
|
|
664
|
+
var child = children[i];
|
|
665
|
+
if(child.nodeType === 1 && child.hasAttribute(attrName)) {
|
|
666
|
+
if(!isHidden(child)){
|
|
667
|
+
hasAttr = true;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return hasAttr;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
AriaService.$inject = ["$$rAF", "$log", "$window"];
|
|
676
|
+
})();
|
|
677
|
+
|
|
678
|
+
(function() {
|
|
679
|
+
'use strict';
|
|
680
|
+
|
|
681
|
+
angular.module('material.core')
|
|
682
|
+
.service('$mdCompiler', mdCompilerService);
|
|
683
|
+
|
|
684
|
+
function mdCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {
|
|
685
|
+
/* jshint validthis: true */
|
|
686
|
+
|
|
687
|
+
/*
|
|
688
|
+
* @ngdoc service
|
|
689
|
+
* @name $mdCompiler
|
|
690
|
+
* @module material.core
|
|
691
|
+
* @description
|
|
692
|
+
* The $mdCompiler service is an abstraction of angular's compiler, that allows the developer
|
|
693
|
+
* to easily compile an element with a templateUrl, controller, and locals.
|
|
694
|
+
*
|
|
695
|
+
* @usage
|
|
696
|
+
* <hljs lang="js">
|
|
697
|
+
* $mdCompiler.compile({
|
|
698
|
+
* templateUrl: 'modal.html',
|
|
699
|
+
* controller: 'ModalCtrl',
|
|
700
|
+
* locals: {
|
|
701
|
+
* modal: myModalInstance;
|
|
702
|
+
* }
|
|
703
|
+
* }).then(function(compileData) {
|
|
704
|
+
* compileData.element; // modal.html's template in an element
|
|
705
|
+
* compileData.link(myScope); //attach controller & scope to element
|
|
706
|
+
* });
|
|
707
|
+
* </hljs>
|
|
708
|
+
*/
|
|
709
|
+
|
|
710
|
+
/*
|
|
711
|
+
* @ngdoc method
|
|
712
|
+
* @name $mdCompiler#compile
|
|
713
|
+
* @description A helper to compile an HTML template/templateUrl with a given controller,
|
|
714
|
+
* locals, and scope.
|
|
715
|
+
* @param {object} options An options object, with the following properties:
|
|
716
|
+
*
|
|
717
|
+
* - `controller` - `{(string=|function()=}` Controller fn that should be associated with
|
|
718
|
+
* newly created scope or the name of a registered controller if passed as a string.
|
|
719
|
+
* - `controllerAs` - `{string=}` A controller alias name. If present the controller will be
|
|
720
|
+
* published to scope under the `controllerAs` name.
|
|
721
|
+
* - `template` - `{string=}` An html template as a string.
|
|
722
|
+
* - `templateUrl` - `{string=}` A path to an html template.
|
|
723
|
+
* - `transformTemplate` - `{function(template)=}` A function which transforms the template after
|
|
724
|
+
* it is loaded. It will be given the template string as a parameter, and should
|
|
725
|
+
* return a a new string representing the transformed template.
|
|
726
|
+
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
|
727
|
+
* be injected into the controller. If any of these dependencies are promises, the compiler
|
|
728
|
+
* will wait for them all to be resolved, or if one is rejected before the controller is
|
|
729
|
+
* instantiated `compile()` will fail..
|
|
730
|
+
* * `key` - `{string}`: a name of a dependency to be injected into the controller.
|
|
731
|
+
* * `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
|
732
|
+
* Otherwise if function, then it is injected and the return value is treated as the
|
|
733
|
+
* dependency. If the result is a promise, it is resolved before its value is
|
|
734
|
+
* injected into the controller.
|
|
735
|
+
*
|
|
736
|
+
* @returns {object=} promise A promise, which will be resolved with a `compileData` object.
|
|
737
|
+
* `compileData` has the following properties:
|
|
738
|
+
*
|
|
739
|
+
* - `element` - `{element}`: an uncompiled element matching the provided template.
|
|
740
|
+
* - `link` - `{function(scope)}`: A link function, which, when called, will compile
|
|
741
|
+
* the element and instantiate the provided controller (if given).
|
|
742
|
+
* - `locals` - `{object}`: The locals which will be passed into the controller once `link` is
|
|
743
|
+
* called. If `bindToController` is true, they will be coppied to the ctrl instead
|
|
744
|
+
* - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in
|
|
745
|
+
*/
|
|
746
|
+
this.compile = function(options) {
|
|
747
|
+
var templateUrl = options.templateUrl;
|
|
748
|
+
var template = options.template || '';
|
|
749
|
+
var controller = options.controller;
|
|
750
|
+
var controllerAs = options.controllerAs;
|
|
751
|
+
var resolve = options.resolve || {};
|
|
752
|
+
var locals = options.locals || {};
|
|
753
|
+
var transformTemplate = options.transformTemplate || angular.identity;
|
|
754
|
+
var bindToController = options.bindToController;
|
|
755
|
+
|
|
756
|
+
// Take resolve values and invoke them.
|
|
757
|
+
// Resolves can either be a string (value: 'MyRegisteredAngularConst'),
|
|
758
|
+
// or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})
|
|
759
|
+
angular.forEach(resolve, function(value, key) {
|
|
760
|
+
if (angular.isString(value)) {
|
|
761
|
+
resolve[key] = $injector.get(value);
|
|
762
|
+
} else {
|
|
763
|
+
resolve[key] = $injector.invoke(value);
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
//Add the locals, which are just straight values to inject
|
|
767
|
+
//eg locals: { three: 3 }, will inject three into the controller
|
|
768
|
+
angular.extend(resolve, locals);
|
|
769
|
+
|
|
770
|
+
if (templateUrl) {
|
|
771
|
+
resolve.$template = $http.get(templateUrl, {cache: $templateCache})
|
|
772
|
+
.then(function(response) {
|
|
773
|
+
return response.data;
|
|
774
|
+
});
|
|
775
|
+
} else {
|
|
776
|
+
resolve.$template = $q.when(template);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Wait for all the resolves to finish if they are promises
|
|
780
|
+
return $q.all(resolve).then(function(locals) {
|
|
781
|
+
|
|
782
|
+
var template = transformTemplate(locals.$template);
|
|
783
|
+
var element = angular.element('<div>').html(template.trim()).contents();
|
|
784
|
+
var linkFn = $compile(element);
|
|
785
|
+
|
|
786
|
+
//Return a linking function that can be used later when the element is ready
|
|
787
|
+
return {
|
|
788
|
+
locals: locals,
|
|
789
|
+
element: element,
|
|
790
|
+
link: function link(scope) {
|
|
791
|
+
locals.$scope = scope;
|
|
792
|
+
|
|
793
|
+
//Instantiate controller if it exists, because we have scope
|
|
794
|
+
if (controller) {
|
|
795
|
+
var ctrl = $controller(controller, locals);
|
|
796
|
+
if (bindToController) {
|
|
797
|
+
angular.extend(ctrl, locals);
|
|
798
|
+
}
|
|
799
|
+
//See angular-route source for this logic
|
|
800
|
+
element.data('$ngControllerController', ctrl);
|
|
801
|
+
element.children().data('$ngControllerController', ctrl);
|
|
802
|
+
|
|
803
|
+
if (controllerAs) {
|
|
804
|
+
scope[controllerAs] = ctrl;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return linkFn(scope);
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
mdCompilerService.$inject = ["$q", "$http", "$injector", "$compile", "$controller", "$templateCache"];
|
|
816
|
+
})();
|
|
817
|
+
|
|
818
|
+
(function() {
|
|
819
|
+
'use strict';
|
|
820
|
+
|
|
821
|
+
/*
|
|
822
|
+
* TODO: Add support for multiple fingers on the `pointer` object (enables pinch gesture)
|
|
823
|
+
*/
|
|
824
|
+
|
|
825
|
+
var START_EVENTS = 'mousedown touchstart pointerdown';
|
|
826
|
+
var MOVE_EVENTS = 'mousemove touchmove pointermove';
|
|
827
|
+
var END_EVENTS = 'mouseup mouseleave touchend touchcancel pointerup pointercancel';
|
|
828
|
+
var HANDLERS;
|
|
829
|
+
|
|
830
|
+
document.contains || (document.contains = function(node) {
|
|
831
|
+
return document.body.contains(node);
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
// TODO add windows phone to this
|
|
835
|
+
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
836
|
+
var isIos = userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i);
|
|
837
|
+
var isAndroid = userAgent.match(/Android/i);
|
|
838
|
+
var shouldHijackClicks = isIos || isAndroid;
|
|
839
|
+
|
|
840
|
+
if (shouldHijackClicks) {
|
|
841
|
+
document.addEventListener('click', function(ev) {
|
|
842
|
+
// Space/enter on a button, and submit events, can send clicks
|
|
843
|
+
var isKeyClick = ev.clientX === 0 && ev.clientY === 0;
|
|
844
|
+
if (isKeyClick || ev.$material) return;
|
|
845
|
+
|
|
846
|
+
// Prevent clicks unless they're sent by material
|
|
847
|
+
ev.preventDefault();
|
|
848
|
+
ev.stopPropagation();
|
|
849
|
+
}, true);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
angular.element(document)
|
|
853
|
+
.on(START_EVENTS, gestureStart)
|
|
854
|
+
.on(MOVE_EVENTS, gestureMove)
|
|
855
|
+
.on(END_EVENTS, gestureEnd)
|
|
856
|
+
// For testing
|
|
857
|
+
.on('$$mdGestureReset', function() {
|
|
858
|
+
lastPointer = pointer = null;
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// The state of the current and previous 'pointer' (user's hand)
|
|
862
|
+
var pointer, lastPointer;
|
|
863
|
+
|
|
864
|
+
function runHandlers(handlerEvent, event) {
|
|
865
|
+
var handler;
|
|
866
|
+
for (var handlerName in HANDLERS) {
|
|
867
|
+
handler = HANDLERS[handlerName];
|
|
868
|
+
if (handlerEvent === 'start') {
|
|
869
|
+
// Run cancel to reset any handlers' state
|
|
870
|
+
handler.cancel();
|
|
871
|
+
}
|
|
872
|
+
handler[handlerEvent](event, pointer);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
function gestureStart(ev) {
|
|
877
|
+
// If we're already touched down, abort
|
|
878
|
+
if (pointer) return;
|
|
879
|
+
|
|
880
|
+
var now = +Date.now();
|
|
881
|
+
|
|
882
|
+
// iOS & old android bug: after a touch event, a click event is sent 350 ms later.
|
|
883
|
+
// If <400ms have passed, don't allow an event of a different type than the previous event
|
|
884
|
+
if (lastPointer && !typesMatch(ev, lastPointer) && (now - lastPointer.endTime < 1500)) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
pointer = makeStartPointer(ev);
|
|
889
|
+
|
|
890
|
+
runHandlers('start', ev);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function gestureMove(ev) {
|
|
894
|
+
if (!pointer || !typesMatch(ev, pointer)) return;
|
|
895
|
+
|
|
896
|
+
updatePointerState(ev, pointer);
|
|
897
|
+
runHandlers('move', ev);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function gestureEnd(ev) {
|
|
901
|
+
if (!pointer || !typesMatch(ev, pointer)) return;
|
|
902
|
+
|
|
903
|
+
updatePointerState(ev, pointer);
|
|
904
|
+
pointer.endTime = +Date.now();
|
|
905
|
+
|
|
906
|
+
runHandlers('end', ev);
|
|
907
|
+
|
|
908
|
+
lastPointer = pointer;
|
|
909
|
+
pointer = null;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/******** Helpers *********/
|
|
913
|
+
function typesMatch(ev, pointer) {
|
|
914
|
+
return ev && pointer && ev.type.charAt(0) === pointer.type;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function getEventPoint(ev) {
|
|
918
|
+
ev = ev.originalEvent || ev; // support jQuery events
|
|
919
|
+
return (ev.touches && ev.touches[0]) ||
|
|
920
|
+
(ev.changedTouches && ev.changedTouches[0]) ||
|
|
921
|
+
ev;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function updatePointerState(ev, pointer) {
|
|
925
|
+
var point = getEventPoint(ev);
|
|
926
|
+
var x = pointer.x = point.pageX;
|
|
927
|
+
var y = pointer.y = point.pageY;
|
|
928
|
+
|
|
929
|
+
pointer.distanceX = x - pointer.startX;
|
|
930
|
+
pointer.distanceY = y - pointer.startY;
|
|
931
|
+
pointer.distance = Math.sqrt(
|
|
932
|
+
pointer.distanceX * pointer.distanceX + pointer.distanceY * pointer.distanceY
|
|
933
|
+
);
|
|
934
|
+
|
|
935
|
+
pointer.directionX = pointer.distanceX > 0 ? 'right' : pointer.distanceX < 0 ? 'left' : '';
|
|
936
|
+
pointer.directionY = pointer.distanceY > 0 ? 'up' : pointer.distanceY < 0 ? 'down' : '';
|
|
937
|
+
|
|
938
|
+
pointer.duration = +Date.now() - pointer.startTime;
|
|
939
|
+
pointer.velocityX = pointer.distanceX / pointer.duration;
|
|
940
|
+
pointer.velocityY = pointer.distanceY / pointer.duration;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
function makeStartPointer(ev) {
|
|
945
|
+
var point = getEventPoint(ev);
|
|
946
|
+
var startPointer = {
|
|
947
|
+
startTime: +Date.now(),
|
|
948
|
+
target: ev.target,
|
|
949
|
+
// 'p' for pointer, 'm' for mouse, 't' for touch
|
|
950
|
+
type: ev.type.charAt(0)
|
|
951
|
+
};
|
|
952
|
+
startPointer.startX = startPointer.x = point.pageX;
|
|
953
|
+
startPointer.startY = startPointer.y = point.pageY;
|
|
954
|
+
return startPointer;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
angular.module('material.core')
|
|
958
|
+
.run(["$mdGesture", function($mdGesture) {}]) // make sure $mdGesture is always instantiated
|
|
959
|
+
.factory('$mdGesture', ["$$MdGestureHandler", "$$rAF", "$timeout", function($$MdGestureHandler, $$rAF, $timeout) {
|
|
960
|
+
HANDLERS = {};
|
|
961
|
+
|
|
962
|
+
if (shouldHijackClicks) {
|
|
963
|
+
addHandler('click', {
|
|
964
|
+
options: {
|
|
965
|
+
maxDistance: 6
|
|
966
|
+
},
|
|
967
|
+
onEnd: function(ev, pointer) {
|
|
968
|
+
if (pointer.distance < this.state.options.maxDistance) {
|
|
969
|
+
this.dispatchEvent(ev, 'click', null, ev);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
addHandler('press', {
|
|
976
|
+
onStart: function(ev, pointer) {
|
|
977
|
+
this.dispatchEvent(ev, '$md.pressdown');
|
|
978
|
+
},
|
|
979
|
+
onEnd: function(ev, pointer) {
|
|
980
|
+
this.dispatchEvent(ev, '$md.pressup');
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
addHandler('hold', {
|
|
986
|
+
options: {
|
|
987
|
+
// If the user keeps his finger within the same <maxDistance> area for
|
|
988
|
+
// <delay> ms, dispatch a hold event.
|
|
989
|
+
maxDistance: 6,
|
|
990
|
+
delay: 500,
|
|
991
|
+
},
|
|
992
|
+
onCancel: function() {
|
|
993
|
+
$timeout.cancel(this.state.timeout);
|
|
994
|
+
},
|
|
995
|
+
onStart: function(ev, pointer) {
|
|
996
|
+
// For hold, require a parent to be registered with $mdGesture.register()
|
|
997
|
+
// Because we prevent scroll events, this is necessary.
|
|
998
|
+
if (!this.state.registeredParent) return this.cancel();
|
|
999
|
+
|
|
1000
|
+
this.state.pos = {x: pointer.x, y: pointer.y};
|
|
1001
|
+
this.state.timeout = $timeout(angular.bind(this, function holdDelayFn() {
|
|
1002
|
+
this.dispatchEvent(ev, '$md.hold');
|
|
1003
|
+
this.cancel(); //we're done!
|
|
1004
|
+
}), this.state.options.delay, false);
|
|
1005
|
+
},
|
|
1006
|
+
onMove: function(ev, pointer) {
|
|
1007
|
+
// Don't scroll while waiting for hold
|
|
1008
|
+
ev.preventDefault();
|
|
1009
|
+
var dx = this.state.pos.x - pointer.x;
|
|
1010
|
+
var dy = this.state.pos.y - pointer.y;
|
|
1011
|
+
if (Math.sqrt(dx*dx + dy*dy) > this.options.maxDistance) {
|
|
1012
|
+
this.cancel();
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
onEnd: function(ev, pointer) {
|
|
1016
|
+
this.onCancel();
|
|
1017
|
+
},
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
addHandler('drag', {
|
|
1021
|
+
options: {
|
|
1022
|
+
minDistance: 6,
|
|
1023
|
+
horizontal: true,
|
|
1024
|
+
},
|
|
1025
|
+
onStart: function(ev) {
|
|
1026
|
+
// For drag, require a parent to be registered with $mdGesture.register()
|
|
1027
|
+
if (!this.state.registeredParent) this.cancel();
|
|
1028
|
+
},
|
|
1029
|
+
onMove: function(ev, pointer) {
|
|
1030
|
+
var shouldStartDrag, shouldCancel;
|
|
1031
|
+
// Don't allow touch events to scroll while we're dragging or
|
|
1032
|
+
// deciding if this touchmove is a proper drag
|
|
1033
|
+
ev.preventDefault();
|
|
1034
|
+
|
|
1035
|
+
if (!this.state.dragPointer) {
|
|
1036
|
+
if (this.state.options.horizontal) {
|
|
1037
|
+
shouldStartDrag = Math.abs(pointer.distanceX) > this.state.options.minDistance;
|
|
1038
|
+
shouldCancel = Math.abs(pointer.distanceY) > this.state.options.minDistance * 1.5;
|
|
1039
|
+
} else {
|
|
1040
|
+
shouldStartDrag = Math.abs(pointer.distanceY) > this.state.options.minDistance;
|
|
1041
|
+
shouldCancel = Math.abs(pointer.distanceX) > this.state.options.minDistance * 1.5;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (shouldStartDrag) {
|
|
1045
|
+
// Create a new pointer, starting at this point where the drag started.
|
|
1046
|
+
this.state.dragPointer = makeStartPointer(ev);
|
|
1047
|
+
updatePointerState(ev, this.state.dragPointer);
|
|
1048
|
+
this.dispatchEvent(ev, '$md.dragstart', this.state.dragPointer);
|
|
1049
|
+
|
|
1050
|
+
} else if (shouldCancel) {
|
|
1051
|
+
this.cancel();
|
|
1052
|
+
}
|
|
1053
|
+
} else {
|
|
1054
|
+
this.dispatchDragMove(ev);
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
// Only dispatch these every frame; any more is unnecessray
|
|
1058
|
+
dispatchDragMove: $$rAF.throttle(function(ev) {
|
|
1059
|
+
// Make sure the drag didn't stop while waiting for the next frame
|
|
1060
|
+
if (this.state.isRunning) {
|
|
1061
|
+
updatePointerState(ev, this.state.dragPointer);
|
|
1062
|
+
this.dispatchEvent(ev, '$md.drag', this.state.dragPointer);
|
|
1063
|
+
}
|
|
1064
|
+
}),
|
|
1065
|
+
onEnd: function(ev, pointer) {
|
|
1066
|
+
if (this.state.dragPointer) {
|
|
1067
|
+
updatePointerState(ev, this.state.dragPointer);
|
|
1068
|
+
this.dispatchEvent(ev, '$md.dragend', this.state.dragPointer);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
addHandler('swipe', {
|
|
1074
|
+
options: {
|
|
1075
|
+
minVelocity: 0.65,
|
|
1076
|
+
minDistance: 10,
|
|
1077
|
+
},
|
|
1078
|
+
onEnd: function(ev, pointer) {
|
|
1079
|
+
if (Math.abs(pointer.velocityX) > this.state.options.minVelocity &&
|
|
1080
|
+
Math.abs(pointer.distanceX) > this.state.options.minDistance) {
|
|
1081
|
+
var eventType = pointer.directionX == 'left' ? '$md.swipeleft' : '$md.swiperight';
|
|
1082
|
+
this.dispatchEvent(ev, eventType);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
var self;
|
|
1088
|
+
return self = {
|
|
1089
|
+
handler: addHandler,
|
|
1090
|
+
register: register
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
function addHandler(name, definition) {
|
|
1094
|
+
var handler = new $$MdGestureHandler(name);
|
|
1095
|
+
angular.extend(handler, definition);
|
|
1096
|
+
HANDLERS[name] = handler;
|
|
1097
|
+
return self;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function register(element, handlerName, options) {
|
|
1101
|
+
var handler = HANDLERS[ handlerName.replace(/^\$md./, '') ];
|
|
1102
|
+
if (!handler) {
|
|
1103
|
+
throw new Error('Failed to register element with handler ' + handlerName + '. ' +
|
|
1104
|
+
'Available handlers: ' + Object.keys(HANDLERS).join(', '));
|
|
1105
|
+
}
|
|
1106
|
+
return handler.registerElement(element, options);
|
|
1107
|
+
}
|
|
1108
|
+
}])
|
|
1109
|
+
.factory('$$MdGestureHandler', ["$$rAF", function($$rAF) {
|
|
1110
|
+
|
|
1111
|
+
function GestureHandler(name) {
|
|
1112
|
+
this.name = name;
|
|
1113
|
+
this.state = {};
|
|
1114
|
+
}
|
|
1115
|
+
GestureHandler.prototype = {
|
|
1116
|
+
onStart: angular.noop,
|
|
1117
|
+
onMove: angular.noop,
|
|
1118
|
+
onEnd: angular.noop,
|
|
1119
|
+
onCancel: angular.noop,
|
|
1120
|
+
options: {},
|
|
1121
|
+
|
|
1122
|
+
dispatchEvent: dispatchEvent,
|
|
1123
|
+
|
|
1124
|
+
start: function(ev, pointer) {
|
|
1125
|
+
if (this.state.isRunning) return;
|
|
1126
|
+
var parentTarget = this.getNearestParent(ev.target);
|
|
1127
|
+
var parentTargetOptions = parentTarget && parentTarget.$mdGesture[this.name] || {};
|
|
1128
|
+
|
|
1129
|
+
this.state = {
|
|
1130
|
+
isRunning: true,
|
|
1131
|
+
options: angular.extend({}, this.options, parentTargetOptions),
|
|
1132
|
+
registeredParent: parentTarget
|
|
1133
|
+
};
|
|
1134
|
+
this.onStart(ev, pointer);
|
|
1135
|
+
},
|
|
1136
|
+
move: function(ev, pointer) {
|
|
1137
|
+
if (!this.state.isRunning) return;
|
|
1138
|
+
this.onMove(ev, pointer);
|
|
1139
|
+
},
|
|
1140
|
+
end: function(ev, pointer) {
|
|
1141
|
+
if (!this.state.isRunning) return;
|
|
1142
|
+
this.onEnd(ev, pointer);
|
|
1143
|
+
this.state.isRunning = false;
|
|
1144
|
+
},
|
|
1145
|
+
cancel: function(ev, pointer) {
|
|
1146
|
+
this.onCancel(ev, pointer);
|
|
1147
|
+
this.state = {};
|
|
1148
|
+
},
|
|
1149
|
+
|
|
1150
|
+
// Find and return the nearest parent element that has been registered via
|
|
1151
|
+
// $mdGesture.register(element, 'handlerName').
|
|
1152
|
+
getNearestParent: function(node) {
|
|
1153
|
+
var current = node;
|
|
1154
|
+
while (current) {
|
|
1155
|
+
if ( (current.$mdGesture || {})[this.name] ) {
|
|
1156
|
+
return current;
|
|
1157
|
+
}
|
|
1158
|
+
current = current.parentNode;
|
|
1159
|
+
}
|
|
1160
|
+
},
|
|
1161
|
+
|
|
1162
|
+
registerElement: function(element, options) {
|
|
1163
|
+
var self = this;
|
|
1164
|
+
element[0].$mdGesture = element[0].$mdGesture || {};
|
|
1165
|
+
element[0].$mdGesture[this.name] = options || {};
|
|
1166
|
+
element.on('$destroy', onDestroy);
|
|
1167
|
+
|
|
1168
|
+
return onDestroy;
|
|
1169
|
+
|
|
1170
|
+
function onDestroy() {
|
|
1171
|
+
delete element[0].$mdGesture[self.name];
|
|
1172
|
+
element.off('$destroy', onDestroy);
|
|
1173
|
+
}
|
|
1174
|
+
},
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
var customEventOptions = {
|
|
1178
|
+
bubbles: true,
|
|
1179
|
+
cancelable: true
|
|
1180
|
+
};
|
|
1181
|
+
/*
|
|
1182
|
+
* NOTE: dispatchEvent is very performance sensitive.
|
|
1183
|
+
*/
|
|
1184
|
+
function dispatchEvent(srcEvent, eventType, eventPointer, /*original DOMEvent */ev) {
|
|
1185
|
+
eventPointer = eventPointer || pointer;
|
|
1186
|
+
var eventObj;
|
|
1187
|
+
|
|
1188
|
+
if (eventType === 'click') {
|
|
1189
|
+
eventObj = document.createEvent('MouseEvents');
|
|
1190
|
+
eventObj.initMouseEvent(
|
|
1191
|
+
'click', true, true, window, ev.detail,
|
|
1192
|
+
ev.screenX, ev.screenY, ev.clientX, ev.clientY,
|
|
1193
|
+
ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
|
|
1194
|
+
ev.button, ev.relatedTarget || null
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
} else {
|
|
1198
|
+
eventObj = document.createEvent('CustomEvent');
|
|
1199
|
+
eventObj.initCustomEvent(eventType, true, true, {});
|
|
1200
|
+
}
|
|
1201
|
+
eventObj.$material = true;
|
|
1202
|
+
eventObj.pointer = eventPointer;
|
|
1203
|
+
eventObj.srcEvent = srcEvent;
|
|
1204
|
+
eventPointer.target.dispatchEvent(eventObj);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
return GestureHandler;
|
|
1208
|
+
}]);
|
|
1209
|
+
|
|
1210
|
+
})();
|
|
1211
|
+
|
|
1212
|
+
(function() {
|
|
1213
|
+
'use strict';
|
|
1214
|
+
|
|
1215
|
+
angular.module('material.core')
|
|
1216
|
+
.provider('$$interimElement', InterimElementProvider);
|
|
1217
|
+
|
|
1218
|
+
/*
|
|
1219
|
+
* @ngdoc service
|
|
1220
|
+
* @name $$interimElement
|
|
1221
|
+
* @module material.core
|
|
1222
|
+
*
|
|
1223
|
+
* @description
|
|
1224
|
+
*
|
|
1225
|
+
* Factory that contructs `$$interimElement.$service` services.
|
|
1226
|
+
* Used internally in material design for elements that appear on screen temporarily.
|
|
1227
|
+
* The service provides a promise-like API for interacting with the temporary
|
|
1228
|
+
* elements.
|
|
1229
|
+
*
|
|
1230
|
+
* ```js
|
|
1231
|
+
* app.service('$mdToast', function($$interimElement) {
|
|
1232
|
+
* var $mdToast = $$interimElement(toastDefaultOptions);
|
|
1233
|
+
* return $mdToast;
|
|
1234
|
+
* });
|
|
1235
|
+
* ```
|
|
1236
|
+
* @param {object=} defaultOptions Options used by default for the `show` method on the service.
|
|
1237
|
+
*
|
|
1238
|
+
* @returns {$$interimElement.$service}
|
|
1239
|
+
*
|
|
1240
|
+
*/
|
|
1241
|
+
|
|
1242
|
+
function InterimElementProvider() {
|
|
1243
|
+
createInterimElementProvider.$get = InterimElementFactory;
|
|
1244
|
+
InterimElementFactory.$inject = ["$document", "$q", "$rootScope", "$timeout", "$rootElement", "$animate", "$interpolate", "$mdCompiler", "$mdTheming"];
|
|
1245
|
+
return createInterimElementProvider;
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Returns a new provider which allows configuration of a new interimElement
|
|
1249
|
+
* service. Allows configuration of default options & methods for options,
|
|
1250
|
+
* as well as configuration of 'preset' methods (eg dialog.basic(): basic is a preset method)
|
|
1251
|
+
*/
|
|
1252
|
+
function createInterimElementProvider(interimFactoryName) {
|
|
1253
|
+
var EXPOSED_METHODS = ['onHide', 'onShow', 'onRemove'];
|
|
1254
|
+
var providerConfig = {
|
|
1255
|
+
presets: {}
|
|
1256
|
+
};
|
|
1257
|
+
var provider = {
|
|
1258
|
+
setDefaults: setDefaults,
|
|
1259
|
+
addPreset: addPreset,
|
|
1260
|
+
$get: factory
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* all interim elements will come with the 'build' preset
|
|
1265
|
+
*/
|
|
1266
|
+
provider.addPreset('build', {
|
|
1267
|
+
methods: ['controller', 'controllerAs', 'resolve',
|
|
1268
|
+
'template', 'templateUrl', 'themable', 'transformTemplate', 'parent']
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
factory.$inject = ["$$interimElement", "$animate", "$injector"];
|
|
1272
|
+
return provider;
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* Save the configured defaults to be used when the factory is instantiated
|
|
1276
|
+
*/
|
|
1277
|
+
function setDefaults(definition) {
|
|
1278
|
+
providerConfig.optionsFactory = definition.options;
|
|
1279
|
+
providerConfig.methods = (definition.methods || []).concat(EXPOSED_METHODS);
|
|
1280
|
+
return provider;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Save the configured preset to be used when the factory is instantiated
|
|
1285
|
+
*/
|
|
1286
|
+
function addPreset(name, definition) {
|
|
1287
|
+
definition = definition || {};
|
|
1288
|
+
definition.methods = definition.methods || [];
|
|
1289
|
+
definition.options = definition.options || function() { return {}; };
|
|
1290
|
+
|
|
1291
|
+
if (/^cancel|hide|show$/.test(name)) {
|
|
1292
|
+
throw new Error("Preset '" + name + "' in " + interimFactoryName + " is reserved!");
|
|
1293
|
+
}
|
|
1294
|
+
if (definition.methods.indexOf('_options') > -1) {
|
|
1295
|
+
throw new Error("Method '_options' in " + interimFactoryName + " is reserved!");
|
|
1296
|
+
}
|
|
1297
|
+
providerConfig.presets[name] = {
|
|
1298
|
+
methods: definition.methods.concat(EXPOSED_METHODS),
|
|
1299
|
+
optionsFactory: definition.options,
|
|
1300
|
+
argOption: definition.argOption
|
|
1301
|
+
};
|
|
1302
|
+
return provider;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* Create a factory that has the given methods & defaults implementing interimElement
|
|
1307
|
+
*/
|
|
1308
|
+
/* @ngInject */
|
|
1309
|
+
function factory($$interimElement, $animate, $injector) {
|
|
1310
|
+
var defaultMethods;
|
|
1311
|
+
var defaultOptions;
|
|
1312
|
+
var interimElementService = $$interimElement();
|
|
1313
|
+
|
|
1314
|
+
/*
|
|
1315
|
+
* publicService is what the developer will be using.
|
|
1316
|
+
* It has methods hide(), cancel(), show(), build(), and any other
|
|
1317
|
+
* presets which were set during the config phase.
|
|
1318
|
+
*/
|
|
1319
|
+
var publicService = {
|
|
1320
|
+
hide: interimElementService.hide,
|
|
1321
|
+
cancel: interimElementService.cancel,
|
|
1322
|
+
show: showInterimElement
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
defaultMethods = providerConfig.methods || [];
|
|
1326
|
+
// This must be invoked after the publicService is initialized
|
|
1327
|
+
defaultOptions = invokeFactory(providerConfig.optionsFactory, {});
|
|
1328
|
+
|
|
1329
|
+
angular.forEach(providerConfig.presets, function(definition, name) {
|
|
1330
|
+
var presetDefaults = invokeFactory(definition.optionsFactory, {});
|
|
1331
|
+
var presetMethods = (definition.methods || []).concat(defaultMethods);
|
|
1332
|
+
|
|
1333
|
+
// Every interimElement built with a preset has a field called `$type`,
|
|
1334
|
+
// which matches the name of the preset.
|
|
1335
|
+
// Eg in preset 'confirm', options.$type === 'confirm'
|
|
1336
|
+
angular.extend(presetDefaults, { $type: name });
|
|
1337
|
+
|
|
1338
|
+
// This creates a preset class which has setter methods for every
|
|
1339
|
+
// method given in the `.addPreset()` function, as well as every
|
|
1340
|
+
// method given in the `.setDefaults()` function.
|
|
1341
|
+
//
|
|
1342
|
+
// @example
|
|
1343
|
+
// .setDefaults({
|
|
1344
|
+
// methods: ['hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent'],
|
|
1345
|
+
// options: dialogDefaultOptions
|
|
1346
|
+
// })
|
|
1347
|
+
// .addPreset('alert', {
|
|
1348
|
+
// methods: ['title', 'ok'],
|
|
1349
|
+
// options: alertDialogOptions
|
|
1350
|
+
// })
|
|
1351
|
+
//
|
|
1352
|
+
// Set values will be passed to the options when interimElemnt.show() is called.
|
|
1353
|
+
function Preset(opts) {
|
|
1354
|
+
this._options = angular.extend({}, presetDefaults, opts);
|
|
1355
|
+
}
|
|
1356
|
+
angular.forEach(presetMethods, function(name) {
|
|
1357
|
+
Preset.prototype[name] = function(value) {
|
|
1358
|
+
this._options[name] = value;
|
|
1359
|
+
return this;
|
|
1360
|
+
};
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
// Create shortcut method for one-linear methods
|
|
1364
|
+
if (definition.argOption) {
|
|
1365
|
+
var methodName = 'show' + name.charAt(0).toUpperCase() + name.slice(1);
|
|
1366
|
+
publicService[methodName] = function(arg) {
|
|
1367
|
+
var config = publicService[name](arg);
|
|
1368
|
+
return publicService.show(config);
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// eg $mdDialog.alert() will return a new alert preset
|
|
1373
|
+
publicService[name] = function(arg) {
|
|
1374
|
+
// If argOption is supplied, eg `argOption: 'content'`, then we assume
|
|
1375
|
+
// if the argument is not an options object then it is the `argOption` option.
|
|
1376
|
+
//
|
|
1377
|
+
// @example `$mdToast.simple('hello')` // sets options.content to hello
|
|
1378
|
+
// // because argOption === 'content'
|
|
1379
|
+
if (arguments.length && definition.argOption && !angular.isObject(arg) &&
|
|
1380
|
+
!angular.isArray(arg)) {
|
|
1381
|
+
return (new Preset())[definition.argOption](arg);
|
|
1382
|
+
} else {
|
|
1383
|
+
return new Preset(arg);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
};
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
return publicService;
|
|
1390
|
+
|
|
1391
|
+
function showInterimElement(opts) {
|
|
1392
|
+
// opts is either a preset which stores its options on an _options field,
|
|
1393
|
+
// or just an object made up of options
|
|
1394
|
+
if (opts && opts._options) opts = opts._options;
|
|
1395
|
+
return interimElementService.show(
|
|
1396
|
+
angular.extend({}, defaultOptions, opts)
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* Helper to call $injector.invoke with a local of the factory name for
|
|
1402
|
+
* this provider.
|
|
1403
|
+
* If an $mdDialog is providing options for a dialog and tries to inject
|
|
1404
|
+
* $mdDialog, a circular dependency error will happen.
|
|
1405
|
+
* We get around that by manually injecting $mdDialog as a local.
|
|
1406
|
+
*/
|
|
1407
|
+
function invokeFactory(factory, defaultVal) {
|
|
1408
|
+
var locals = {};
|
|
1409
|
+
locals[interimFactoryName] = publicService;
|
|
1410
|
+
return $injector.invoke(factory || function() { return defaultVal; }, {}, locals);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/* @ngInject */
|
|
1418
|
+
function InterimElementFactory($document, $q, $rootScope, $timeout, $rootElement, $animate,
|
|
1419
|
+
$interpolate, $mdCompiler, $mdTheming ) {
|
|
1420
|
+
var startSymbol = $interpolate.startSymbol(),
|
|
1421
|
+
endSymbol = $interpolate.endSymbol(),
|
|
1422
|
+
usesStandardSymbols = ((startSymbol === '{{') && (endSymbol === '}}')),
|
|
1423
|
+
processTemplate = usesStandardSymbols ? angular.identity : replaceInterpolationSymbols;
|
|
1424
|
+
|
|
1425
|
+
return function createInterimElementService() {
|
|
1426
|
+
/*
|
|
1427
|
+
* @ngdoc service
|
|
1428
|
+
* @name $$interimElement.$service
|
|
1429
|
+
*
|
|
1430
|
+
* @description
|
|
1431
|
+
* A service used to control inserting and removing an element into the DOM.
|
|
1432
|
+
*
|
|
1433
|
+
*/
|
|
1434
|
+
var stack = [];
|
|
1435
|
+
var service;
|
|
1436
|
+
return service = {
|
|
1437
|
+
show: show,
|
|
1438
|
+
hide: hide,
|
|
1439
|
+
cancel: cancel
|
|
1440
|
+
};
|
|
1441
|
+
|
|
1442
|
+
/*
|
|
1443
|
+
* @ngdoc method
|
|
1444
|
+
* @name $$interimElement.$service#show
|
|
1445
|
+
* @kind function
|
|
1446
|
+
*
|
|
1447
|
+
* @description
|
|
1448
|
+
* Adds the `$interimElement` to the DOM and returns a promise that will be resolved or rejected
|
|
1449
|
+
* with hide or cancel, respectively.
|
|
1450
|
+
*
|
|
1451
|
+
* @param {*} options is hashMap of settings
|
|
1452
|
+
* @returns a Promise
|
|
1453
|
+
*
|
|
1454
|
+
*/
|
|
1455
|
+
function show(options) {
|
|
1456
|
+
if (stack.length) {
|
|
1457
|
+
service.cancel();
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
var interimElement = new InterimElement(options);
|
|
1461
|
+
|
|
1462
|
+
stack.push(interimElement);
|
|
1463
|
+
return interimElement.show().then(function() {
|
|
1464
|
+
return interimElement.deferred.promise;
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/*
|
|
1469
|
+
* @ngdoc method
|
|
1470
|
+
* @name $$interimElement.$service#hide
|
|
1471
|
+
* @kind function
|
|
1472
|
+
*
|
|
1473
|
+
* @description
|
|
1474
|
+
* Removes the `$interimElement` from the DOM and resolves the promise returned from `show`
|
|
1475
|
+
*
|
|
1476
|
+
* @param {*} resolveParam Data to resolve the promise with
|
|
1477
|
+
* @returns a Promise that will be resolved after the element has been removed.
|
|
1478
|
+
*
|
|
1479
|
+
*/
|
|
1480
|
+
function hide(response) {
|
|
1481
|
+
var interimElement = stack.shift();
|
|
1482
|
+
interimElement && interimElement.remove().then(function() {
|
|
1483
|
+
interimElement.deferred.resolve(response);
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
return interimElement ? interimElement.deferred.promise : $q.when(response);
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
/*
|
|
1490
|
+
* @ngdoc method
|
|
1491
|
+
* @name $$interimElement.$service#cancel
|
|
1492
|
+
* @kind function
|
|
1493
|
+
*
|
|
1494
|
+
* @description
|
|
1495
|
+
* Removes the `$interimElement` from the DOM and rejects the promise returned from `show`
|
|
1496
|
+
*
|
|
1497
|
+
* @param {*} reason Data to reject the promise with
|
|
1498
|
+
* @returns Promise that will be rejected after the element has been removed.
|
|
1499
|
+
*
|
|
1500
|
+
*/
|
|
1501
|
+
function cancel(reason) {
|
|
1502
|
+
var interimElement = stack.shift();
|
|
1503
|
+
interimElement && interimElement.remove().then(function() {
|
|
1504
|
+
interimElement.deferred.reject(reason);
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
return interimElement ? interimElement.deferred.promise : $q.reject(reason);
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
/*
|
|
1512
|
+
* Internal Interim Element Object
|
|
1513
|
+
* Used internally to manage the DOM element and related data
|
|
1514
|
+
*/
|
|
1515
|
+
function InterimElement(options) {
|
|
1516
|
+
var self;
|
|
1517
|
+
var hideTimeout, element;
|
|
1518
|
+
|
|
1519
|
+
options = options || {};
|
|
1520
|
+
options = angular.extend({
|
|
1521
|
+
scope: options.scope || $rootScope.$new(options.isolateScope),
|
|
1522
|
+
onShow: function(scope, element, options) {
|
|
1523
|
+
return $animate.enter(element, options.parent);
|
|
1524
|
+
},
|
|
1525
|
+
onRemove: function(scope, element, options) {
|
|
1526
|
+
// Element could be undefined if a new element is shown before
|
|
1527
|
+
// the old one finishes compiling.
|
|
1528
|
+
return element && $animate.leave(element) || $q.when();
|
|
1529
|
+
}
|
|
1530
|
+
}, options);
|
|
1531
|
+
|
|
1532
|
+
if (options.template) {
|
|
1533
|
+
options.template = processTemplate(options.template);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
return self = {
|
|
1537
|
+
options: options,
|
|
1538
|
+
deferred: $q.defer(),
|
|
1539
|
+
show: function() {
|
|
1540
|
+
return $mdCompiler.compile(options).then(function(compileData) {
|
|
1541
|
+
angular.extend(compileData.locals, self.options);
|
|
1542
|
+
|
|
1543
|
+
// Search for parent at insertion time, if not specified
|
|
1544
|
+
if (angular.isString(options.parent)) {
|
|
1545
|
+
options.parent = angular.element($document[0].querySelector(options.parent));
|
|
1546
|
+
} else if (!options.parent) {
|
|
1547
|
+
options.parent = $rootElement.find('body');
|
|
1548
|
+
if (!options.parent.length) options.parent = $rootElement;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
element = compileData.link(options.scope);
|
|
1552
|
+
if (options.themable) $mdTheming(element);
|
|
1553
|
+
var ret = options.onShow(options.scope, element, options);
|
|
1554
|
+
return $q.when(ret)
|
|
1555
|
+
.then(function(){
|
|
1556
|
+
// Issue onComplete callback when the `show()` finishes
|
|
1557
|
+
(options.onComplete || angular.noop)(options.scope, element, options);
|
|
1558
|
+
startHideTimeout();
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
function startHideTimeout() {
|
|
1562
|
+
if (options.hideDelay) {
|
|
1563
|
+
hideTimeout = $timeout(service.cancel, options.hideDelay) ;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
},
|
|
1568
|
+
cancelTimeout: function() {
|
|
1569
|
+
if (hideTimeout) {
|
|
1570
|
+
$timeout.cancel(hideTimeout);
|
|
1571
|
+
hideTimeout = undefined;
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1574
|
+
remove: function() {
|
|
1575
|
+
self.cancelTimeout();
|
|
1576
|
+
var ret = options.onRemove(options.scope, element, options);
|
|
1577
|
+
return $q.when(ret).then(function() {
|
|
1578
|
+
options.scope.$destroy();
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
/*
|
|
1586
|
+
* Replace `{{` and `}}` in a string (usually a template) with the actual start-/endSymbols used
|
|
1587
|
+
* for interpolation. This allows pre-defined templates (for components such as dialog, toast etc)
|
|
1588
|
+
* to continue to work in apps that use custom interpolation start-/endSymbols.
|
|
1589
|
+
*
|
|
1590
|
+
* @param {string} text The text in which to replace `{{` / `}}`
|
|
1591
|
+
* @returns {string} The modified string using the actual interpolation start-/endSymbols
|
|
1592
|
+
*/
|
|
1593
|
+
function replaceInterpolationSymbols(text) {
|
|
1594
|
+
if (!text || !angular.isString(text)) return text;
|
|
1595
|
+
return text.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
})();
|
|
1602
|
+
|
|
1603
|
+
(function() {
|
|
1604
|
+
'use strict';
|
|
1605
|
+
|
|
1606
|
+
/**
|
|
1607
|
+
* @ngdoc module
|
|
1608
|
+
* @name material.core.componentRegistry
|
|
1609
|
+
*
|
|
1610
|
+
* @description
|
|
1611
|
+
* A component instance registration service.
|
|
1612
|
+
* Note: currently this as a private service in the SideNav component.
|
|
1613
|
+
*/
|
|
1614
|
+
angular.module('material.core')
|
|
1615
|
+
.factory('$mdComponentRegistry', ComponentRegistry);
|
|
1616
|
+
|
|
1617
|
+
/*
|
|
1618
|
+
* @private
|
|
1619
|
+
* @ngdoc factory
|
|
1620
|
+
* @name ComponentRegistry
|
|
1621
|
+
* @module material.core.componentRegistry
|
|
1622
|
+
*
|
|
1623
|
+
*/
|
|
1624
|
+
function ComponentRegistry($log, $q) {
|
|
1625
|
+
|
|
1626
|
+
var self;
|
|
1627
|
+
var instances = [ ];
|
|
1628
|
+
var pendings = { };
|
|
1629
|
+
|
|
1630
|
+
return self = {
|
|
1631
|
+
/**
|
|
1632
|
+
* Used to print an error when an instance for a handle isn't found.
|
|
1633
|
+
*/
|
|
1634
|
+
notFoundError: function(handle) {
|
|
1635
|
+
$log.error('No instance found for handle', handle);
|
|
1636
|
+
},
|
|
1637
|
+
/**
|
|
1638
|
+
* Return all registered instances as an array.
|
|
1639
|
+
*/
|
|
1640
|
+
getInstances: function() {
|
|
1641
|
+
return instances;
|
|
1642
|
+
},
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Get a registered instance.
|
|
1646
|
+
* @param handle the String handle to look up for a registered instance.
|
|
1647
|
+
*/
|
|
1648
|
+
get: function(handle) {
|
|
1649
|
+
if ( !isValidID(handle) ) return null;
|
|
1650
|
+
|
|
1651
|
+
var i, j, instance;
|
|
1652
|
+
for(i = 0, j = instances.length; i < j; i++) {
|
|
1653
|
+
instance = instances[i];
|
|
1654
|
+
if(instance.$$mdHandle === handle) {
|
|
1655
|
+
return instance;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
return null;
|
|
1659
|
+
},
|
|
1660
|
+
|
|
1661
|
+
/**
|
|
1662
|
+
* Register an instance.
|
|
1663
|
+
* @param instance the instance to register
|
|
1664
|
+
* @param handle the handle to identify the instance under.
|
|
1665
|
+
*/
|
|
1666
|
+
register: function(instance, handle) {
|
|
1667
|
+
if ( !handle ) return angular.noop;
|
|
1668
|
+
|
|
1669
|
+
instance.$$mdHandle = handle;
|
|
1670
|
+
instances.push(instance);
|
|
1671
|
+
resolveWhen();
|
|
1672
|
+
|
|
1673
|
+
return deregister;
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* Remove registration for an instance
|
|
1677
|
+
*/
|
|
1678
|
+
function deregister() {
|
|
1679
|
+
var index = instances.indexOf(instance);
|
|
1680
|
+
if (index !== -1) {
|
|
1681
|
+
instances.splice(index, 1);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* Resolve any pending promises for this instance
|
|
1687
|
+
*/
|
|
1688
|
+
function resolveWhen() {
|
|
1689
|
+
var dfd = pendings[handle];
|
|
1690
|
+
if ( dfd ) {
|
|
1691
|
+
dfd.resolve( instance );
|
|
1692
|
+
delete pendings[handle];
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
},
|
|
1696
|
+
|
|
1697
|
+
/**
|
|
1698
|
+
* Async accessor to registered component instance
|
|
1699
|
+
* If not available then a promise is created to notify
|
|
1700
|
+
* all listeners when the instance is registered.
|
|
1701
|
+
*/
|
|
1702
|
+
when : function(handle) {
|
|
1703
|
+
if ( isValidID(handle) ) {
|
|
1704
|
+
var deferred = $q.defer();
|
|
1705
|
+
var instance = self.get(handle);
|
|
1706
|
+
|
|
1707
|
+
if ( instance ) {
|
|
1708
|
+
deferred.resolve( instance );
|
|
1709
|
+
} else {
|
|
1710
|
+
pendings[handle] = deferred;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
return deferred.promise;
|
|
1714
|
+
}
|
|
1715
|
+
return $q.reject("Invalid `md-component-id` value.");
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
};
|
|
1719
|
+
|
|
1720
|
+
function isValidID(handle){
|
|
1721
|
+
return handle && (handle !== "");
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
}
|
|
1725
|
+
ComponentRegistry.$inject = ["$log", "$q"];
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
})();
|
|
1729
|
+
|
|
1730
|
+
(function() {
|
|
1731
|
+
'use strict';
|
|
1732
|
+
|
|
1733
|
+
angular.module('material.core')
|
|
1734
|
+
.factory('$mdInkRipple', InkRippleService)
|
|
1735
|
+
.directive('mdInkRipple', InkRippleDirective)
|
|
1736
|
+
.directive('mdNoInk', attrNoDirective())
|
|
1737
|
+
.directive('mdNoBar', attrNoDirective())
|
|
1738
|
+
.directive('mdNoStretch', attrNoDirective());
|
|
1739
|
+
|
|
1740
|
+
function InkRippleDirective($mdInkRipple) {
|
|
1741
|
+
return {
|
|
1742
|
+
controller: angular.noop,
|
|
1743
|
+
link: function (scope, element, attr) {
|
|
1744
|
+
if (attr.hasOwnProperty('mdInkRippleCheckbox')) {
|
|
1745
|
+
$mdInkRipple.attachCheckboxBehavior(scope, element);
|
|
1746
|
+
} else {
|
|
1747
|
+
$mdInkRipple.attachButtonBehavior(scope, element);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
InkRippleDirective.$inject = ["$mdInkRipple"];
|
|
1753
|
+
|
|
1754
|
+
function InkRippleService($window, $timeout) {
|
|
1755
|
+
|
|
1756
|
+
return {
|
|
1757
|
+
attachButtonBehavior: attachButtonBehavior,
|
|
1758
|
+
attachCheckboxBehavior: attachCheckboxBehavior,
|
|
1759
|
+
attachTabBehavior: attachTabBehavior,
|
|
1760
|
+
attach: attach
|
|
1761
|
+
};
|
|
1762
|
+
|
|
1763
|
+
function attachButtonBehavior(scope, element, options) {
|
|
1764
|
+
return attach(scope, element, angular.extend({
|
|
1765
|
+
isFAB: element.hasClass('md-fab'),
|
|
1766
|
+
isMenuItem: element.hasClass('md-menu-item'),
|
|
1767
|
+
center: false,
|
|
1768
|
+
dimBackground: true
|
|
1769
|
+
}, options));
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
function attachCheckboxBehavior(scope, element, options) {
|
|
1773
|
+
return attach(scope, element, angular.extend({
|
|
1774
|
+
center: true,
|
|
1775
|
+
dimBackground: false,
|
|
1776
|
+
fitRipple: true
|
|
1777
|
+
}, options));
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
function attachTabBehavior(scope, element, options) {
|
|
1781
|
+
return attach(scope, element, angular.extend({
|
|
1782
|
+
center: false,
|
|
1783
|
+
dimBackground: true,
|
|
1784
|
+
outline: true
|
|
1785
|
+
}, options));
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
function attach(scope, element, options) {
|
|
1789
|
+
if (element.controller('mdNoInk')) return angular.noop;
|
|
1790
|
+
|
|
1791
|
+
options = angular.extend({
|
|
1792
|
+
colorElement: element,
|
|
1793
|
+
mousedown: true,
|
|
1794
|
+
hover: true,
|
|
1795
|
+
focus: true,
|
|
1796
|
+
center: false,
|
|
1797
|
+
mousedownPauseTime: 150,
|
|
1798
|
+
dimBackground: false,
|
|
1799
|
+
outline: false,
|
|
1800
|
+
isFAB: false,
|
|
1801
|
+
isMenuItem: false,
|
|
1802
|
+
fitRipple: false
|
|
1803
|
+
}, options);
|
|
1804
|
+
|
|
1805
|
+
var rippleSize,
|
|
1806
|
+
controller = element.controller('mdInkRipple') || {},
|
|
1807
|
+
counter = 0,
|
|
1808
|
+
ripples = [],
|
|
1809
|
+
states = [],
|
|
1810
|
+
isActiveExpr = element.attr('md-highlight'),
|
|
1811
|
+
isActive = false,
|
|
1812
|
+
isHeld = false,
|
|
1813
|
+
node = element[0],
|
|
1814
|
+
rippleSizeSetting = element.attr('md-ripple-size'),
|
|
1815
|
+
color = parseColor(element.attr('md-ink-ripple')) || parseColor($window.getComputedStyle(options.colorElement[0]).color || 'rgb(0, 0, 0)');
|
|
1816
|
+
|
|
1817
|
+
switch (rippleSizeSetting) {
|
|
1818
|
+
case 'full':
|
|
1819
|
+
options.isFAB = true;
|
|
1820
|
+
break;
|
|
1821
|
+
case 'partial':
|
|
1822
|
+
options.isFAB = false;
|
|
1823
|
+
break;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// expose onInput for ripple testing
|
|
1827
|
+
if (options.mousedown) {
|
|
1828
|
+
element.on('$md.pressdown', onPressDown)
|
|
1829
|
+
.on('$md.pressup', onPressUp);
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
controller.createRipple = createRipple;
|
|
1833
|
+
|
|
1834
|
+
if (isActiveExpr) {
|
|
1835
|
+
scope.$watch(isActiveExpr, function watchActive(newValue) {
|
|
1836
|
+
isActive = newValue;
|
|
1837
|
+
if (isActive && !ripples.length) {
|
|
1838
|
+
$timeout(function () { createRipple(0, 0); }, 0, false);
|
|
1839
|
+
}
|
|
1840
|
+
angular.forEach(ripples, updateElement);
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// Publish self-detach method if desired...
|
|
1845
|
+
return function detach() {
|
|
1846
|
+
element.off('$md.pressdown', onPressDown)
|
|
1847
|
+
.off('$md.pressup', onPressUp);
|
|
1848
|
+
getRippleContainer().remove();
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* Gets the current ripple container
|
|
1853
|
+
* If there is no ripple container, it creates one and returns it
|
|
1854
|
+
*
|
|
1855
|
+
* @returns {angular.element} ripple container element
|
|
1856
|
+
*/
|
|
1857
|
+
function getRippleContainer() {
|
|
1858
|
+
var container = element.data('$mdRippleContainer');
|
|
1859
|
+
if (container) return container;
|
|
1860
|
+
container = angular.element('<div class="md-ripple-container">');
|
|
1861
|
+
element.append(container);
|
|
1862
|
+
element.data('$mdRippleContainer', container);
|
|
1863
|
+
return container;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
function parseColor(color) {
|
|
1867
|
+
if (!color) return;
|
|
1868
|
+
if (color.indexOf('rgba') === 0) return color.replace(/\d?\.?\d*\s*\)\s*$/, '0.1)');
|
|
1869
|
+
if (color.indexOf('rgb') === 0) return rgbToRGBA(color);
|
|
1870
|
+
if (color.indexOf('#') === 0) return hexToRGBA(color);
|
|
1871
|
+
|
|
1872
|
+
/**
|
|
1873
|
+
* Converts a hex value to an rgba string
|
|
1874
|
+
*
|
|
1875
|
+
* @param {string} hex value (3 or 6 digits) to be converted
|
|
1876
|
+
*
|
|
1877
|
+
* @returns {string} rgba color with 0.1 alpha
|
|
1878
|
+
*/
|
|
1879
|
+
function hexToRGBA(color) {
|
|
1880
|
+
var hex = color.charAt(0) === '#' ? color.substr(1) : color,
|
|
1881
|
+
dig = hex.length / 3,
|
|
1882
|
+
red = hex.substr(0, dig),
|
|
1883
|
+
grn = hex.substr(dig, dig),
|
|
1884
|
+
blu = hex.substr(dig * 2);
|
|
1885
|
+
if (dig === 1) {
|
|
1886
|
+
red += red;
|
|
1887
|
+
grn += grn;
|
|
1888
|
+
blu += blu;
|
|
1889
|
+
}
|
|
1890
|
+
return 'rgba(' + parseInt(red, 16) + ',' + parseInt(grn, 16) + ',' + parseInt(blu, 16) + ',0.1)';
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
/**
|
|
1894
|
+
* Converts rgb value to rgba string
|
|
1895
|
+
*
|
|
1896
|
+
* @param {string} rgb color string
|
|
1897
|
+
*
|
|
1898
|
+
* @returns {string} rgba color with 0.1 alpha
|
|
1899
|
+
*/
|
|
1900
|
+
function rgbToRGBA(color) {
|
|
1901
|
+
return color.replace(')', ', 0.1)').replace('(', 'a(');
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
function removeElement(elem, wait) {
|
|
1907
|
+
ripples.splice(ripples.indexOf(elem), 1);
|
|
1908
|
+
if (ripples.length === 0) {
|
|
1909
|
+
getRippleContainer().css({ backgroundColor: '' });
|
|
1910
|
+
}
|
|
1911
|
+
$timeout(function () { elem.remove(); }, wait, false);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function updateElement(elem) {
|
|
1915
|
+
var index = ripples.indexOf(elem),
|
|
1916
|
+
state = states[index] || {},
|
|
1917
|
+
elemIsActive = ripples.length > 1 ? false : isActive,
|
|
1918
|
+
elemIsHeld = ripples.length > 1 ? false : isHeld;
|
|
1919
|
+
if (elemIsActive || state.animating || elemIsHeld) {
|
|
1920
|
+
elem.addClass('md-ripple-visible');
|
|
1921
|
+
} else if (elem) {
|
|
1922
|
+
elem.removeClass('md-ripple-visible');
|
|
1923
|
+
if (options.outline) {
|
|
1924
|
+
elem.css({
|
|
1925
|
+
width: rippleSize + 'px',
|
|
1926
|
+
height: rippleSize + 'px',
|
|
1927
|
+
marginLeft: (rippleSize * -1) + 'px',
|
|
1928
|
+
marginTop: (rippleSize * -1) + 'px'
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
removeElement(elem, options.outline ? 450 : 650);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
/**
|
|
1936
|
+
* Creates a ripple at the provided coordinates
|
|
1937
|
+
*
|
|
1938
|
+
* @param {number} left cursor position
|
|
1939
|
+
* @param {number} top cursor position
|
|
1940
|
+
*
|
|
1941
|
+
* @returns {angular.element} the generated ripple element
|
|
1942
|
+
*/
|
|
1943
|
+
function createRipple(left, top) {
|
|
1944
|
+
|
|
1945
|
+
color = parseColor(element.attr('md-ink-ripple')) || parseColor($window.getComputedStyle(options.colorElement[0]).color || 'rgb(0, 0, 0)');
|
|
1946
|
+
|
|
1947
|
+
var container = getRippleContainer(),
|
|
1948
|
+
size = getRippleSize(left, top),
|
|
1949
|
+
css = getRippleCss(size, left, top),
|
|
1950
|
+
elem = getRippleElement(css),
|
|
1951
|
+
index = ripples.indexOf(elem),
|
|
1952
|
+
state = states[index] || {};
|
|
1953
|
+
|
|
1954
|
+
rippleSize = size;
|
|
1955
|
+
|
|
1956
|
+
state.animating = true;
|
|
1957
|
+
|
|
1958
|
+
$timeout(function () {
|
|
1959
|
+
if (options.dimBackground) {
|
|
1960
|
+
container.css({ backgroundColor: color });
|
|
1961
|
+
}
|
|
1962
|
+
elem.addClass('md-ripple-placed md-ripple-scaled');
|
|
1963
|
+
if (options.outline) {
|
|
1964
|
+
elem.css({
|
|
1965
|
+
borderWidth: (size * 0.5) + 'px',
|
|
1966
|
+
marginLeft: (size * -0.5) + 'px',
|
|
1967
|
+
marginTop: (size * -0.5) + 'px'
|
|
1968
|
+
});
|
|
1969
|
+
} else {
|
|
1970
|
+
elem.css({ left: '50%', top: '50%' });
|
|
1971
|
+
}
|
|
1972
|
+
updateElement(elem);
|
|
1973
|
+
$timeout(function () {
|
|
1974
|
+
state.animating = false;
|
|
1975
|
+
updateElement(elem);
|
|
1976
|
+
}, (options.outline ? 450 : 225), false);
|
|
1977
|
+
}, 0, false);
|
|
1978
|
+
|
|
1979
|
+
return elem;
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* Creates the ripple element with the provided css
|
|
1983
|
+
*
|
|
1984
|
+
* @param {object} css properties to be applied
|
|
1985
|
+
*
|
|
1986
|
+
* @returns {angular.element} the generated ripple element
|
|
1987
|
+
*/
|
|
1988
|
+
function getRippleElement(css) {
|
|
1989
|
+
var elem = angular.element('<div class="md-ripple" data-counter="' + counter++ + '">');
|
|
1990
|
+
ripples.unshift(elem);
|
|
1991
|
+
states.unshift({ animating: true });
|
|
1992
|
+
container.append(elem);
|
|
1993
|
+
css && elem.css(css);
|
|
1994
|
+
return elem;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* Calculate the ripple size
|
|
1999
|
+
*
|
|
2000
|
+
* @returns {number} calculated ripple diameter
|
|
2001
|
+
*/
|
|
2002
|
+
function getRippleSize(left, top) {
|
|
2003
|
+
var width = container.prop('offsetWidth'),
|
|
2004
|
+
height = container.prop('offsetHeight'),
|
|
2005
|
+
multiplier, size, rect;
|
|
2006
|
+
if (options.isMenuItem) {
|
|
2007
|
+
size = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
|
|
2008
|
+
} else if (options.outline) {
|
|
2009
|
+
rect = node.getBoundingClientRect();
|
|
2010
|
+
left -= rect.left;
|
|
2011
|
+
top -= rect.top;
|
|
2012
|
+
width = Math.max(left, width - left);
|
|
2013
|
+
height = Math.max(top, height - top);
|
|
2014
|
+
size = 2 * Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
|
|
2015
|
+
} else {
|
|
2016
|
+
multiplier = options.isFAB ? 1.1 : 0.8;
|
|
2017
|
+
size = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) * multiplier;
|
|
2018
|
+
if (options.fitRipple) {
|
|
2019
|
+
size = Math.min(height, width, size);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
return size;
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/**
|
|
2026
|
+
* Generates the ripple css
|
|
2027
|
+
*
|
|
2028
|
+
* @param {number} the diameter of the ripple
|
|
2029
|
+
* @param {number} the left cursor offset
|
|
2030
|
+
* @param {number} the top cursor offset
|
|
2031
|
+
*
|
|
2032
|
+
* @returns {{backgroundColor: *, width: string, height: string, marginLeft: string, marginTop: string}}
|
|
2033
|
+
*/
|
|
2034
|
+
function getRippleCss(size, left, top) {
|
|
2035
|
+
var rect,
|
|
2036
|
+
css = {
|
|
2037
|
+
backgroundColor: rgbaToRGB(color),
|
|
2038
|
+
borderColor: rgbaToRGB(color),
|
|
2039
|
+
width: size + 'px',
|
|
2040
|
+
height: size + 'px'
|
|
2041
|
+
};
|
|
2042
|
+
|
|
2043
|
+
if (options.outline) {
|
|
2044
|
+
css.width = 0;
|
|
2045
|
+
css.height = 0;
|
|
2046
|
+
} else {
|
|
2047
|
+
css.marginLeft = css.marginTop = (size * -0.5) + 'px';
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
if (options.center) {
|
|
2051
|
+
css.left = css.top = '50%';
|
|
2052
|
+
} else {
|
|
2053
|
+
rect = node.getBoundingClientRect();
|
|
2054
|
+
css.left = Math.round((left - rect.left) / container.prop('offsetWidth') * 100) + '%';
|
|
2055
|
+
css.top = Math.round((top - rect.top) / container.prop('offsetHeight') * 100) + '%';
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
return css;
|
|
2059
|
+
|
|
2060
|
+
/**
|
|
2061
|
+
* Converts rgba string to rgb, removing the alpha value
|
|
2062
|
+
*
|
|
2063
|
+
* @param {string} rgba color
|
|
2064
|
+
*
|
|
2065
|
+
* @returns {string} rgb color
|
|
2066
|
+
*/
|
|
2067
|
+
function rgbaToRGB(color) {
|
|
2068
|
+
return color.replace('rgba', 'rgb').replace(/,[^\)\,]+\)/, ')');
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* Handles user input start and stop events
|
|
2075
|
+
*
|
|
2076
|
+
*/
|
|
2077
|
+
function onPressDown(ev) {
|
|
2078
|
+
if (!isRippleAllowed()) return;
|
|
2079
|
+
|
|
2080
|
+
var ripple = createRipple(ev.pointer.x, ev.pointer.y);
|
|
2081
|
+
isHeld = true;
|
|
2082
|
+
}
|
|
2083
|
+
function onPressUp(ev) {
|
|
2084
|
+
isHeld = false;
|
|
2085
|
+
var ripple = ripples[ ripples.length - 1 ];
|
|
2086
|
+
$timeout(function () { updateElement(ripple); }, 0, false);
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
/**
|
|
2090
|
+
* Determines if the ripple is allowed
|
|
2091
|
+
*
|
|
2092
|
+
* @returns {boolean} true if the ripple is allowed, false if not
|
|
2093
|
+
*/
|
|
2094
|
+
function isRippleAllowed() {
|
|
2095
|
+
var parent = node.parentNode;
|
|
2096
|
+
var grandparent = parent && parent.parentNode;
|
|
2097
|
+
var ancestor = grandparent && grandparent.parentNode;
|
|
2098
|
+
return !isDisabled(node) && !isDisabled(parent) && !isDisabled(grandparent) && !isDisabled(ancestor);
|
|
2099
|
+
function isDisabled (elem) {
|
|
2100
|
+
return elem && elem.hasAttribute && elem.hasAttribute('disabled');
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
InkRippleService.$inject = ["$window", "$timeout"];
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* noink/nobar/nostretch directive: make any element that has one of
|
|
2110
|
+
* these attributes be given a controller, so that other directives can
|
|
2111
|
+
* `require:` these and see if there is a `no<xxx>` parent attribute.
|
|
2112
|
+
*
|
|
2113
|
+
* @usage
|
|
2114
|
+
* <hljs lang="html">
|
|
2115
|
+
* <parent md-no-ink>
|
|
2116
|
+
* <child detect-no>
|
|
2117
|
+
* </child>
|
|
2118
|
+
* </parent>
|
|
2119
|
+
* </hljs>
|
|
2120
|
+
*
|
|
2121
|
+
* <hljs lang="js">
|
|
2122
|
+
* myApp.directive('detectNo', function() {
|
|
2123
|
+
* return {
|
|
2124
|
+
* require: ['^?mdNoInk', ^?mdNoBar'],
|
|
2125
|
+
* link: function(scope, element, attr, ctrls) {
|
|
2126
|
+
* var noinkCtrl = ctrls[0];
|
|
2127
|
+
* var nobarCtrl = ctrls[1];
|
|
2128
|
+
* if (noInkCtrl) {
|
|
2129
|
+
* alert("the md-no-ink flag has been specified on an ancestor!");
|
|
2130
|
+
* }
|
|
2131
|
+
* if (nobarCtrl) {
|
|
2132
|
+
* alert("the md-no-bar flag has been specified on an ancestor!");
|
|
2133
|
+
* }
|
|
2134
|
+
* }
|
|
2135
|
+
* };
|
|
2136
|
+
* });
|
|
2137
|
+
* </hljs>
|
|
2138
|
+
*/
|
|
2139
|
+
function attrNoDirective() {
|
|
2140
|
+
return function() {
|
|
2141
|
+
return {
|
|
2142
|
+
controller: angular.noop
|
|
2143
|
+
};
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
})();
|
|
2147
|
+
|
|
2148
|
+
(function() {
|
|
2149
|
+
'use strict';
|
|
2150
|
+
|
|
2151
|
+
angular.module('material.core.theming.palette', [])
|
|
2152
|
+
.constant('$mdColorPalette', {
|
|
2153
|
+
'red': {
|
|
2154
|
+
'50': '#ffebee',
|
|
2155
|
+
'100': '#ffcdd2',
|
|
2156
|
+
'200': '#ef9a9a',
|
|
2157
|
+
'300': '#e57373',
|
|
2158
|
+
'400': '#ef5350',
|
|
2159
|
+
'500': '#f44336',
|
|
2160
|
+
'600': '#e53935',
|
|
2161
|
+
'700': '#d32f2f',
|
|
2162
|
+
'800': '#c62828',
|
|
2163
|
+
'900': '#b71c1c',
|
|
2164
|
+
'A100': '#ff8a80',
|
|
2165
|
+
'A200': '#ff5252',
|
|
2166
|
+
'A400': '#ff1744',
|
|
2167
|
+
'A700': '#d50000',
|
|
2168
|
+
'contrastDefaultColor': 'light',
|
|
2169
|
+
'contrastDarkColors': '50 100 200 300 400 A100',
|
|
2170
|
+
'contrastStrongLightColors': '500 600 700 A200 A400 A700'
|
|
2171
|
+
},
|
|
2172
|
+
'pink': {
|
|
2173
|
+
'50': '#fce4ec',
|
|
2174
|
+
'100': '#f8bbd0',
|
|
2175
|
+
'200': '#f48fb1',
|
|
2176
|
+
'300': '#f06292',
|
|
2177
|
+
'400': '#ec407a',
|
|
2178
|
+
'500': '#e91e63',
|
|
2179
|
+
'600': '#d81b60',
|
|
2180
|
+
'700': '#c2185b',
|
|
2181
|
+
'800': '#ad1457',
|
|
2182
|
+
'900': '#880e4f',
|
|
2183
|
+
'A100': '#ff80ab',
|
|
2184
|
+
'A200': '#ff4081',
|
|
2185
|
+
'A400': '#f50057',
|
|
2186
|
+
'A700': '#c51162',
|
|
2187
|
+
'contrastDefaultColor': 'light',
|
|
2188
|
+
'contrastDarkColors': '50 100 200 300 400 A100',
|
|
2189
|
+
'contrastStrongLightColors': '500 600 A200 A400 A700'
|
|
2190
|
+
},
|
|
2191
|
+
'purple': {
|
|
2192
|
+
'50': '#f3e5f5',
|
|
2193
|
+
'100': '#e1bee7',
|
|
2194
|
+
'200': '#ce93d8',
|
|
2195
|
+
'300': '#ba68c8',
|
|
2196
|
+
'400': '#ab47bc',
|
|
2197
|
+
'500': '#9c27b0',
|
|
2198
|
+
'600': '#8e24aa',
|
|
2199
|
+
'700': '#7b1fa2',
|
|
2200
|
+
'800': '#6a1b9a',
|
|
2201
|
+
'900': '#4a148c',
|
|
2202
|
+
'A100': '#ea80fc',
|
|
2203
|
+
'A200': '#e040fb',
|
|
2204
|
+
'A400': '#d500f9',
|
|
2205
|
+
'A700': '#aa00ff',
|
|
2206
|
+
'contrastDefaultColor': 'light',
|
|
2207
|
+
'contrastDarkColors': '50 100 200 A100',
|
|
2208
|
+
'contrastStrongLightColors': '300 400 A200 A400 A700'
|
|
2209
|
+
},
|
|
2210
|
+
'deep-purple': {
|
|
2211
|
+
'50': '#ede7f6',
|
|
2212
|
+
'100': '#d1c4e9',
|
|
2213
|
+
'200': '#b39ddb',
|
|
2214
|
+
'300': '#9575cd',
|
|
2215
|
+
'400': '#7e57c2',
|
|
2216
|
+
'500': '#673ab7',
|
|
2217
|
+
'600': '#5e35b1',
|
|
2218
|
+
'700': '#512da8',
|
|
2219
|
+
'800': '#4527a0',
|
|
2220
|
+
'900': '#311b92',
|
|
2221
|
+
'A100': '#b388ff',
|
|
2222
|
+
'A200': '#7c4dff',
|
|
2223
|
+
'A400': '#651fff',
|
|
2224
|
+
'A700': '#6200ea',
|
|
2225
|
+
'contrastDefaultColor': 'light',
|
|
2226
|
+
'contrastDarkColors': '50 100 200 A100',
|
|
2227
|
+
'contrastStrongLightColors': '300 400 A200'
|
|
2228
|
+
},
|
|
2229
|
+
'indigo': {
|
|
2230
|
+
'50': '#e8eaf6',
|
|
2231
|
+
'100': '#c5cae9',
|
|
2232
|
+
'200': '#9fa8da',
|
|
2233
|
+
'300': '#7986cb',
|
|
2234
|
+
'400': '#5c6bc0',
|
|
2235
|
+
'500': '#3f51b5',
|
|
2236
|
+
'600': '#3949ab',
|
|
2237
|
+
'700': '#303f9f',
|
|
2238
|
+
'800': '#283593',
|
|
2239
|
+
'900': '#1a237e',
|
|
2240
|
+
'A100': '#8c9eff',
|
|
2241
|
+
'A200': '#536dfe',
|
|
2242
|
+
'A400': '#3d5afe',
|
|
2243
|
+
'A700': '#304ffe',
|
|
2244
|
+
'contrastDefaultColor': 'light',
|
|
2245
|
+
'contrastDarkColors': '50 100 200 A100',
|
|
2246
|
+
'contrastStrongLightColors': '300 400 A200 A400'
|
|
2247
|
+
},
|
|
2248
|
+
'blue': {
|
|
2249
|
+
'50': '#e3f2fd',
|
|
2250
|
+
'100': '#bbdefb',
|
|
2251
|
+
'200': '#90caf9',
|
|
2252
|
+
'300': '#64b5f6',
|
|
2253
|
+
'400': '#42a5f5',
|
|
2254
|
+
'500': '#2196f3',
|
|
2255
|
+
'600': '#1e88e5',
|
|
2256
|
+
'700': '#1976d2',
|
|
2257
|
+
'800': '#1565c0',
|
|
2258
|
+
'900': '#0d47a1',
|
|
2259
|
+
'A100': '#82b1ff',
|
|
2260
|
+
'A200': '#448aff',
|
|
2261
|
+
'A400': '#2979ff',
|
|
2262
|
+
'A700': '#2962ff',
|
|
2263
|
+
'contrastDefaultColor': 'light',
|
|
2264
|
+
'contrastDarkColors': '100 200 300 400 A100',
|
|
2265
|
+
'contrastStrongLightColors': '500 600 700 A200 A400 A700'
|
|
2266
|
+
},
|
|
2267
|
+
'light-blue': {
|
|
2268
|
+
'50': '#e1f5fe',
|
|
2269
|
+
'100': '#b3e5fc',
|
|
2270
|
+
'200': '#81d4fa',
|
|
2271
|
+
'300': '#4fc3f7',
|
|
2272
|
+
'400': '#29b6f6',
|
|
2273
|
+
'500': '#03a9f4',
|
|
2274
|
+
'600': '#039be5',
|
|
2275
|
+
'700': '#0288d1',
|
|
2276
|
+
'800': '#0277bd',
|
|
2277
|
+
'900': '#01579b',
|
|
2278
|
+
'A100': '#80d8ff',
|
|
2279
|
+
'A200': '#40c4ff',
|
|
2280
|
+
'A400': '#00b0ff',
|
|
2281
|
+
'A700': '#0091ea',
|
|
2282
|
+
'contrastDefaultColor': 'dark',
|
|
2283
|
+
'contrastLightColors': '500 600 700 800 900 A700',
|
|
2284
|
+
'contrastStrongLightColors': '500 600 700 800 A700'
|
|
2285
|
+
},
|
|
2286
|
+
'cyan': {
|
|
2287
|
+
'50': '#e0f7fa',
|
|
2288
|
+
'100': '#b2ebf2',
|
|
2289
|
+
'200': '#80deea',
|
|
2290
|
+
'300': '#4dd0e1',
|
|
2291
|
+
'400': '#26c6da',
|
|
2292
|
+
'500': '#00bcd4',
|
|
2293
|
+
'600': '#00acc1',
|
|
2294
|
+
'700': '#0097a7',
|
|
2295
|
+
'800': '#00838f',
|
|
2296
|
+
'900': '#006064',
|
|
2297
|
+
'A100': '#84ffff',
|
|
2298
|
+
'A200': '#18ffff',
|
|
2299
|
+
'A400': '#00e5ff',
|
|
2300
|
+
'A700': '#00b8d4',
|
|
2301
|
+
'contrastDefaultColor': 'dark',
|
|
2302
|
+
'contrastLightColors': '500 600 700 800 900',
|
|
2303
|
+
'contrastStrongLightColors': '500 600 700 800'
|
|
2304
|
+
},
|
|
2305
|
+
'teal': {
|
|
2306
|
+
'50': '#e0f2f1',
|
|
2307
|
+
'100': '#b2dfdb',
|
|
2308
|
+
'200': '#80cbc4',
|
|
2309
|
+
'300': '#4db6ac',
|
|
2310
|
+
'400': '#26a69a',
|
|
2311
|
+
'500': '#009688',
|
|
2312
|
+
'600': '#00897b',
|
|
2313
|
+
'700': '#00796b',
|
|
2314
|
+
'800': '#00695c',
|
|
2315
|
+
'900': '#004d40',
|
|
2316
|
+
'A100': '#a7ffeb',
|
|
2317
|
+
'A200': '#64ffda',
|
|
2318
|
+
'A400': '#1de9b6',
|
|
2319
|
+
'A700': '#00bfa5',
|
|
2320
|
+
'contrastDefaultColor': 'dark',
|
|
2321
|
+
'contrastLightColors': '500 600 700 800 900',
|
|
2322
|
+
'contrastStrongLightColors': '500 600 700'
|
|
2323
|
+
},
|
|
2324
|
+
'green': {
|
|
2325
|
+
'50': '#e8f5e9',
|
|
2326
|
+
'100': '#c8e6c9',
|
|
2327
|
+
'200': '#a5d6a7',
|
|
2328
|
+
'300': '#81c784',
|
|
2329
|
+
'400': '#66bb6a',
|
|
2330
|
+
'500': '#4caf50',
|
|
2331
|
+
'600': '#43a047',
|
|
2332
|
+
'700': '#388e3c',
|
|
2333
|
+
'800': '#2e7d32',
|
|
2334
|
+
'900': '#1b5e20',
|
|
2335
|
+
'A100': '#b9f6ca',
|
|
2336
|
+
'A200': '#69f0ae',
|
|
2337
|
+
'A400': '#00e676',
|
|
2338
|
+
'A700': '#00c853',
|
|
2339
|
+
'contrastDefaultColor': 'dark',
|
|
2340
|
+
'contrastLightColors': '500 600 700 800 900',
|
|
2341
|
+
'contrastStrongLightColors': '500 600 700'
|
|
2342
|
+
},
|
|
2343
|
+
'light-green': {
|
|
2344
|
+
'50': '#f1f8e9',
|
|
2345
|
+
'100': '#dcedc8',
|
|
2346
|
+
'200': '#c5e1a5',
|
|
2347
|
+
'300': '#aed581',
|
|
2348
|
+
'400': '#9ccc65',
|
|
2349
|
+
'500': '#8bc34a',
|
|
2350
|
+
'600': '#7cb342',
|
|
2351
|
+
'700': '#689f38',
|
|
2352
|
+
'800': '#558b2f',
|
|
2353
|
+
'900': '#33691e',
|
|
2354
|
+
'A100': '#ccff90',
|
|
2355
|
+
'A200': '#b2ff59',
|
|
2356
|
+
'A400': '#76ff03',
|
|
2357
|
+
'A700': '#64dd17',
|
|
2358
|
+
'contrastDefaultColor': 'dark',
|
|
2359
|
+
'contrastLightColors': '800 900',
|
|
2360
|
+
'contrastStrongLightColors': '800 900'
|
|
2361
|
+
},
|
|
2362
|
+
'lime': {
|
|
2363
|
+
'50': '#f9fbe7',
|
|
2364
|
+
'100': '#f0f4c3',
|
|
2365
|
+
'200': '#e6ee9c',
|
|
2366
|
+
'300': '#dce775',
|
|
2367
|
+
'400': '#d4e157',
|
|
2368
|
+
'500': '#cddc39',
|
|
2369
|
+
'600': '#c0ca33',
|
|
2370
|
+
'700': '#afb42b',
|
|
2371
|
+
'800': '#9e9d24',
|
|
2372
|
+
'900': '#827717',
|
|
2373
|
+
'A100': '#f4ff81',
|
|
2374
|
+
'A200': '#eeff41',
|
|
2375
|
+
'A400': '#c6ff00',
|
|
2376
|
+
'A700': '#aeea00',
|
|
2377
|
+
'contrastDefaultColor': 'dark',
|
|
2378
|
+
'contrastLightColors': '900',
|
|
2379
|
+
'contrastStrongLightColors': '900'
|
|
2380
|
+
},
|
|
2381
|
+
'yellow': {
|
|
2382
|
+
'50': '#fffde7',
|
|
2383
|
+
'100': '#fff9c4',
|
|
2384
|
+
'200': '#fff59d',
|
|
2385
|
+
'300': '#fff176',
|
|
2386
|
+
'400': '#ffee58',
|
|
2387
|
+
'500': '#ffeb3b',
|
|
2388
|
+
'600': '#fdd835',
|
|
2389
|
+
'700': '#fbc02d',
|
|
2390
|
+
'800': '#f9a825',
|
|
2391
|
+
'900': '#f57f17',
|
|
2392
|
+
'A100': '#ffff8d',
|
|
2393
|
+
'A200': '#ffff00',
|
|
2394
|
+
'A400': '#ffea00',
|
|
2395
|
+
'A700': '#ffd600',
|
|
2396
|
+
'contrastDefaultColor': 'dark'
|
|
2397
|
+
},
|
|
2398
|
+
'amber': {
|
|
2399
|
+
'50': '#fff8e1',
|
|
2400
|
+
'100': '#ffecb3',
|
|
2401
|
+
'200': '#ffe082',
|
|
2402
|
+
'300': '#ffd54f',
|
|
2403
|
+
'400': '#ffca28',
|
|
2404
|
+
'500': '#ffc107',
|
|
2405
|
+
'600': '#ffb300',
|
|
2406
|
+
'700': '#ffa000',
|
|
2407
|
+
'800': '#ff8f00',
|
|
2408
|
+
'900': '#ff6f00',
|
|
2409
|
+
'A100': '#ffe57f',
|
|
2410
|
+
'A200': '#ffd740',
|
|
2411
|
+
'A400': '#ffc400',
|
|
2412
|
+
'A700': '#ffab00',
|
|
2413
|
+
'contrastDefaultColor': 'dark'
|
|
2414
|
+
},
|
|
2415
|
+
'orange': {
|
|
2416
|
+
'50': '#fff3e0',
|
|
2417
|
+
'100': '#ffe0b2',
|
|
2418
|
+
'200': '#ffcc80',
|
|
2419
|
+
'300': '#ffb74d',
|
|
2420
|
+
'400': '#ffa726',
|
|
2421
|
+
'500': '#ff9800',
|
|
2422
|
+
'600': '#fb8c00',
|
|
2423
|
+
'700': '#f57c00',
|
|
2424
|
+
'800': '#ef6c00',
|
|
2425
|
+
'900': '#e65100',
|
|
2426
|
+
'A100': '#ffd180',
|
|
2427
|
+
'A200': '#ffab40',
|
|
2428
|
+
'A400': '#ff9100',
|
|
2429
|
+
'A700': '#ff6d00',
|
|
2430
|
+
'contrastDefaultColor': 'dark',
|
|
2431
|
+
'contrastLightColors': '800 900',
|
|
2432
|
+
'contrastStrongLightColors': '800 900'
|
|
2433
|
+
},
|
|
2434
|
+
'deep-orange': {
|
|
2435
|
+
'50': '#fbe9e7',
|
|
2436
|
+
'100': '#ffccbc',
|
|
2437
|
+
'200': '#ffab91',
|
|
2438
|
+
'300': '#ff8a65',
|
|
2439
|
+
'400': '#ff7043',
|
|
2440
|
+
'500': '#ff5722',
|
|
2441
|
+
'600': '#f4511e',
|
|
2442
|
+
'700': '#e64a19',
|
|
2443
|
+
'800': '#d84315',
|
|
2444
|
+
'900': '#bf360c',
|
|
2445
|
+
'A100': '#ff9e80',
|
|
2446
|
+
'A200': '#ff6e40',
|
|
2447
|
+
'A400': '#ff3d00',
|
|
2448
|
+
'A700': '#dd2c00',
|
|
2449
|
+
'contrastDefaultColor': 'light',
|
|
2450
|
+
'contrastDarkColors': '50 100 200 300 400 A100 A200',
|
|
2451
|
+
'contrastStrongLightColors': '500 600 700 800 900 A400 A700'
|
|
2452
|
+
},
|
|
2453
|
+
'brown': {
|
|
2454
|
+
'50': '#efebe9',
|
|
2455
|
+
'100': '#d7ccc8',
|
|
2456
|
+
'200': '#bcaaa4',
|
|
2457
|
+
'300': '#a1887f',
|
|
2458
|
+
'400': '#8d6e63',
|
|
2459
|
+
'500': '#795548',
|
|
2460
|
+
'600': '#6d4c41',
|
|
2461
|
+
'700': '#5d4037',
|
|
2462
|
+
'800': '#4e342e',
|
|
2463
|
+
'900': '#3e2723',
|
|
2464
|
+
'A100': '#d7ccc8',
|
|
2465
|
+
'A200': '#bcaaa4',
|
|
2466
|
+
'A400': '#8d6e63',
|
|
2467
|
+
'A700': '#5d4037',
|
|
2468
|
+
'contrastDefaultColor': 'light',
|
|
2469
|
+
'contrastDarkColors': '50 100 200',
|
|
2470
|
+
'contrastStrongLightColors': '300 400'
|
|
2471
|
+
},
|
|
2472
|
+
'grey': {
|
|
2473
|
+
'0': '#ffffff',
|
|
2474
|
+
'50': '#fafafa',
|
|
2475
|
+
'100': '#f5f5f5',
|
|
2476
|
+
'200': '#eeeeee',
|
|
2477
|
+
'300': '#e0e0e0',
|
|
2478
|
+
'400': '#bdbdbd',
|
|
2479
|
+
'500': '#9e9e9e',
|
|
2480
|
+
'600': '#757575',
|
|
2481
|
+
'700': '#616161',
|
|
2482
|
+
'800': '#424242',
|
|
2483
|
+
'900': '#212121',
|
|
2484
|
+
'1000': '#000000',
|
|
2485
|
+
'A100': '#ffffff',
|
|
2486
|
+
'A200': '#eeeeee',
|
|
2487
|
+
'A400': '#bdbdbd',
|
|
2488
|
+
'A700': '#616161',
|
|
2489
|
+
'contrastDefaultColor': 'dark',
|
|
2490
|
+
'contrastLightColors': '600 700 800 900'
|
|
2491
|
+
},
|
|
2492
|
+
'blue-grey': {
|
|
2493
|
+
'50': '#eceff1',
|
|
2494
|
+
'100': '#cfd8dc',
|
|
2495
|
+
'200': '#b0bec5',
|
|
2496
|
+
'300': '#90a4ae',
|
|
2497
|
+
'400': '#78909c',
|
|
2498
|
+
'500': '#607d8b',
|
|
2499
|
+
'600': '#546e7a',
|
|
2500
|
+
'700': '#455a64',
|
|
2501
|
+
'800': '#37474f',
|
|
2502
|
+
'900': '#263238',
|
|
2503
|
+
'A100': '#cfd8dc',
|
|
2504
|
+
'A200': '#b0bec5',
|
|
2505
|
+
'A400': '#78909c',
|
|
2506
|
+
'A700': '#455a64',
|
|
2507
|
+
'contrastDefaultColor': 'light',
|
|
2508
|
+
'contrastDarkColors': '50 100 200 300',
|
|
2509
|
+
'contrastStrongLightColors': '400 500'
|
|
2510
|
+
}
|
|
2511
|
+
});
|
|
2512
|
+
})();
|
|
2513
|
+
|
|
2514
|
+
(function() {
|
|
2515
|
+
'use strict';
|
|
2516
|
+
|
|
2517
|
+
angular.module('material.core.theming', ['material.core.theming.palette'])
|
|
2518
|
+
.directive('mdTheme', ThemingDirective)
|
|
2519
|
+
.directive('mdThemable', ThemableDirective)
|
|
2520
|
+
.provider('$mdTheming', ThemingProvider)
|
|
2521
|
+
.run(generateThemes);
|
|
2522
|
+
|
|
2523
|
+
/**
|
|
2524
|
+
* @ngdoc provider
|
|
2525
|
+
* @name $mdThemingProvider
|
|
2526
|
+
* @module material.core
|
|
2527
|
+
*
|
|
2528
|
+
* @description Provider to configure the `$mdTheming` service.
|
|
2529
|
+
*/
|
|
2530
|
+
|
|
2531
|
+
/**
|
|
2532
|
+
* @ngdoc method
|
|
2533
|
+
* @name $mdThemingProvider#setDefaultTheme
|
|
2534
|
+
* @param {string} themeName Default theme name to be applied to elements. Default value is `default`.
|
|
2535
|
+
*/
|
|
2536
|
+
|
|
2537
|
+
/**
|
|
2538
|
+
* @ngdoc method
|
|
2539
|
+
* @name $mdThemingProvider#alwaysWatchTheme
|
|
2540
|
+
* @param {boolean} watch Whether or not to always watch themes for changes and re-apply
|
|
2541
|
+
* classes when they change. Default is `false`. Enabling can reduce performance.
|
|
2542
|
+
*/
|
|
2543
|
+
|
|
2544
|
+
// In memory storage of defined themes and color palettes (both loaded by CSS, and user specified)
|
|
2545
|
+
var PALETTES;
|
|
2546
|
+
var THEMES;
|
|
2547
|
+
var themingProvider;
|
|
2548
|
+
var generationIsDone;
|
|
2549
|
+
|
|
2550
|
+
var DARK_FOREGROUND = {
|
|
2551
|
+
name: 'dark',
|
|
2552
|
+
'1': 'rgba(0,0,0,0.87)',
|
|
2553
|
+
'2': 'rgba(0,0,0,0.54)',
|
|
2554
|
+
'3': 'rgba(0,0,0,0.26)',
|
|
2555
|
+
'4': 'rgba(0,0,0,0.12)'
|
|
2556
|
+
};
|
|
2557
|
+
var LIGHT_FOREGROUND = {
|
|
2558
|
+
name: 'light',
|
|
2559
|
+
'1': 'rgba(255,255,255,1.0)',
|
|
2560
|
+
'2': 'rgba(255,255,255,0.7)',
|
|
2561
|
+
'3': 'rgba(255,255,255,0.3)',
|
|
2562
|
+
'4': 'rgba(255,255,255,0.12)'
|
|
2563
|
+
};
|
|
2564
|
+
|
|
2565
|
+
var DARK_SHADOW = '1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)';
|
|
2566
|
+
var LIGHT_SHADOW = '';
|
|
2567
|
+
|
|
2568
|
+
var DARK_CONTRAST_COLOR = colorToRgbaArray('rgba(0,0,0,0.87)');
|
|
2569
|
+
var LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgba(255,255,255,0.87');
|
|
2570
|
+
var STRONG_LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgb(255,255,255)');
|
|
2571
|
+
|
|
2572
|
+
var THEME_COLOR_TYPES = ['primary', 'accent', 'warn', 'background'];
|
|
2573
|
+
var DEFAULT_COLOR_TYPE = 'primary';
|
|
2574
|
+
|
|
2575
|
+
// A color in a theme will use these hues by default, if not specified by user.
|
|
2576
|
+
var LIGHT_DEFAULT_HUES = {
|
|
2577
|
+
'accent': {
|
|
2578
|
+
'default': 'A200',
|
|
2579
|
+
'hue-1': 'A100',
|
|
2580
|
+
'hue-2': 'A400',
|
|
2581
|
+
'hue-3': 'A700'
|
|
2582
|
+
}
|
|
2583
|
+
};
|
|
2584
|
+
var DARK_DEFAULT_HUES = {
|
|
2585
|
+
'background': {
|
|
2586
|
+
'default': '500',
|
|
2587
|
+
'hue-1': '300',
|
|
2588
|
+
'hue-2': '600',
|
|
2589
|
+
'hue-3': '800'
|
|
2590
|
+
}
|
|
2591
|
+
};
|
|
2592
|
+
THEME_COLOR_TYPES.forEach(function(colorType) {
|
|
2593
|
+
// Color types with unspecified default hues will use these default hue values
|
|
2594
|
+
var defaultDefaultHues = {
|
|
2595
|
+
'default': '500',
|
|
2596
|
+
'hue-1': '300',
|
|
2597
|
+
'hue-2': '800',
|
|
2598
|
+
'hue-3': 'A100'
|
|
2599
|
+
};
|
|
2600
|
+
if (!LIGHT_DEFAULT_HUES[colorType]) LIGHT_DEFAULT_HUES[colorType] = defaultDefaultHues;
|
|
2601
|
+
if (!DARK_DEFAULT_HUES[colorType]) DARK_DEFAULT_HUES[colorType] = defaultDefaultHues;
|
|
2602
|
+
});
|
|
2603
|
+
|
|
2604
|
+
var VALID_HUE_VALUES = [
|
|
2605
|
+
'50', '100', '200', '300', '400', '500', '600',
|
|
2606
|
+
'700', '800', '900', 'A100', 'A200', 'A400', 'A700'
|
|
2607
|
+
];
|
|
2608
|
+
|
|
2609
|
+
function ThemingProvider($mdColorPalette) {
|
|
2610
|
+
PALETTES = {};
|
|
2611
|
+
THEMES = {};
|
|
2612
|
+
var defaultTheme = 'default';
|
|
2613
|
+
var alwaysWatchTheme = false;
|
|
2614
|
+
|
|
2615
|
+
// Load JS Defined Palettes
|
|
2616
|
+
angular.extend(PALETTES, $mdColorPalette);
|
|
2617
|
+
|
|
2618
|
+
// Default theme defined in core.js
|
|
2619
|
+
|
|
2620
|
+
ThemingService.$inject = ["$rootScope", "$log"];
|
|
2621
|
+
return themingProvider = {
|
|
2622
|
+
definePalette: definePalette,
|
|
2623
|
+
extendPalette: extendPalette,
|
|
2624
|
+
theme: registerTheme,
|
|
2625
|
+
|
|
2626
|
+
setDefaultTheme: function(theme) {
|
|
2627
|
+
defaultTheme = theme;
|
|
2628
|
+
},
|
|
2629
|
+
alwaysWatchTheme: function(alwaysWatch) {
|
|
2630
|
+
alwaysWatchTheme = alwaysWatch;
|
|
2631
|
+
},
|
|
2632
|
+
$get: ThemingService,
|
|
2633
|
+
_LIGHT_DEFAULT_HUES: LIGHT_DEFAULT_HUES,
|
|
2634
|
+
_DARK_DEFAULT_HUES: DARK_DEFAULT_HUES,
|
|
2635
|
+
_PALETTES: PALETTES,
|
|
2636
|
+
_THEMES: THEMES,
|
|
2637
|
+
_parseRules: parseRules,
|
|
2638
|
+
_rgba: rgba
|
|
2639
|
+
};
|
|
2640
|
+
|
|
2641
|
+
// Example: $mdThemingProvider.definePalette('neonRed', { 50: '#f5fafa', ... });
|
|
2642
|
+
function definePalette(name, map) {
|
|
2643
|
+
map = map || {};
|
|
2644
|
+
PALETTES[name] = checkPaletteValid(name, map);
|
|
2645
|
+
return themingProvider;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
// Returns an new object which is a copy of a given palette `name` with variables from
|
|
2649
|
+
// `map` overwritten
|
|
2650
|
+
// Example: var neonRedMap = $mdThemingProvider.extendPalette('red', { 50: '#f5fafafa' });
|
|
2651
|
+
function extendPalette(name, map) {
|
|
2652
|
+
return checkPaletteValid(name, angular.extend({}, PALETTES[name] || {}, map) );
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
// Make sure that palette has all required hues
|
|
2656
|
+
function checkPaletteValid(name, map) {
|
|
2657
|
+
var missingColors = VALID_HUE_VALUES.filter(function(field) {
|
|
2658
|
+
return !map[field];
|
|
2659
|
+
});
|
|
2660
|
+
if (missingColors.length) {
|
|
2661
|
+
throw new Error("Missing colors %1 in palette %2!"
|
|
2662
|
+
.replace('%1', missingColors.join(', '))
|
|
2663
|
+
.replace('%2', name));
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
return map;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
// Register a theme (which is a collection of color palettes to use with various states
|
|
2670
|
+
// ie. warn, accent, primary )
|
|
2671
|
+
// Optionally inherit from an existing theme
|
|
2672
|
+
// $mdThemingProvider.theme('custom-theme').primaryPalette('red');
|
|
2673
|
+
function registerTheme(name, inheritFrom) {
|
|
2674
|
+
inheritFrom = inheritFrom || 'default';
|
|
2675
|
+
if (THEMES[name]) return THEMES[name];
|
|
2676
|
+
|
|
2677
|
+
var parentTheme = typeof inheritFrom === 'string' ? THEMES[inheritFrom] : inheritFrom;
|
|
2678
|
+
var theme = new Theme(name);
|
|
2679
|
+
|
|
2680
|
+
if (parentTheme) {
|
|
2681
|
+
angular.forEach(parentTheme.colors, function(color, colorType) {
|
|
2682
|
+
theme.colors[colorType] = {
|
|
2683
|
+
name: color.name,
|
|
2684
|
+
// Make sure a COPY of the hues is given to the child color,
|
|
2685
|
+
// not the same reference.
|
|
2686
|
+
hues: angular.extend({}, color.hues)
|
|
2687
|
+
};
|
|
2688
|
+
});
|
|
2689
|
+
}
|
|
2690
|
+
THEMES[name] = theme;
|
|
2691
|
+
|
|
2692
|
+
return theme;
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
function Theme(name) {
|
|
2696
|
+
var self = this;
|
|
2697
|
+
self.name = name;
|
|
2698
|
+
self.colors = {};
|
|
2699
|
+
|
|
2700
|
+
self.dark = setDark;
|
|
2701
|
+
setDark(false);
|
|
2702
|
+
|
|
2703
|
+
function setDark(isDark) {
|
|
2704
|
+
isDark = arguments.length === 0 ? true : !!isDark;
|
|
2705
|
+
|
|
2706
|
+
// If no change, abort
|
|
2707
|
+
if (isDark === self.isDark) return;
|
|
2708
|
+
|
|
2709
|
+
self.isDark = isDark;
|
|
2710
|
+
|
|
2711
|
+
self.foregroundPalette = self.isDark ? LIGHT_FOREGROUND : DARK_FOREGROUND;
|
|
2712
|
+
self.foregroundShadow = self.isDark ? DARK_SHADOW : LIGHT_SHADOW;
|
|
2713
|
+
|
|
2714
|
+
// Light and dark themes have different default hues.
|
|
2715
|
+
// Go through each existing color type for this theme, and for every
|
|
2716
|
+
// hue value that is still the default hue value from the previous light/dark setting,
|
|
2717
|
+
// set it to the default hue value from the new light/dark setting.
|
|
2718
|
+
var newDefaultHues = self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES;
|
|
2719
|
+
var oldDefaultHues = self.isDark ? LIGHT_DEFAULT_HUES : DARK_DEFAULT_HUES;
|
|
2720
|
+
angular.forEach(newDefaultHues, function(newDefaults, colorType) {
|
|
2721
|
+
var color = self.colors[colorType];
|
|
2722
|
+
var oldDefaults = oldDefaultHues[colorType];
|
|
2723
|
+
if (color) {
|
|
2724
|
+
for (var hueName in color.hues) {
|
|
2725
|
+
if (color.hues[hueName] === oldDefaults[hueName]) {
|
|
2726
|
+
color.hues[hueName] = newDefaults[hueName];
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
});
|
|
2731
|
+
|
|
2732
|
+
return self;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
THEME_COLOR_TYPES.forEach(function(colorType) {
|
|
2736
|
+
var defaultHues = (self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES)[colorType];
|
|
2737
|
+
self[colorType + 'Palette'] = function setPaletteType(paletteName, hues) {
|
|
2738
|
+
var color = self.colors[colorType] = {
|
|
2739
|
+
name: paletteName,
|
|
2740
|
+
hues: angular.extend({}, defaultHues, hues)
|
|
2741
|
+
};
|
|
2742
|
+
|
|
2743
|
+
Object.keys(color.hues).forEach(function(name) {
|
|
2744
|
+
if (!defaultHues[name]) {
|
|
2745
|
+
throw new Error("Invalid hue name '%1' in theme %2's %3 color %4. Available hue names: %4"
|
|
2746
|
+
.replace('%1', name)
|
|
2747
|
+
.replace('%2', self.name)
|
|
2748
|
+
.replace('%3', paletteName)
|
|
2749
|
+
.replace('%4', Object.keys(defaultHues).join(', '))
|
|
2750
|
+
);
|
|
2751
|
+
}
|
|
2752
|
+
});
|
|
2753
|
+
Object.keys(color.hues).map(function(key) {
|
|
2754
|
+
return color.hues[key];
|
|
2755
|
+
}).forEach(function(hueValue) {
|
|
2756
|
+
if (VALID_HUE_VALUES.indexOf(hueValue) == -1) {
|
|
2757
|
+
throw new Error("Invalid hue value '%1' in theme %2's %3 color %4. Available hue values: %5"
|
|
2758
|
+
.replace('%1', hueValue)
|
|
2759
|
+
.replace('%2', self.name)
|
|
2760
|
+
.replace('%3', colorType)
|
|
2761
|
+
.replace('%4', paletteName)
|
|
2762
|
+
.replace('%5', VALID_HUE_VALUES.join(', '))
|
|
2763
|
+
);
|
|
2764
|
+
}
|
|
2765
|
+
});
|
|
2766
|
+
return self;
|
|
2767
|
+
};
|
|
2768
|
+
|
|
2769
|
+
self[colorType + 'Color'] = function() {
|
|
2770
|
+
var args = Array.prototype.slice.call(arguments);
|
|
2771
|
+
console.warn('$mdThemingProviderTheme.' + colorType + 'Color() has been depricated. ' +
|
|
2772
|
+
'Use $mdThemingProviderTheme.' + colorType + 'Palette() instead.');
|
|
2773
|
+
return self[colorType + 'Palette'].apply(self, args);
|
|
2774
|
+
};
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
/**
|
|
2779
|
+
* @ngdoc service
|
|
2780
|
+
* @name $mdTheming
|
|
2781
|
+
*
|
|
2782
|
+
* @description
|
|
2783
|
+
*
|
|
2784
|
+
* Service that makes an element apply theming related classes to itself.
|
|
2785
|
+
*
|
|
2786
|
+
* ```js
|
|
2787
|
+
* app.directive('myFancyDirective', function($mdTheming) {
|
|
2788
|
+
* return {
|
|
2789
|
+
* restrict: 'e',
|
|
2790
|
+
* link: function(scope, el, attrs) {
|
|
2791
|
+
* $mdTheming(el);
|
|
2792
|
+
* }
|
|
2793
|
+
* };
|
|
2794
|
+
* });
|
|
2795
|
+
* ```
|
|
2796
|
+
* @param {el=} element to apply theming to
|
|
2797
|
+
*/
|
|
2798
|
+
/* @ngInject */
|
|
2799
|
+
function ThemingService($rootScope, $log) {
|
|
2800
|
+
applyTheme.inherit = function(el, parent) {
|
|
2801
|
+
var ctrl = parent.controller('mdTheme');
|
|
2802
|
+
|
|
2803
|
+
var attrThemeValue = el.attr('md-theme-watch');
|
|
2804
|
+
if ( (alwaysWatchTheme || angular.isDefined(attrThemeValue)) && attrThemeValue != 'false') {
|
|
2805
|
+
var deregisterWatch = $rootScope.$watch(function() {
|
|
2806
|
+
return ctrl && ctrl.$mdTheme || defaultTheme;
|
|
2807
|
+
}, changeTheme);
|
|
2808
|
+
el.on('$destroy', deregisterWatch);
|
|
2809
|
+
} else {
|
|
2810
|
+
var theme = ctrl && ctrl.$mdTheme || defaultTheme;
|
|
2811
|
+
changeTheme(theme);
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
function changeTheme(theme) {
|
|
2815
|
+
if (!registered(theme)) {
|
|
2816
|
+
$log.warn('Attempted to use unregistered theme \'' + theme + '\'. ' +
|
|
2817
|
+
'Register it with $mdThemingProvider.theme().');
|
|
2818
|
+
}
|
|
2819
|
+
var oldTheme = el.data('$mdThemeName');
|
|
2820
|
+
if (oldTheme) el.removeClass('md-' + oldTheme +'-theme');
|
|
2821
|
+
el.addClass('md-' + theme + '-theme');
|
|
2822
|
+
el.data('$mdThemeName', theme);
|
|
2823
|
+
}
|
|
2824
|
+
};
|
|
2825
|
+
|
|
2826
|
+
applyTheme.registered = registered;
|
|
2827
|
+
|
|
2828
|
+
return applyTheme;
|
|
2829
|
+
|
|
2830
|
+
function registered(theme) {
|
|
2831
|
+
if (theme === undefined || theme === '') return true;
|
|
2832
|
+
return THEMES[theme] !== undefined;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
function applyTheme(scope, el) {
|
|
2836
|
+
// Allow us to be invoked via a linking function signature.
|
|
2837
|
+
if (el === undefined) {
|
|
2838
|
+
el = scope;
|
|
2839
|
+
scope = undefined;
|
|
2840
|
+
}
|
|
2841
|
+
if (scope === undefined) {
|
|
2842
|
+
scope = $rootScope;
|
|
2843
|
+
}
|
|
2844
|
+
applyTheme.inherit(el, el);
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
ThemingProvider.$inject = ["$mdColorPalette"];
|
|
2849
|
+
|
|
2850
|
+
function ThemingDirective($mdTheming, $interpolate, $log) {
|
|
2851
|
+
return {
|
|
2852
|
+
priority: 100,
|
|
2853
|
+
link: {
|
|
2854
|
+
pre: function(scope, el, attrs) {
|
|
2855
|
+
var ctrl = {
|
|
2856
|
+
$setTheme: function(theme) {
|
|
2857
|
+
if (!$mdTheming.registered(theme)) {
|
|
2858
|
+
$log.warn('attempted to use unregistered theme \'' + theme + '\'');
|
|
2859
|
+
}
|
|
2860
|
+
ctrl.$mdTheme = theme;
|
|
2861
|
+
}
|
|
2862
|
+
};
|
|
2863
|
+
el.data('$mdThemeController', ctrl);
|
|
2864
|
+
ctrl.$setTheme($interpolate(attrs.mdTheme)(scope));
|
|
2865
|
+
attrs.$observe('mdTheme', ctrl.$setTheme);
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
ThemingDirective.$inject = ["$mdTheming", "$interpolate", "$log"];
|
|
2871
|
+
|
|
2872
|
+
function ThemableDirective($mdTheming) {
|
|
2873
|
+
return $mdTheming;
|
|
2874
|
+
}
|
|
2875
|
+
ThemableDirective.$inject = ["$mdTheming"];
|
|
2876
|
+
|
|
2877
|
+
function parseRules(theme, colorType, rules) {
|
|
2878
|
+
checkValidPalette(theme, colorType);
|
|
2879
|
+
|
|
2880
|
+
rules = rules.replace(/THEME_NAME/g, theme.name);
|
|
2881
|
+
var generatedRules = [];
|
|
2882
|
+
var color = theme.colors[colorType];
|
|
2883
|
+
|
|
2884
|
+
var themeNameRegex = new RegExp('.md-' + theme.name + '-theme', 'g');
|
|
2885
|
+
// Matches '{{ primary-color }}', etc
|
|
2886
|
+
var hueRegex = new RegExp('(\'|")?{{\\s*(' + colorType + ')-(color|contrast)-?(\\d\\.?\\d*)?\\s*}}(\"|\')?','g');
|
|
2887
|
+
var simpleVariableRegex = /'?"?\{\{\s*([a-zA-Z]+)-(A?\d+|hue\-[0-3]|shadow)-?(\d\.?\d*)?\s*\}\}'?"?/g;
|
|
2888
|
+
var palette = PALETTES[color.name];
|
|
2889
|
+
|
|
2890
|
+
// find and replace simple variables where we use a specific hue, not angentire palette
|
|
2891
|
+
// eg. "{{primary-100}}"
|
|
2892
|
+
//\(' + THEME_COLOR_TYPES.join('\|') + '\)'
|
|
2893
|
+
rules = rules.replace(simpleVariableRegex, function(match, colorType, hue, opacity) {
|
|
2894
|
+
if (colorType === 'foreground') {
|
|
2895
|
+
if (hue == 'shadow') {
|
|
2896
|
+
return theme.foregroundShadow;
|
|
2897
|
+
} else {
|
|
2898
|
+
return theme.foregroundPalette[hue] || theme.foregroundPalette['1'];
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
if (hue.indexOf('hue') === 0) {
|
|
2902
|
+
hue = theme.colors[colorType].hues[hue];
|
|
2903
|
+
}
|
|
2904
|
+
return rgba( (PALETTES[ theme.colors[colorType].name ][hue] || '').value, opacity );
|
|
2905
|
+
});
|
|
2906
|
+
|
|
2907
|
+
// For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3)
|
|
2908
|
+
angular.forEach(color.hues, function(hueValue, hueName) {
|
|
2909
|
+
var newRule = rules
|
|
2910
|
+
.replace(hueRegex, function(match, _, colorType, hueType, opacity) {
|
|
2911
|
+
return rgba(palette[hueValue][hueType === 'color' ? 'value' : 'contrast'], opacity);
|
|
2912
|
+
});
|
|
2913
|
+
if (hueName !== 'default') {
|
|
2914
|
+
newRule = newRule.replace(themeNameRegex, '.md-' + theme.name + '-theme.md-' + hueName);
|
|
2915
|
+
}
|
|
2916
|
+
generatedRules.push(newRule);
|
|
2917
|
+
});
|
|
2918
|
+
|
|
2919
|
+
return generatedRules.join('');
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
// Generate our themes at run time given the state of THEMES and PALETTES
|
|
2923
|
+
function generateThemes($injector) {
|
|
2924
|
+
var themeCss = $injector.has('$MD_THEME_CSS') ? $injector.get('$MD_THEME_CSS') : '';
|
|
2925
|
+
|
|
2926
|
+
// MD_THEME_CSS is a string generated by the build process that includes all the themable
|
|
2927
|
+
// components as templates
|
|
2928
|
+
|
|
2929
|
+
// Expose contrast colors for palettes to ensure that text is always readable
|
|
2930
|
+
angular.forEach(PALETTES, sanitizePalette);
|
|
2931
|
+
|
|
2932
|
+
// Break the CSS into individual rules
|
|
2933
|
+
var rules = themeCss.split(/\}(?!(\}|'|"|;))/)
|
|
2934
|
+
.filter(function(rule) { return rule && rule.length; })
|
|
2935
|
+
.map(function(rule) { return rule.trim() + '}'; });
|
|
2936
|
+
|
|
2937
|
+
var rulesByType = {};
|
|
2938
|
+
THEME_COLOR_TYPES.forEach(function(type) {
|
|
2939
|
+
rulesByType[type] = '';
|
|
2940
|
+
});
|
|
2941
|
+
var ruleMatchRegex = new RegExp('md-(' + THEME_COLOR_TYPES.join('|') + ')', 'g');
|
|
2942
|
+
|
|
2943
|
+
// Sort the rules based on type, allowing us to do color substitution on a per-type basis
|
|
2944
|
+
rules.forEach(function(rule) {
|
|
2945
|
+
var match = rule.match(ruleMatchRegex);
|
|
2946
|
+
// First: test that if the rule has '.md-accent', it goes into the accent set of rules
|
|
2947
|
+
for (var i = 0, type; type = THEME_COLOR_TYPES[i]; i++) {
|
|
2948
|
+
if (rule.indexOf('.md-' + type) > -1) {
|
|
2949
|
+
return rulesByType[type] += rule;
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
// If no eg 'md-accent' class is found, try to just find 'accent' in the rule and guess from
|
|
2954
|
+
// there
|
|
2955
|
+
for (i = 0; type = THEME_COLOR_TYPES[i]; i++) {
|
|
2956
|
+
if (rule.indexOf(type) > -1) {
|
|
2957
|
+
return rulesByType[type] += rule;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
// Default to the primary array
|
|
2962
|
+
return rulesByType[DEFAULT_COLOR_TYPE] += rule;
|
|
2963
|
+
});
|
|
2964
|
+
|
|
2965
|
+
var styleString = '';
|
|
2966
|
+
|
|
2967
|
+
// For each theme, use the color palettes specified for `primary`, `warn` and `accent`
|
|
2968
|
+
// to generate CSS rules.
|
|
2969
|
+
angular.forEach(THEMES, function(theme) {
|
|
2970
|
+
THEME_COLOR_TYPES.forEach(function(colorType) {
|
|
2971
|
+
styleString += parseRules(theme, colorType, rulesByType[colorType] + '');
|
|
2972
|
+
});
|
|
2973
|
+
if (theme.colors.primary.name == theme.colors.accent.name) {
|
|
2974
|
+
console.warn("$mdThemingProvider: Using the same palette for primary and" +
|
|
2975
|
+
"accent. This violates the material design spec.");
|
|
2976
|
+
}
|
|
2977
|
+
});
|
|
2978
|
+
|
|
2979
|
+
// Insert our newly minted styles into the DOM
|
|
2980
|
+
if (!generationIsDone) {
|
|
2981
|
+
var style = document.createElement('style');
|
|
2982
|
+
style.innerHTML = styleString;
|
|
2983
|
+
var head = document.getElementsByTagName('head')[0];
|
|
2984
|
+
head.insertBefore(style, head.firstElementChild);
|
|
2985
|
+
generationIsDone = true;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
// The user specifies a 'default' contrast color as either light or dark,
|
|
2989
|
+
// then explicitly lists which hues are the opposite contrast (eg. A100 has dark, A200 has light)
|
|
2990
|
+
function sanitizePalette(palette) {
|
|
2991
|
+
var defaultContrast = palette.contrastDefaultColor;
|
|
2992
|
+
var lightColors = palette.contrastLightColors || [];
|
|
2993
|
+
var strongLightColors = palette.contrastStrongLightColors || [];
|
|
2994
|
+
var darkColors = palette.contrastDarkColors || [];
|
|
2995
|
+
|
|
2996
|
+
// These colors are provided as space-separated lists
|
|
2997
|
+
if (typeof lightColors === 'string') lightColors = lightColors.split(' ');
|
|
2998
|
+
if (typeof strongLightColors === 'string') strongLightColors = strongLightColors.split(' ');
|
|
2999
|
+
if (typeof darkColors === 'string') darkColors = darkColors.split(' ');
|
|
3000
|
+
|
|
3001
|
+
// Cleanup after ourselves
|
|
3002
|
+
delete palette.contrastDefaultColor;
|
|
3003
|
+
delete palette.contrastLightColors;
|
|
3004
|
+
delete palette.contrastStrongLightColors;
|
|
3005
|
+
delete palette.contrastDarkColors;
|
|
3006
|
+
|
|
3007
|
+
// Change { 'A100': '#fffeee' } to { 'A100': { value: '#fffeee', contrast:DARK_CONTRAST_COLOR }
|
|
3008
|
+
angular.forEach(palette, function(hueValue, hueName) {
|
|
3009
|
+
if (angular.isObject(hueValue)) return; // Already converted
|
|
3010
|
+
// Map everything to rgb colors
|
|
3011
|
+
var rgbValue = colorToRgbaArray(hueValue);
|
|
3012
|
+
if (!rgbValue) {
|
|
3013
|
+
throw new Error("Color %1, in palette %2's hue %3, is invalid. Hex or rgb(a) color expected."
|
|
3014
|
+
.replace('%1', hueValue)
|
|
3015
|
+
.replace('%2', palette.name)
|
|
3016
|
+
.replace('%3', hueName));
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
palette[hueName] = {
|
|
3020
|
+
value: rgbValue,
|
|
3021
|
+
contrast: getContrastColor()
|
|
3022
|
+
};
|
|
3023
|
+
function getContrastColor() {
|
|
3024
|
+
if (defaultContrast === 'light') {
|
|
3025
|
+
if (darkColors.indexOf(hueName) > -1) {
|
|
3026
|
+
return DARK_CONTRAST_COLOR;
|
|
3027
|
+
} else {
|
|
3028
|
+
return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR
|
|
3029
|
+
: LIGHT_CONTRAST_COLOR;
|
|
3030
|
+
}
|
|
3031
|
+
} else {
|
|
3032
|
+
if (lightColors.indexOf(hueName) > -1) {
|
|
3033
|
+
return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR
|
|
3034
|
+
: LIGHT_CONTRAST_COLOR;
|
|
3035
|
+
} else {
|
|
3036
|
+
return DARK_CONTRAST_COLOR;
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
});
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
}
|
|
3044
|
+
generateThemes.$inject = ["$injector"];
|
|
3045
|
+
|
|
3046
|
+
function checkValidPalette(theme, colorType) {
|
|
3047
|
+
// If theme attempts to use a palette that doesnt exist, throw error
|
|
3048
|
+
if (!PALETTES[ (theme.colors[colorType] || {}).name ]) {
|
|
3049
|
+
throw new Error(
|
|
3050
|
+
"You supplied an invalid color palette for theme %1's %2 palette. Available palettes: %3"
|
|
3051
|
+
.replace('%1', theme.name)
|
|
3052
|
+
.replace('%2', colorType)
|
|
3053
|
+
.replace('%3', Object.keys(PALETTES).join(', '))
|
|
3054
|
+
);
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
function colorToRgbaArray(clr) {
|
|
3059
|
+
if (angular.isArray(clr) && clr.length == 3) return clr;
|
|
3060
|
+
if (/^rgb/.test(clr)) {
|
|
3061
|
+
return clr.replace(/(^\s*rgba?\(|\)\s*$)/g, '').split(',').map(function(value, i) {
|
|
3062
|
+
return i == 3 ? parseFloat(value, 10) : parseInt(value, 10);
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
if (clr.charAt(0) == '#') clr = clr.substring(1);
|
|
3066
|
+
if (!/^([a-fA-F0-9]{3}){1,2}$/g.test(clr)) return;
|
|
3067
|
+
|
|
3068
|
+
var dig = clr.length / 3;
|
|
3069
|
+
var red = clr.substr(0, dig);
|
|
3070
|
+
var grn = clr.substr(dig, dig);
|
|
3071
|
+
var blu = clr.substr(dig * 2);
|
|
3072
|
+
if (dig === 1) {
|
|
3073
|
+
red += red;
|
|
3074
|
+
grn += grn;
|
|
3075
|
+
blu += blu;
|
|
3076
|
+
}
|
|
3077
|
+
return [parseInt(red, 16), parseInt(grn, 16), parseInt(blu, 16)];
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3080
|
+
function rgba(rgbArray, opacity) {
|
|
3081
|
+
if (rgbArray.length == 4) {
|
|
3082
|
+
rgbArray = angular.copy(rgbArray);
|
|
3083
|
+
opacity ? rgbArray.pop() : opacity = rgbArray.pop();
|
|
3084
|
+
}
|
|
3085
|
+
return opacity && (typeof opacity == 'number' || (typeof opacity == 'string' && opacity.length)) ?
|
|
3086
|
+
'rgba(' + rgbArray.join(',') + ',' + opacity + ')' :
|
|
3087
|
+
'rgb(' + rgbArray.join(',') + ')';
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
})();
|