├── .bowerrc ├── .gitignore ├── .jshintrc ├── .travis.yml ├── README.md ├── app ├── app.css ├── app.js ├── components │ └── version │ │ ├── interpolate-filter.js │ │ ├── interpolate-filter_test.js │ │ ├── version-directive.js │ │ ├── version-directive_test.js │ │ ├── version.js │ │ └── version_test.js ├── dialog.tmpl.html ├── home │ ├── home.html │ └── home.js ├── img │ └── icons │ │ ├── ic_add_24px.svg │ │ ├── ic_close_24px.svg │ │ ├── ic_done_24px.svg │ │ ├── ic_done_all_24px.svg │ │ ├── ic_menu_24px.svg │ │ └── ic_refresh_24px.svg ├── index.html └── view1 │ ├── view1.html │ └── view1.js ├── bower.json ├── dist ├── .gitkeep ├── app.css ├── app.js ├── components │ └── version │ │ ├── interpolate-filter.js │ │ ├── interpolate-filter_test.js │ │ ├── version-directive.js │ │ ├── version-directive_test.js │ │ ├── version.js │ │ └── version_test.js ├── dialog.tmpl.html ├── home │ ├── home.html │ └── home.js ├── img │ └── icons │ │ ├── ic_add_24px.svg │ │ ├── ic_close_24px.svg │ │ ├── ic_done_24px.svg │ │ ├── ic_done_all_24px.svg │ │ ├── ic_menu_24px.svg │ │ └── ic_refresh_24px.svg ├── index.html ├── view1 │ ├── view1.html │ ├── view1.js │ └── view1_test.js └── view2 │ ├── view2.html │ ├── view2.js │ └── view2_test.js ├── e2e-tests ├── protractor.conf.js └── scenarios.js ├── karma.conf.js └── package.json /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/* 2 | !.gitkeep 3 | node_modules/ 4 | bower_components/ 5 | tmp 6 | .DS_Store 7 | .idea -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globalstrict": true, 3 | "globals": { 4 | "angular": false, 5 | "describe": false, 6 | "it": false, 7 | "expect": false, 8 | "beforeEach": false, 9 | "afterEach": false, 10 | "module": false, 11 | "inject": false 12 | } 13 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | 5 | before_script: 6 | - export DISPLAY=:99.0 7 | - sh -e /etc/init.d/xvfb start 8 | - npm start > /dev/null & 9 | - npm run update-webdriver 10 | - sleep 1 # give server time to start 11 | 12 | script: 13 | - node_modules/.bin/karma start karma.conf.js --no-auto-watch --single-run --reporters=dots --browsers=Firefox 14 | - node_modules/.bin/protractor e2e-tests/protractor.conf.js --browser=firefox 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | material-angular-demo-project 2 | ============================= 3 | 4 | Проект для демонстрации material-angular 5 | 6 | ### Install Dependencies 7 | 8 | We have two kinds of dependencies in this project: tools and angular framework code. The tools help 9 | us manage and test the application. 10 | 11 | * We get the tools we depend upon via `npm`, the [node package manager][npm]. 12 | * We get the angular code via `bower`, a [client-side code package manager][bower]. 13 | 14 | We have preconfigured `npm` to automatically run `bower` so we can simply do: 15 | 16 | ``` 17 | npm install 18 | ``` 19 | 20 | Behind the scenes this will also call `bower install`. You should find that you have two new 21 | folders in your project. 22 | 23 | * `node_modules` - contains the npm packages for the tools we need 24 | * `app/bower_components` - contains the angular framework files 25 | 26 | *Note that the `bower_components` folder would normally be installed in the root folder but 27 | angular-seed changes this location through the `.bowerrc` file. Putting it in the app folder makes 28 | it easier to serve the files by a webserver.* 29 | 30 | ### Run the Application 31 | 32 | We have preconfigured the project with a simple development web server. The simplest way to start 33 | this server is: 34 | 35 | ``` 36 | npm start 37 | ``` 38 | 39 | Now browse to the app at `http://localhost:8888/app/index.html`. 40 | 41 | 42 | The angular-seed app comes with end-to-end tests, again written in [Jasmine][jasmine]. These tests 43 | are run with the [Protractor][protractor] End-to-End test runner. It uses native events and has 44 | special features for Angular applications. 45 | 46 | * the configuration is found at `e2e-tests/protractor-conf.js` 47 | * the end-to-end tests are found in `e2e-tests/scenarios.js` 48 | 49 | Protractor simulates interaction with our web app and verifies that the application responds 50 | correctly. Therefore, our web server needs to be serving up the application, so that Protractor 51 | can interact with it. 52 | 53 | ``` 54 | npm start 55 | ``` 56 | 57 | In addition, since Protractor is built upon WebDriver we need to install this. The angular-seed 58 | project comes with a predefined script to do this: 59 | 60 | ``` 61 | npm run update-webdriver 62 | ``` 63 | 64 | This will download and install the latest version of the stand-alone WebDriver tool. 65 | 66 | Once you have ensured that the development web server hosting our application is up and running 67 | and WebDriver is updated, you can run the end-to-end tests using the supplied npm script: 68 | 69 | ``` 70 | npm run protractor 71 | ``` 72 | 73 | This script will execute the end-to-end tests against the application being hosted on the 74 | development server. 75 | 76 | 77 | ## Updating Angular 78 | 79 | Previously we recommended that you merge in changes to angular-seed into your own fork of the project. 80 | Now that the angular framework library code and tools are acquired through package managers (npm and 81 | bower) you can use these tools instead to update the dependencies. 82 | 83 | You can update the tool dependencies by running: 84 | 85 | ``` 86 | npm update 87 | ``` 88 | 89 | This will find the latest versions that match the version ranges specified in the `package.json` file. 90 | 91 | You can update the Angular dependencies by running: 92 | 93 | ``` 94 | bower update 95 | ``` 96 | 97 | This will find the latest versions that match the version ranges specified in the `bower.json` file. 98 | 99 | 100 | ## Loading Angular Asynchronously 101 | 102 | The angular-seed project supports loading the framework and application scripts asynchronously. The 103 | special `index-async.html` is designed to support this style of loading. For it to work you must 104 | inject a piece of Angular JavaScript into the HTML page. The project has a predefined script to help 105 | do this. 106 | 107 | ``` 108 | npm run update-index-async 109 | ``` 110 | 111 | This will copy the contents of the `angular-loader.js` library file into the `index-async.html` page. 112 | You can run this every time you update the version of Angular that you are using. 113 | 114 | 115 | ## Serving the Application Files 116 | 117 | While angular is client-side-only technology and it's possible to create angular webapps that 118 | don't require a backend server at all, we recommend serving the project files using a local 119 | webserver during development to avoid issues with security restrictions (sandbox) in browsers. The 120 | sandbox implementation varies between browsers, but quite often prevents things like cookies, xhr, 121 | etc to function properly when an html page is opened via `file://` scheme instead of `http://`. 122 | 123 | 124 | ### Running the App during Development 125 | 126 | The angular-seed project comes preconfigured with a local development webserver. It is a node.js 127 | tool called [http-server][http-server]. You can start this webserver with `npm start` but you may choose to 128 | install the tool globally: 129 | 130 | ``` 131 | sudo npm install -g http-server 132 | ``` 133 | 134 | Then you can start your own development web server to serve static files from a folder by 135 | running: 136 | 137 | ``` 138 | http-server -a localhost -p 8888 139 | ``` 140 | 141 | Alternatively, you can choose to configure your own webserver, such as apache or nginx. Just 142 | configure your server to serve the files under the `app/` directory. 143 | 144 | 145 | ### Running the App in Production 146 | 147 | This really depends on how complex your app is and the overall infrastructure of your system, but 148 | the general rule is that all you need in production are all the files under the `app/` directory. 149 | Everything else should be omitted. 150 | 151 | Angular apps are really just a bunch of static html, css and js files that just need to be hosted 152 | somewhere they can be accessed by browsers. 153 | 154 | If your Angular app is talking to the backend server via xhr or other means, you need to figure 155 | out what is the best way to host the static files to comply with the same origin policy if 156 | applicable. Usually this is done by hosting the files by the backend server or through 157 | reverse-proxying the backend server(s) and webserver(s). 158 | 159 | 160 | ## Continuous Integration 161 | 162 | ### Travis CI 163 | 164 | [Travis CI][travis] is a continuous integration service, which can monitor GitHub for new commits 165 | to your repository and execute scripts such as building the app or running tests. The angular-seed 166 | project contains a Travis configuration file, `.travis.yml`, which will cause Travis to run your 167 | tests when you push to GitHub. 168 | 169 | You will need to enable the integration between Travis and GitHub. See the Travis website for more 170 | instruction on how to do this. 171 | 172 | ### CloudBees 173 | 174 | CloudBees have provided a CI/deployment setup: 175 | 176 | 177 | 178 | 179 | If you run this, you will get a cloned version of this repo to start working on in a private git repo, 180 | along with a CI service (in Jenkins) hosted that will run unit and end to end tests in both Firefox and Chrome. 181 | 182 | 183 | ## Contact 184 | 185 | For more information on AngularJS please check out http://angularjs.org/ 186 | 187 | [git]: http://git-scm.com/ 188 | [bower]: http://bower.io 189 | [npm]: https://www.npmjs.org/ 190 | [node]: http://nodejs.org 191 | [protractor]: https://github.com/angular/protractor 192 | [jasmine]: http://jasmine.github.io 193 | [karma]: http://karma-runner.github.io 194 | [travis]: https://travis-ci.org/ 195 | [http-server]: https://github.com/nodeapps/http-server 196 | -------------------------------------------------------------------------------- /app/app.css: -------------------------------------------------------------------------------- 1 | /* app css stylesheet */ 2 | body { 3 | height: none; 4 | background-color: #E7E7E7; 5 | } 6 | 7 | .box { 8 | width: 200px; 9 | height: 200px; 10 | background-color: yellow; 11 | 12 | } 13 | 14 | .fix-top { 15 | position: fixed; 16 | top:0; 17 | } 18 | 19 | .nornal-btn { 20 | width: 56px; 21 | height: 56px; 22 | } 23 | 24 | .nornal-round-btn { 25 | width: 56px; 26 | height: 56px; 27 | border-radius: 50%; 28 | } 29 | 30 | .float-btn { 31 | height:56px; 32 | width: 56px; 33 | position: fixed; 34 | bottom: 55px; 35 | right: 55px; 36 | } 37 | 38 | md-whiteframe { 39 | background: #fff; 40 | margin: 20px; 41 | padding: 20px; 42 | } 43 | 44 | .check { 45 | background-color: #E8EAF6; 46 | } 47 | .left-box { 48 | width:56px; height: 56px; padding:0; background-color: gray; border-radius: 50%; 49 | } 50 | .active-checkbox { 51 | background-color: transparent !important; 52 | } 53 | 54 | core-tooltip.fancy::shadow .core-tooltip { 55 | opacity: 0; 56 | -webkit-transition: all 300ms cubic-bezier(0,1.92,.99,1.07); 57 | transition: all 300ms cubic-bezier(0,1.92,.99,1.07); 58 | -webkit-transform: translate3d(0, -10px, 0); 59 | transform: translate3d(0, -10px, 0); 60 | } 61 | 62 | core-tooltip.fancy:hover::shadow .core-tooltip, 63 | core-tooltip.fancy:focus::shadow .core-tooltip { 64 | opacity: 1; 65 | -webkit-transform: translate3d(0, 0, 0); 66 | transform: translate3d(0, 0, 0); 67 | } 68 | 69 | .sample-show-hide { 70 | 71 | } 72 | 73 | .sample-show-hide { 74 | -webkit-transition:all linear 0.5s; 75 | transition:all linear 0.5s; 76 | } 77 | 78 | .sample-show-hide.ng-hide { 79 | opacity:0; 80 | } 81 | 82 | 83 | .md-subheader { 84 | background-color: #dcedc8; 85 | 86 | } 87 | h2.md-subheader { 88 | margin: 0px; 89 | margin-left: -24px; 90 | margin-right: -24px; 91 | margin-top: -24px; } 92 | h2.md-subheader.md-sticky-clone { 93 | margin-right: 0px; 94 | margin-top: 0px; 95 | box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); } 96 | h2 .md-subheader-content { 97 | padding-left: 10px; } 98 | 99 | 100 | 101 | md-backdrop { 102 | position: fixed !important; 103 | } 104 | 105 | md-toast { 106 | position: fixed !important; 107 | 108 | } 109 | 110 | md-sidenav { 111 | position: fixed !important; 112 | } 113 | 114 | md-tooltip { 115 | position: fixed !important; 116 | } 117 | 118 | .menu-item { 119 | background: none; 120 | border-width: 0; 121 | cursor: pointer; 122 | display: block; 123 | color: #333; 124 | font-size: inherit; 125 | line-height: 40px; 126 | max-height: 40px; 127 | opacity: 1; 128 | margin: 0; 129 | outline: none; 130 | padding: 0px 28px; 131 | position: relative; 132 | text-align: left; 133 | text-decoration: none; 134 | width: 100%; 135 | z-index: 1; 136 | -webkit-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 137 | -webkit-transition-property: max-height, background-color, opacity; 138 | -moz-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 139 | -moz-transition-property: max-height, background-color, opacity; 140 | transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 141 | transition-property: max-height, background-color, opacity; 142 | } 143 | .menu-item.ng-hide { 144 | max-height: 0; 145 | opacity: 0; 146 | } 147 | .menu-item:hover { 148 | color: #999; 149 | } 150 | .menu-item:focus { 151 | font-weight: bold; 152 | } 153 | .menu-item.menu-title { 154 | color: #888; 155 | font-size: 14px; 156 | padding-left: 16px; 157 | text-align: left; 158 | text-transform: uppercase; 159 | transition: color 0.35s cubic-bezier(0.35, 0, 0.25, 1); 160 | } 161 | .menu-item.menu-title:hover, 162 | .menu-item.menu-title.active { 163 | color: #1976d2; 164 | } 165 | 166 | .menu-icon { 167 | background: none; 168 | border: none; 169 | } 170 | 171 | .menu-separator-icon { 172 | margin: 0; 173 | } 174 | .menu-module-name { 175 | opacity: 0.6; 176 | font-size: 18px; 177 | } 178 | 179 | .list-cont { 180 | background-color: #E7E7E7 !important; 181 | max-width: 800px; 182 | margin: 0 auto; 183 | height: 100%; 184 | overflow: hidden; 185 | } 186 | 187 | .list-cb { 188 | margin: 0; 189 | position: relative; 190 | top: 15px; 191 | left: 19px; 192 | } 193 | 194 | .list-check-area { 195 | width:56px; 196 | height: 56px; 197 | padding:0; 198 | margin-right: 10px; 199 | } -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Declare app level module which depends on views, and components 4 | angular.module('myApp', [ 5 | 'ngRoute', 6 | 'myApp.view1', 7 | 'myApp.home', 8 | 'myApp.version', 9 | 'ngMaterial' 10 | ]). 11 | config(['$routeProvider', function($routeProvider) { 12 | $routeProvider.otherwise({redirectTo: '/home'}); 13 | }]) 14 | 15 | .controller('MainCtrl', function($scope, $timeout, $mdSidenav) { 16 | $scope.toggleRight = function() { 17 | $mdSidenav('left').toggle(); 18 | }; 19 | 20 | $scope.menu = {}; 21 | $scope.menu.pages = [ 22 | {"url": "/home", "discription":"Главная"}, 23 | {"url": "/view1", "discription":"Список дел"} 24 | 25 | ]; 26 | 27 | $scope.menu.isPageSelected = function(page) { 28 | return ($scope.menu.currentPage === page); 29 | }; 30 | 31 | $scope.menu.toggleSelectPage = function(page) { 32 | $scope.menu.currentPage = page; 33 | }; 34 | }) 35 | 36 | .controller('LeftCtrl', function($scope, $timeout, $mdSidenav) { 37 | $scope.close = function() { 38 | $mdSidenav('left').close(); 39 | }; 40 | }); -------------------------------------------------------------------------------- /app/components/version/interpolate-filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version.interpolate-filter', []) 4 | 5 | .filter('interpolate', ['version', function(version) { 6 | return function(text) { 7 | return String(text).replace(/\%VERSION\%/mg, version); 8 | }; 9 | }]); 10 | -------------------------------------------------------------------------------- /app/components/version/interpolate-filter_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('interpolate filter', function() { 7 | beforeEach(module(function($provide) { 8 | $provide.value('version', 'TEST_VER'); 9 | })); 10 | 11 | it('should replace VERSION', inject(function(interpolateFilter) { 12 | expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after'); 13 | })); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /app/components/version/version-directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version.version-directive', []) 4 | 5 | .directive('appVersion', ['version', function(version) { 6 | return function(scope, elm, attrs) { 7 | elm.text(version); 8 | }; 9 | }]); 10 | -------------------------------------------------------------------------------- /app/components/version/version-directive_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('app-version directive', function() { 7 | it('should print current version', function() { 8 | module(function($provide) { 9 | $provide.value('version', 'TEST_VER'); 10 | }); 11 | inject(function($compile, $rootScope) { 12 | var element = $compile('')($rootScope); 13 | expect(element.text()).toEqual('TEST_VER'); 14 | }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /app/components/version/version.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version', [ 4 | 'myApp.version.interpolate-filter', 5 | 'myApp.version.version-directive' 6 | ]) 7 | 8 | .value('version', '0.1'); 9 | -------------------------------------------------------------------------------- /app/components/version/version_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('version service', function() { 7 | it('should return current version', inject(function(version) { 8 | expect(version).toEqual('0.1'); 9 | })); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /app/dialog.tmpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Добавить 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |

15 | Цвет       16 |

17 |
18 |
19 | R 20 |
21 | 22 | 23 | 24 |
25 |
26 |
27 | G 28 |
29 | 30 | 31 | 32 |
33 |
34 |
35 | B 36 |
37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 |
46 |
47 | 48 | Отмена 49 | 50 | 51 | Добавить 52 | 53 |
54 |
-------------------------------------------------------------------------------- /app/home/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Это простая демонстрация разработки Angular приложения в стиле Material Design с библиотеки Material Angular

4 |

Внимание!: В данном приложении не содержится никакой серверной части, поэтому все изменения не будут сохраняться.

5 |

Приложение служит только для демонстрации

6 |

Переходите в 'Список дел', там Вы можете добавлять, удалять задачи, можете выбирать несколько задач сразу

7 |
8 |
-------------------------------------------------------------------------------- /app/home/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.home', ['ngRoute','ngMaterial']) 4 | 5 | .config(['$routeProvider', function($routeProvider) { 6 | $routeProvider.when('/home', { 7 | templateUrl: 'home/home.html', 8 | controller: 'HomeCtrl' 9 | }); 10 | }]) 11 | 12 | .controller('HomeCtrl', function($scope) { 13 | 14 | }); -------------------------------------------------------------------------------- /app/img/icons/ic_add_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/img/icons/ic_close_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/img/icons/ic_done_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/img/icons/ic_done_all_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/img/icons/ic_menu_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/img/icons/ic_refresh_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TODO list 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | Меню 46 | 47 | 48 | 49 | Список задач 50 |
51 |
52 | 53 | 54 |
55 | 56 | 57 |
58 | 59 |

Меню

60 |
61 | 62 | 63 | {{page.discription}} 64 | 65 | 66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /app/view1/view1.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |

6 | 7 | 8 | Назад 9 | 10 | 11 | 12 | 13 | Выбранно элементов: {{countSelected}} 14 |
15 | 16 | 17 | В архив 18 | 19 | 20 | 21 | 22 |

23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 |
42 |

{{item.what}}

43 |

{{item.who}}

44 |

45 | {{item.notes}} 46 |

47 |
48 | 49 |
50 | 51 | 52 | 53 | 54 | В архив 55 | 56 | 57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 | 65 | 66 |
67 | 68 | 69 | Добавить 70 | 71 | 72 | 73 |
74 |
-------------------------------------------------------------------------------- /app/view1/view1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.view1', ['ngRoute','ngMaterial']) 4 | 5 | .config(['$routeProvider', function($routeProvider) { 6 | $routeProvider.when('/view1', { 7 | templateUrl: 'view1/view1.html', 8 | controller: 'View1Ctrl' 9 | }); 10 | }]) 11 | 12 | .controller('View1Ctrl', function($scope, $mdDialog, $mdToast, $animate) { 13 | 14 | $scope.todos = [ 15 | { 16 | color: { 17 | red: 125, 18 | green: 5, 19 | blue: 50 20 | }, 21 | what: 'Brunch this weekend?', 22 | when: '3:08PM', 23 | notes: " I'll be in your neighborhood doing errands", 24 | check: false, 25 | show: false, 26 | visible: true, // для анимации удаления 27 | btns: false 28 | }, 29 | { 30 | color: { 31 | red: 125, 32 | green: 225, 33 | blue: 0 34 | }, 35 | what: 'Brunch this weekend?', 36 | when: '3:08PM', 37 | notes: " I'll be in your neighborhood doing errands", 38 | check: false, 39 | show: false, 40 | visible: true, 41 | btns: false 42 | }, 43 | { 44 | color: { 45 | red: 25, 46 | green: 15, 47 | blue: 50 48 | }, 49 | what: 'Brunch this weekend?', 50 | when: '3:08PM', 51 | notes: " I'll be in your neighborhood doing errands", 52 | check: false, 53 | show: false, 54 | visible: true, 55 | btns: false 56 | }, 57 | { 58 | color: { 59 | red: 125, 60 | green: 5, 61 | blue: 150 62 | }, 63 | what: 'Brunch this weekend?', 64 | when: '3:08PM', 65 | notes: " I'll be in your neighborhood doing errands", 66 | check: false, 67 | show: false, 68 | visible: true, 69 | btns: false 70 | }, 71 | { 72 | color: { 73 | red: 25, 74 | green: 5, 75 | blue: 150 76 | }, 77 | what: 'Brunch this weekend?', 78 | when: '3:08PM', 79 | notes: " I'll be in your neighborhood doing errands", 80 | check: false, 81 | show: false, 82 | visible: true, 83 | btns: false 84 | }, 85 | ] 86 | 87 | 88 | $scope.showItem = function(item ) { 89 | item.show = true; 90 | }; 91 | 92 | $scope.hideItem = function(item ) { 93 | item.show = false; 94 | }; 95 | 96 | $scope.countSelected = 0; 97 | $scope.oneSelected= false; 98 | 99 | $scope.deselectAll = function(item) { 100 | 101 | $scope.todos.forEach( function(element) { 102 | 103 | decheck(element); 104 | }); 105 | 106 | if($scope.countSelected>0) { 107 | $scope.oneSelected = true; 108 | } else { 109 | $scope.oneSelected = false; 110 | } 111 | } 112 | 113 | $scope.remove = function(item) { 114 | item.visible = false; 115 | var idx = $scope.todos.indexOf(item); 116 | 117 | 118 | 119 | setTimeout( function() { 120 | $scope.todos.splice(idx,1); 121 | 122 | $mdToast.show( 123 | $mdToast.simple() 124 | .content('Запись отправлена в архив') 125 | .position($scope.getToastPosition()) 126 | .hideDelay(3000) 127 | ); 128 | 129 | 130 | $scope.countSelected = 0; 131 | } ,1000); 132 | 133 | }; 134 | 135 | $scope.toastPosition = { 136 | bottom: true, 137 | top: false, 138 | left: true, 139 | right: false 140 | }; 141 | 142 | $scope.getToastPosition = function() { 143 | return Object.keys($scope.toastPosition) 144 | .filter(function(pos) { return $scope.toastPosition[pos]; }) 145 | .join(' '); 146 | }; 147 | 148 | $scope.archiveAll = function () { 149 | 150 | //Здесь должен выполняться запросс на удаление 151 | var newTodos = []; 152 | $scope.todos.forEach(function(item){ 153 | if(item.check ===false){ 154 | 155 | } else { 156 | item.visible = false; 157 | } 158 | }); 159 | 160 | 161 | setTimeout( function() { 162 | $scope.todos.forEach(function(item){ 163 | if(item.check ===false){ 164 | newTodos.push(item); 165 | } 166 | }); 167 | 168 | 169 | $scope.todos = newTodos; 170 | 171 | 172 | $mdToast.show( 173 | $mdToast.simple() 174 | .content('Отправленно в архив записей: ' + $scope.countSelected) 175 | .position($scope.getToastPosition()) 176 | .hideDelay(3000) 177 | ); 178 | 179 | 180 | $scope.countSelected = 0; 181 | 182 | } ,1000); 183 | 184 | $scope.oneSelected = false; 185 | 186 | } 187 | 188 | function decheck(item) { 189 | if(item.check===true) { 190 | $scope.countSelected--; 191 | } 192 | 193 | item.check=false; 194 | } 195 | 196 | $scope.oneCheck = function(item) { 197 | 198 | 199 | if(item.check===true) { 200 | $scope.countSelected++; 201 | } else { 202 | $scope.countSelected--; 203 | } 204 | 205 | if($scope.countSelected>0) { 206 | $scope.oneSelected = true; 207 | } else { 208 | $scope.oneSelected = false; 209 | } 210 | }; 211 | 212 | $scope.showAlert = function(ev) { 213 | 214 | $mdDialog.show({ 215 | controller: DialogController, 216 | templateUrl: 'dialog.tmpl.html', 217 | targetEvent: ev, 218 | }) 219 | .then(function(answer) { 220 | 221 | 222 | var item = { 223 | 224 | color: answer.color, 225 | what: answer.what, 226 | when: answer.when, 227 | notes: answer.notes, 228 | check: false, 229 | show: false, 230 | visible: true 231 | }; 232 | 233 | $scope.todos.unshift(item); 234 | 235 | 236 | $mdToast.show( 237 | $mdToast.simple() 238 | .content('Задание добавлено') 239 | .position($scope.getToastPosition()) 240 | .hideDelay(3000) 241 | ); 242 | 243 | }, function() { 244 | /* 'You cancelled the dialog.';*/ 245 | }); 246 | }; 247 | 248 | }); 249 | 250 | function DialogController($scope, $mdDialog) { 251 | 252 | $scope.todo = {}; 253 | 254 | $scope.todo.color = { 255 | red: Math.floor(Math.random() * 255), 256 | green: Math.floor(Math.random() * 255), 257 | blue: Math.floor(Math.random() * 255) 258 | }; 259 | 260 | $scope.hide = function() { 261 | $mdDialog.hide(); 262 | }; 263 | $scope.cancel = function() { 264 | $mdDialog.cancel(); 265 | }; 266 | $scope.answer = function(answer) { 267 | $mdDialog.hide(answer); 268 | }; 269 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material angular demo", 3 | "description": "Material angular demo project", 4 | "version": "0.0.0", 5 | "homepage": "https://github.com/nesterione/material-angular-demo-project", 6 | "private": true, 7 | "dependencies": { 8 | "angular": "1.3.x", 9 | "angular-route": "1.3.x", 10 | "angular-loader": "1.3.x", 11 | "angular-mocks": "~1.3.x", 12 | "html5-boilerplate": "~4.3.0", 13 | "angular-material":"" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesterione/material-angular-demo-project/e252a895166858fdcffb1f0269d90d457120ceb7/dist/.gitkeep -------------------------------------------------------------------------------- /dist/app.css: -------------------------------------------------------------------------------- 1 | /* app css stylesheet */ 2 | body { 3 | height: none; 4 | background-color: #E7E7E7; 5 | } 6 | 7 | .box { 8 | width: 200px; 9 | height: 200px; 10 | background-color: yellow; 11 | 12 | } 13 | 14 | .fix-top { 15 | position: fixed; 16 | top:0; 17 | } 18 | 19 | .nornal-btn { 20 | width: 56px; 21 | height: 56px; 22 | } 23 | 24 | .nornal-round-btn { 25 | width: 56px; 26 | height: 56px; 27 | border-radius: 50%; 28 | } 29 | 30 | .float-btn { 31 | height:56px; 32 | width: 56px; 33 | position: fixed; 34 | bottom: 55px; 35 | right: 55px; 36 | } 37 | 38 | md-whiteframe { 39 | background: #fff; 40 | margin: 20px; 41 | padding: 20px; 42 | } 43 | 44 | .check { 45 | background-color: #E8EAF6; 46 | } 47 | .left-box { 48 | width:56px; height: 56px; padding:0; background-color: gray; border-radius: 50%; 49 | } 50 | .active-checkbox { 51 | background-color: transparent !important; 52 | } 53 | 54 | core-tooltip.fancy::shadow .core-tooltip { 55 | opacity: 0; 56 | -webkit-transition: all 300ms cubic-bezier(0,1.92,.99,1.07); 57 | transition: all 300ms cubic-bezier(0,1.92,.99,1.07); 58 | -webkit-transform: translate3d(0, -10px, 0); 59 | transform: translate3d(0, -10px, 0); 60 | } 61 | 62 | core-tooltip.fancy:hover::shadow .core-tooltip, 63 | core-tooltip.fancy:focus::shadow .core-tooltip { 64 | opacity: 1; 65 | -webkit-transform: translate3d(0, 0, 0); 66 | transform: translate3d(0, 0, 0); 67 | } 68 | 69 | .sample-show-hide { 70 | 71 | } 72 | 73 | .sample-show-hide { 74 | -webkit-transition:all linear 0.5s; 75 | transition:all linear 0.5s; 76 | } 77 | 78 | .sample-show-hide.ng-hide { 79 | opacity:0; 80 | } 81 | 82 | 83 | .md-subheader { 84 | background-color: #dcedc8; 85 | 86 | } 87 | h2.md-subheader { 88 | margin: 0px; 89 | margin-left: -24px; 90 | margin-right: -24px; 91 | margin-top: -24px; } 92 | h2.md-subheader.md-sticky-clone { 93 | margin-right: 0px; 94 | margin-top: 0px; 95 | box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); } 96 | h2 .md-subheader-content { 97 | padding-left: 10px; } 98 | 99 | 100 | 101 | md-backdrop { 102 | position: fixed !important; 103 | } 104 | 105 | md-toast { 106 | position: fixed !important; 107 | 108 | } 109 | 110 | md-sidenav { 111 | position: fixed !important; 112 | } 113 | 114 | md-tooltip { 115 | position: fixed !important; 116 | } 117 | 118 | .menu-item { 119 | background: none; 120 | border-width: 0; 121 | cursor: pointer; 122 | display: block; 123 | color: #333; 124 | font-size: inherit; 125 | line-height: 40px; 126 | max-height: 40px; 127 | opacity: 1; 128 | margin: 0; 129 | outline: none; 130 | padding: 0px 28px; 131 | position: relative; 132 | text-align: left; 133 | text-decoration: none; 134 | width: 100%; 135 | z-index: 1; 136 | -webkit-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 137 | -webkit-transition-property: max-height, background-color, opacity; 138 | -moz-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 139 | -moz-transition-property: max-height, background-color, opacity; 140 | transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1); 141 | transition-property: max-height, background-color, opacity; 142 | } 143 | .menu-item.ng-hide { 144 | max-height: 0; 145 | opacity: 0; 146 | } 147 | .menu-item:hover { 148 | color: #999; 149 | } 150 | .menu-item:focus { 151 | font-weight: bold; 152 | } 153 | .menu-item.menu-title { 154 | color: #888; 155 | font-size: 14px; 156 | padding-left: 16px; 157 | text-align: left; 158 | text-transform: uppercase; 159 | transition: color 0.35s cubic-bezier(0.35, 0, 0.25, 1); 160 | } 161 | .menu-item.menu-title:hover, 162 | .menu-item.menu-title.active { 163 | color: #1976d2; 164 | } 165 | 166 | .menu-icon { 167 | background: none; 168 | border: none; 169 | } 170 | 171 | .menu-separator-icon { 172 | margin: 0; 173 | } 174 | .menu-module-name { 175 | opacity: 0.6; 176 | font-size: 18px; 177 | } 178 | 179 | .list-cont { 180 | background-color: #E7E7E7 !important; 181 | max-width: 800px; 182 | margin: 0 auto; 183 | height: 100%; 184 | overflow: hidden; 185 | } 186 | 187 | .list-cb { 188 | margin: 0; 189 | position: relative; 190 | top: 15px; 191 | left: 19px; 192 | } 193 | 194 | .list-check-area { 195 | width:56px; 196 | height: 56px; 197 | padding:0; 198 | margin-right: 10px; 199 | } -------------------------------------------------------------------------------- /dist/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Declare app level module which depends on views, and components 4 | angular.module('myApp', [ 5 | 'ngRoute', 6 | 'myApp.view1', 7 | 'myApp.home', 8 | 'myApp.version', 9 | 'ngMaterial' 10 | ]). 11 | config(['$routeProvider', function($routeProvider) { 12 | $routeProvider.otherwise({redirectTo: '/home'}); 13 | }]) 14 | 15 | .controller('MainCtrl', function($scope, $timeout, $mdSidenav) { 16 | $scope.toggleRight = function() { 17 | $mdSidenav('left').toggle(); 18 | }; 19 | 20 | $scope.menu = {}; 21 | $scope.menu.pages = [ 22 | {"url": "/home", "discription":"Главная"}, 23 | {"url": "/view1", "discription":"Список дел"} 24 | 25 | ]; 26 | 27 | $scope.menu.isPageSelected = function(page) { 28 | return ($scope.menu.currentPage === page); 29 | }; 30 | 31 | $scope.menu.toggleSelectPage = function(page) { 32 | $scope.menu.currentPage = page; 33 | }; 34 | }) 35 | 36 | .controller('LeftCtrl', function($scope, $timeout, $mdSidenav) { 37 | $scope.close = function() { 38 | $mdSidenav('left').close(); 39 | }; 40 | }); -------------------------------------------------------------------------------- /dist/components/version/interpolate-filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version.interpolate-filter', []) 4 | 5 | .filter('interpolate', ['version', function(version) { 6 | return function(text) { 7 | return String(text).replace(/\%VERSION\%/mg, version); 8 | }; 9 | }]); 10 | -------------------------------------------------------------------------------- /dist/components/version/interpolate-filter_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('interpolate filter', function() { 7 | beforeEach(module(function($provide) { 8 | $provide.value('version', 'TEST_VER'); 9 | })); 10 | 11 | it('should replace VERSION', inject(function(interpolateFilter) { 12 | expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after'); 13 | })); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /dist/components/version/version-directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version.version-directive', []) 4 | 5 | .directive('appVersion', ['version', function(version) { 6 | return function(scope, elm, attrs) { 7 | elm.text(version); 8 | }; 9 | }]); 10 | -------------------------------------------------------------------------------- /dist/components/version/version-directive_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('app-version directive', function() { 7 | it('should print current version', function() { 8 | module(function($provide) { 9 | $provide.value('version', 'TEST_VER'); 10 | }); 11 | inject(function($compile, $rootScope) { 12 | var element = $compile('')($rootScope); 13 | expect(element.text()).toEqual('TEST_VER'); 14 | }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /dist/components/version/version.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.version', [ 4 | 'myApp.version.interpolate-filter', 5 | 'myApp.version.version-directive' 6 | ]) 7 | 8 | .value('version', '0.1'); 9 | -------------------------------------------------------------------------------- /dist/components/version/version_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.version module', function() { 4 | beforeEach(module('myApp.version')); 5 | 6 | describe('version service', function() { 7 | it('should return current version', inject(function(version) { 8 | expect(version).toEqual('0.1'); 9 | })); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /dist/dialog.tmpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Добавить 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |

15 | Цвет       16 |

17 |
18 |
19 | R 20 |
21 | 22 | 23 | 24 |
25 |
26 |
27 | G 28 |
29 | 30 | 31 | 32 |
33 |
34 |
35 | B 36 |
37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 |
46 |
47 | 48 | Отмена 49 | 50 | 51 | Добавить 52 | 53 |
54 |
-------------------------------------------------------------------------------- /dist/home/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Это простая демонстрация разработки Angular приложения в стиле Material Design с библиотеки Material Angular

4 |

Внимание!: В данном приложении не содержится никакой серверной части, поэтому все изменения не будут сохраняться.

5 |

Приложение служит только для демонстрации

6 |

Переходите в 'Список дел', там Вы можете добавлять, удалять задачи, можете выбирать несколько задач сразу

7 |
8 |
-------------------------------------------------------------------------------- /dist/home/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.home', ['ngRoute','ngMaterial']) 4 | 5 | .config(['$routeProvider', function($routeProvider) { 6 | $routeProvider.when('/home', { 7 | templateUrl: 'home/home.html', 8 | controller: 'HomeCtrl' 9 | }); 10 | }]) 11 | 12 | .controller('HomeCtrl', function($scope) { 13 | 14 | }); -------------------------------------------------------------------------------- /dist/img/icons/ic_add_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /dist/img/icons/ic_close_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /dist/img/icons/ic_done_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dist/img/icons/ic_done_all_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /dist/img/icons/ic_menu_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /dist/img/icons/ic_refresh_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TODO list 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | Меню 46 | 47 | 48 | 49 | Список задач 50 |
51 |
52 | 53 | 54 |
55 | 56 | 57 |
58 | 59 |

Меню

60 |
61 | 62 | 63 | {{page.discription}} 64 | 65 | 66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /dist/view1/view1.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |

6 | 7 | 8 | Назад 9 | 10 | 11 | 12 | 13 | Выбранно элементов: {{countSelected}} 14 |
15 | 16 | 17 | В архив 18 | 19 | 20 | 21 | 22 |

23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 |
42 |

{{item.what}}

43 |

{{item.who}}

44 |

45 | {{item.notes}} 46 |

47 |
48 | 49 |
50 | 51 | 52 | 53 | 54 | В архив 55 | 56 | 57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 | 65 | 66 |
67 | 68 | 69 | Добавить 70 | 71 | 72 | 73 |
74 |
-------------------------------------------------------------------------------- /dist/view1/view1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.view1', ['ngRoute','ngMaterial']) 4 | 5 | .config(['$routeProvider', function($routeProvider) { 6 | $routeProvider.when('/view1', { 7 | templateUrl: 'view1/view1.html', 8 | controller: 'View1Ctrl' 9 | }); 10 | }]) 11 | 12 | .controller('View1Ctrl', function($scope, $mdDialog, $mdToast, $animate) { 13 | 14 | $scope.todos = [ 15 | { 16 | color: { 17 | red: 125, 18 | green: 5, 19 | blue: 50 20 | }, 21 | what: 'Brunch this weekend?', 22 | when: '3:08PM', 23 | notes: " I'll be in your neighborhood doing errands", 24 | check: false, 25 | show: false, 26 | visible: true, // для анимации удаления 27 | btns: false 28 | }, 29 | { 30 | color: { 31 | red: 125, 32 | green: 225, 33 | blue: 0 34 | }, 35 | what: 'Brunch this weekend?', 36 | when: '3:08PM', 37 | notes: " I'll be in your neighborhood doing errands", 38 | check: false, 39 | show: false, 40 | visible: true, 41 | btns: false 42 | }, 43 | { 44 | color: { 45 | red: 25, 46 | green: 15, 47 | blue: 50 48 | }, 49 | what: 'Brunch this weekend?', 50 | when: '3:08PM', 51 | notes: " I'll be in your neighborhood doing errands", 52 | check: false, 53 | show: false, 54 | visible: true, 55 | btns: false 56 | }, 57 | { 58 | color: { 59 | red: 125, 60 | green: 5, 61 | blue: 150 62 | }, 63 | what: 'Brunch this weekend?', 64 | when: '3:08PM', 65 | notes: " I'll be in your neighborhood doing errands", 66 | check: false, 67 | show: false, 68 | visible: true, 69 | btns: false 70 | }, 71 | { 72 | color: { 73 | red: 25, 74 | green: 5, 75 | blue: 150 76 | }, 77 | what: 'Brunch this weekend?', 78 | when: '3:08PM', 79 | notes: " I'll be in your neighborhood doing errands", 80 | check: false, 81 | show: false, 82 | visible: true, 83 | btns: false 84 | }, 85 | ] 86 | 87 | 88 | $scope.showItem = function(item ) { 89 | item.show = true; 90 | }; 91 | 92 | $scope.hideItem = function(item ) { 93 | item.show = false; 94 | }; 95 | 96 | $scope.countSelected = 0; 97 | $scope.oneSelected= false; 98 | 99 | $scope.deselectAll = function(item) { 100 | 101 | $scope.todos.forEach( function(element) { 102 | 103 | decheck(element); 104 | }); 105 | 106 | if($scope.countSelected>0) { 107 | $scope.oneSelected = true; 108 | } else { 109 | $scope.oneSelected = false; 110 | } 111 | } 112 | 113 | $scope.remove = function(item) { 114 | item.visible = false; 115 | var idx = $scope.todos.indexOf(item); 116 | 117 | 118 | 119 | setTimeout( function() { 120 | $scope.todos.splice(idx,1); 121 | 122 | $mdToast.show( 123 | $mdToast.simple() 124 | .content('Запись отправлена в архив') 125 | .position($scope.getToastPosition()) 126 | .hideDelay(3000) 127 | ); 128 | 129 | 130 | $scope.countSelected = 0; 131 | } ,1000); 132 | 133 | }; 134 | 135 | $scope.toastPosition = { 136 | bottom: true, 137 | top: false, 138 | left: true, 139 | right: false 140 | }; 141 | 142 | $scope.getToastPosition = function() { 143 | return Object.keys($scope.toastPosition) 144 | .filter(function(pos) { return $scope.toastPosition[pos]; }) 145 | .join(' '); 146 | }; 147 | 148 | $scope.archiveAll = function () { 149 | 150 | //Здесь должен выполняться запросс на удаление 151 | var newTodos = []; 152 | $scope.todos.forEach(function(item){ 153 | if(item.check ===false){ 154 | 155 | } else { 156 | item.visible = false; 157 | } 158 | }); 159 | 160 | 161 | setTimeout( function() { 162 | $scope.todos.forEach(function(item){ 163 | if(item.check ===false){ 164 | newTodos.push(item); 165 | } 166 | }); 167 | 168 | 169 | $scope.todos = newTodos; 170 | 171 | 172 | $mdToast.show( 173 | $mdToast.simple() 174 | .content('Отправленно в архив записей: ' + $scope.countSelected) 175 | .position($scope.getToastPosition()) 176 | .hideDelay(3000) 177 | ); 178 | 179 | 180 | $scope.countSelected = 0; 181 | 182 | } ,1000); 183 | 184 | $scope.oneSelected = false; 185 | 186 | } 187 | 188 | function decheck(item) { 189 | if(item.check===true) { 190 | $scope.countSelected--; 191 | } 192 | 193 | item.check=false; 194 | } 195 | 196 | $scope.oneCheck = function(item) { 197 | 198 | 199 | if(item.check===true) { 200 | $scope.countSelected++; 201 | } else { 202 | $scope.countSelected--; 203 | } 204 | 205 | if($scope.countSelected>0) { 206 | $scope.oneSelected = true; 207 | } else { 208 | $scope.oneSelected = false; 209 | } 210 | }; 211 | 212 | $scope.showAlert = function(ev) { 213 | 214 | $mdDialog.show({ 215 | controller: DialogController, 216 | templateUrl: 'dialog.tmpl.html', 217 | targetEvent: ev, 218 | }) 219 | .then(function(answer) { 220 | 221 | 222 | var item = { 223 | 224 | color: answer.color, 225 | what: answer.what, 226 | when: answer.when, 227 | notes: answer.notes, 228 | check: false, 229 | show: false, 230 | visible: true 231 | }; 232 | 233 | $scope.todos.unshift(item); 234 | 235 | 236 | $mdToast.show( 237 | $mdToast.simple() 238 | .content('Задание добавлено') 239 | .position($scope.getToastPosition()) 240 | .hideDelay(3000) 241 | ); 242 | 243 | }, function() { 244 | /* 'You cancelled the dialog.';*/ 245 | }); 246 | }; 247 | 248 | }); 249 | 250 | function DialogController($scope, $mdDialog) { 251 | 252 | $scope.todo = {}; 253 | 254 | $scope.todo.color = { 255 | red: Math.floor(Math.random() * 255), 256 | green: Math.floor(Math.random() * 255), 257 | blue: Math.floor(Math.random() * 255) 258 | }; 259 | 260 | $scope.hide = function() { 261 | $mdDialog.hide(); 262 | }; 263 | $scope.cancel = function() { 264 | $mdDialog.cancel(); 265 | }; 266 | $scope.answer = function(answer) { 267 | $mdDialog.hide(answer); 268 | }; 269 | } -------------------------------------------------------------------------------- /dist/view1/view1_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.view1 module', function() { 4 | 5 | beforeEach(module('myApp.view1')); 6 | 7 | describe('view1 controller', function(){ 8 | 9 | it('should ....', inject(function($controller) { 10 | //spec body 11 | var view1Ctrl = $controller('View1Ctrl'); 12 | expect(view1Ctrl).toBeDefined(); 13 | })); 14 | 15 | }); 16 | }); -------------------------------------------------------------------------------- /dist/view2/view2.html: -------------------------------------------------------------------------------- 1 |
2 |

Toast can be dismissed with a swipe, a timer, or a button.

3 |
4 |
5 | 6 | Show Custom 7 | 8 | 9 | Show Simple 10 | 11 | 12 | Show With Action 13 | 14 |
15 |
16 |
17 |
18 | Toast Position: "{{getToastPosition()}}" 19 |
20 | 21 | {{name}} 22 | 23 | 24 | FAB 25 | 26 | 27 | FAB 28 | 29 |
30 |
-------------------------------------------------------------------------------- /dist/view2/view2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myApp.view2', ['ngRoute','ngMaterial']) 4 | 5 | .config(['$routeProvider', function($routeProvider) { 6 | $routeProvider.when('/view2', { 7 | templateUrl: 'view2/view2.html', 8 | controller: 'View2Ctrl' 9 | }); 10 | }]) 11 | 12 | .controller('View2Ctrl', function($scope, $mdToast, $animate) { 13 | $scope.toastPosition = { 14 | bottom: false, 15 | top: true, 16 | left: false, 17 | right: true 18 | }; 19 | $scope.getToastPosition = function() { 20 | return Object.keys($scope.toastPosition) 21 | .filter(function(pos) { return $scope.toastPosition[pos]; }) 22 | .join(' '); 23 | }; 24 | $scope.showCustomToast = function() { 25 | $mdToast.show({ 26 | controller: 'ToastCtrl', 27 | templateUrl: 'toast-template.html', 28 | hideDelay: 6000, 29 | position: $scope.getToastPosition() 30 | }); 31 | }; 32 | $scope.showSimpleToast = function() { 33 | $mdToast.show( 34 | $mdToast.simple() 35 | .content('Simple Toast!') 36 | .position($scope.getToastPosition()) 37 | .hideDelay(0) 38 | ); 39 | }; 40 | $scope.showActionToast = function() { 41 | var toast = $mdToast.simple() 42 | .content('Action Toast!') 43 | .action('OK') 44 | .highlightAction(false) 45 | .position($scope.getToastPosition()); 46 | $mdToast.show(toast).then(function() { 47 | alert('You clicked \'OK\'.'); 48 | }); 49 | }; 50 | }) 51 | .controller('ToastCtrl', function($scope, $mdToast) { 52 | $scope.closeToast = function() { 53 | $mdToast.hide(); 54 | }; 55 | }); -------------------------------------------------------------------------------- /dist/view2/view2_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('myApp.view2 module', function() { 4 | 5 | beforeEach(module('myApp.view2')); 6 | 7 | describe('view2 controller', function(){ 8 | 9 | it('should ....', inject(function($controller) { 10 | //spec body 11 | var view2Ctrl = $controller('View2Ctrl'); 12 | expect(view2Ctrl).toBeDefined(); 13 | })); 14 | 15 | }); 16 | }); -------------------------------------------------------------------------------- /e2e-tests/protractor.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | allScriptsTimeout: 11000, 3 | 4 | specs: [ 5 | '*.js' 6 | ], 7 | 8 | capabilities: { 9 | 'browserName': 'chrome' 10 | }, 11 | 12 | baseUrl: 'http://localhost:8000/app/', 13 | 14 | framework: 'jasmine', 15 | 16 | jasmineNodeOpts: { 17 | defaultTimeoutInterval: 30000 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /e2e-tests/scenarios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* https://github.com/angular/protractor/blob/master/docs/toc.md */ 4 | 5 | describe('my app', function() { 6 | 7 | browser.get('index.html'); 8 | 9 | it('should automatically redirect to /view1 when location hash/fragment is empty', function() { 10 | expect(browser.getLocationAbsUrl()).toMatch("/view1"); 11 | }); 12 | 13 | 14 | describe('view1', function() { 15 | 16 | beforeEach(function() { 17 | browser.get('index.html#/view1'); 18 | }); 19 | 20 | 21 | it('should render view1 when user navigates to /view1', function() { 22 | expect(element.all(by.css('[ng-view] p')).first().getText()). 23 | toMatch(/partial for view 1/); 24 | }); 25 | 26 | }); 27 | 28 | 29 | describe('view2', function() { 30 | 31 | beforeEach(function() { 32 | browser.get('index.html#/view2'); 33 | }); 34 | 35 | 36 | it('should render view2 when user navigates to /view2', function() { 37 | expect(element.all(by.css('[ng-view] p')).first().getText()). 38 | toMatch(/partial for view 2/); 39 | }); 40 | 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config){ 2 | config.set({ 3 | 4 | basePath : './', 5 | 6 | files : [ 7 | 'app/bower_components/angular/angular.js', 8 | 'app/bower_components/angular-route/angular-route.js', 9 | 'app/bower_components/angular-mocks/angular-mocks.js', 10 | 'app/components/**/*.js', 11 | 'app/view*/**/*.js' 12 | ], 13 | 14 | autoWatch : true, 15 | 16 | frameworks: ['jasmine'], 17 | 18 | browsers : ['Chrome'], 19 | 20 | plugins : [ 21 | 'karma-chrome-launcher', 22 | 'karma-firefox-launcher', 23 | 'karma-jasmine', 24 | 'karma-junit-reporter' 25 | ], 26 | 27 | junitReporter : { 28 | outputFile: 'test_out/unit.xml', 29 | suite: 'unit' 30 | } 31 | 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-angular-demo-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "Material angular demo project", 6 | "repository": "https://github.com/nesterione/material-angular-demo-project", 7 | "devDependencies": { 8 | "karma": "~0.10", 9 | "protractor": "^1.1.1", 10 | "http-server": "^0.6.1", 11 | "bower": "^1.3.1", 12 | "shelljs": "^0.2.6", 13 | "karma-junit-reporter": "^0.2.2" 14 | }, 15 | "scripts": { 16 | "postinstall": "bower install", 17 | 18 | "prestart": "npm install", 19 | "start": "http-server -a localhost -p 8888 -c-1", 20 | 21 | "pretest": "npm install", 22 | "test": "karma start karma.conf.js", 23 | "test-single-run": "karma start karma.conf.js --single-run", 24 | 25 | "preupdate-webdriver": "npm install", 26 | "update-webdriver": "webdriver-manager update", 27 | 28 | "preprotractor": "npm run update-webdriver", 29 | "protractor": "protractor e2e-tests/protractor.conf.js", 30 | 31 | "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + sed(/sourceMappingURL=angular-loader.min.js.map/,'sourceMappingURL=bower_components/angular-loader/angular-loader.min.js.map','app/bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" 32 | } 33 | } 34 | --------------------------------------------------------------------------------