├── .npmignore ├── scripts ├── test-cases │ ├── web │ │ ├── ionic.json │ │ └── bootstrap.json │ ├── both │ │ ├── ionic.json │ │ └── bootstrap.json │ └── mobile │ │ ├── ionic.json │ │ └── bootstrap.json ├── test-generator.sh └── update-starter-kit.sh ├── generators └── app │ ├── templates │ ├── .bowerrc │ ├── gulp │ │ ├── .jshintrc │ │ ├── unit-tests.js │ │ ├── translations.js │ │ ├── watch.js │ │ ├── images.js │ │ ├── inject.js │ │ ├── e2e-tests.js │ │ ├── typings.js │ │ ├── styles.js │ │ ├── server.js │ │ ├── scripts.js │ │ └── build.js │ ├── sources │ │ ├── main │ │ │ ├── theme │ │ │ │ ├── theme-variables.scss │ │ │ │ ├── _theme.scss │ │ │ │ ├── __bootstrap.bootstrap-variables.scss │ │ │ │ ├── __ionic.ionic-variables.scss │ │ │ │ ├── __ionic.ionic.scss │ │ │ │ └── __bootstrap.bootstrap.scss │ │ │ ├── ui-components │ │ │ │ └── loading │ │ │ │ │ ├── __bootstrap.loading.html │ │ │ │ │ ├── __material.loading.html │ │ │ │ │ ├── __ionic.loading.html │ │ │ │ │ ├── __ionic.loading.scss │ │ │ │ │ ├── loading.directive.ts │ │ │ │ │ └── loading.directive.spec.ts │ │ │ ├── main.wrappers.ts │ │ │ ├── hacks.scss │ │ │ ├── screens │ │ │ │ ├── home │ │ │ │ │ ├── _home.scss │ │ │ │ │ ├── __bootstrap.home.html │ │ │ │ │ ├── __ionic.home.html │ │ │ │ │ ├── home.controller.ts │ │ │ │ │ └── __material.home.html │ │ │ │ └── about │ │ │ │ │ ├── __bootstrap.about.html │ │ │ │ │ ├── __ionic.about.html │ │ │ │ │ ├── about.controller.ts │ │ │ │ │ └── __material.about.html │ │ │ ├── helpers.scss │ │ │ ├── shell │ │ │ │ ├── _shell.scss │ │ │ │ ├── __material.shell.html │ │ │ │ ├── __ionic.shell.html │ │ │ │ ├── _shell.controller.ts │ │ │ │ └── __bootstrap.shell.html │ │ │ ├── _main.module.ts │ │ │ ├── _main.scss │ │ │ ├── web-services │ │ │ │ └── quote │ │ │ │ │ ├── quote.service.ts │ │ │ │ │ └── quote.service.spec.ts │ │ │ ├── _main.routes.ts │ │ │ ├── main.config.ts │ │ │ ├── _main.constants.ts │ │ │ ├── helpers │ │ │ │ ├── context │ │ │ │ │ ├── context.service.ts │ │ │ │ │ └── context.service.spec.ts │ │ │ │ ├── logger │ │ │ │ │ ├── logger.spec.ts │ │ │ │ │ └── logger.ts │ │ │ │ └── cache │ │ │ │ │ ├── cache.service.ts │ │ │ │ │ └── cache.service.spec.ts │ │ │ └── _main.run.ts │ │ ├── images │ │ │ └── angularjs-logo.png │ │ ├── translations │ │ │ ├── _en-US.po │ │ │ └── _fr-FR.po │ │ └── _index.html │ ├── _web │ │ └── sources │ │ │ ├── robots.txt │ │ │ └── favicon.ico │ ├── browserslist │ ├── _mobile │ │ ├── resources │ │ │ ├── icon.png │ │ │ ├── splash.png │ │ │ ├── ios │ │ │ │ ├── icon │ │ │ │ │ ├── icon.png │ │ │ │ │ ├── icon-40.png │ │ │ │ │ ├── icon-50.png │ │ │ │ │ ├── icon-60.png │ │ │ │ │ ├── icon-72.png │ │ │ │ │ ├── icon-76.png │ │ │ │ │ ├── icon@2x.png │ │ │ │ │ ├── icon-40@2x.png │ │ │ │ │ ├── icon-50@2x.png │ │ │ │ │ ├── icon-60@2x.png │ │ │ │ │ ├── icon-60@3x.png │ │ │ │ │ ├── icon-72@2x.png │ │ │ │ │ ├── icon-76@2x.png │ │ │ │ │ ├── icon-small.png │ │ │ │ │ ├── icon-small@2x.png │ │ │ │ │ └── icon-small@3x.png │ │ │ │ └── splash │ │ │ │ │ ├── Default-667h.png │ │ │ │ │ ├── Default-736h.png │ │ │ │ │ ├── Default~iphone.png │ │ │ │ │ ├── Default@2x~iphone.png │ │ │ │ │ ├── Default-568h@2x~iphone.png │ │ │ │ │ ├── Default-Portrait~ipad.png │ │ │ │ │ └── Default-Portrait@2x~ipad.png │ │ │ └── android │ │ │ │ ├── icon │ │ │ │ ├── drawable-hdpi-icon.png │ │ │ │ ├── drawable-ldpi-icon.png │ │ │ │ ├── drawable-mdpi-icon.png │ │ │ │ ├── drawable-xhdpi-icon.png │ │ │ │ ├── drawable-xxhdpi-icon.png │ │ │ │ └── drawable-xxxhdpi-icon.png │ │ │ │ └── splash │ │ │ │ ├── drawable-port-hdpi-screen.png │ │ │ │ ├── drawable-port-ldpi-screen.png │ │ │ │ ├── drawable-port-mdpi-screen.png │ │ │ │ ├── drawable-port-xhdpi-screen.png │ │ │ │ ├── drawable-port-xxhdpi-screen.png │ │ │ │ └── drawable-port-xxxhdpi-screen.png │ │ ├── gulp │ │ │ └── cordova.js │ │ ├── hooks │ │ │ ├── after_prepare │ │ │ │ └── 010_add_platform_class.js │ │ │ └── README.md │ │ └── _config.xml │ ├── e2e │ │ ├── .jshintrc │ │ ├── main.po.js │ │ ├── screens │ │ │ ├── about │ │ │ │ ├── __ionic.about.po.js │ │ │ │ ├── __material.about.po.js │ │ │ │ ├── __bootstrap.about.po.js │ │ │ │ ├── __ionic.about.spec.js │ │ │ │ ├── __bootstrap.about.spec.js │ │ │ │ └── __material.about.spec.js │ │ │ └── home │ │ │ │ ├── __ionic.home.po.js │ │ │ │ ├── __ionic.home.spec.js │ │ │ │ ├── __bootstrap.home.spec.js │ │ │ │ ├── __material.home.spec.js │ │ │ │ ├── __bootstrap.home.po.js │ │ │ │ └── __material.home.po.js │ │ └── shell │ │ │ ├── __ionic.shell.spec.js │ │ │ ├── __ionic.shell.po.js │ │ │ ├── __bootstrap.shell.spec.js │ │ │ ├── __material.shell.spec.js │ │ │ ├── __bootstrap.shell.po.js │ │ │ └── __material.shell.po.js │ ├── .editorconfig │ ├── tsconfig.json │ ├── .gitignore │ ├── .htmlhintrc │ ├── gulpfile.js │ ├── docs │ │ ├── updating.md │ │ ├── coding-guides │ │ │ ├── javascript.md │ │ │ ├── html.md │ │ │ ├── typescript.md │ │ │ ├── unit-tests.md │ │ │ ├── css.md │ │ │ └── e2e-tests.md │ │ ├── i18n.md │ │ ├── _proxy.md │ │ ├── api-proxy.md │ │ ├── build-environments.md │ │ └── _tasks.md │ ├── .jshintrc │ ├── protractor.conf.js │ ├── _bower.json │ ├── tslint.json │ ├── _package.json │ ├── karma.conf.js │ ├── _gulpfile.config.js │ ├── _typings.json │ └── _README.md │ ├── options.json │ ├── prompts.json │ └── index.js ├── .gitignore ├── package.json ├── LICENSE ├── .travis.yml └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | sample/ 2 | deploy/ 3 | scripts/ 4 | .gitignore 5 | .travis.yml -------------------------------------------------------------------------------- /scripts/test-cases/web/ionic.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "web", 3 | "ui": "ionic" 4 | } -------------------------------------------------------------------------------- /generators/app/templates/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "sources/libraries" 3 | } 4 | -------------------------------------------------------------------------------- /scripts/test-cases/both/ionic.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "both", 3 | "ui": "ionic" 4 | } -------------------------------------------------------------------------------- /scripts/test-cases/both/bootstrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "both", 3 | "ui": "bootstrap" 4 | } -------------------------------------------------------------------------------- /scripts/test-cases/mobile/ionic.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "mobile", 3 | "ui": "ionic" 4 | } -------------------------------------------------------------------------------- /scripts/test-cases/web/bootstrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "web", 3 | "ui": "bootstrap" 4 | } -------------------------------------------------------------------------------- /scripts/test-cases/mobile/bootstrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "mobile", 3 | "ui": "bootstrap" 4 | } -------------------------------------------------------------------------------- /generators/app/templates/gulp/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "node": true 4 | } 5 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/theme-variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Application global variables. 3 | */ -------------------------------------------------------------------------------- /generators/app/templates/_web/sources/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | 3 | # Allow crawling of all content 4 | User-agent: * 5 | Disallow: 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | sample/ 3 | sample-app/ 4 | deploy/ 5 | .idea/ 6 | npm-debug.log 7 | .npm-debug.log 8 | .DS_Store 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /generators/app/templates/_web/sources/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_web/sources/favicon.ico -------------------------------------------------------------------------------- /generators/app/templates/browserslist: -------------------------------------------------------------------------------- 1 | # List of supported browsers, for autoprefixer 2 | # See https://github.com/ai/browserslist 3 | 4 | > 1% 5 | Last 2 versions 6 | IE 10 7 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/splash.png -------------------------------------------------------------------------------- /generators/app/templates/sources/images/angularjs-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/sources/images/angularjs-logo.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-40.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-50.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-60.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-72.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-76.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-40@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-50@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-60@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-60@3x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-72@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-76@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-small.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-small@2x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/icon/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/icon/icon-small@3x.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default-667h.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default-736h.png -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/__bootstrap.loading.html: -------------------------------------------------------------------------------- 1 |
2 | {{message}} 3 |
4 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/__material.loading.html: -------------------------------------------------------------------------------- 1 |
2 | {{message}} 3 |
4 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default~iphone.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default@2x~iphone.png -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/__ionic.loading.html: -------------------------------------------------------------------------------- 1 |
2 | {{message}} 3 |
4 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-hdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-hdpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-ldpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-ldpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-mdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-mdpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-xhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-xhdpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-xxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-xxhdpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /generators/app/templates/e2e/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "globals": { 4 | "browser": false, 5 | "element": false, 6 | "by": false, 7 | "$": false, 8 | "$$": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/icon/drawable-xxxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/icon/drawable-xxxhdpi-icon.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/ios/splash/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/ios/splash/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /generators/app/templates/sources/main/main.wrappers.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | 3 | /** 4 | * Wraps external global libraries into AngularJS injection system. 5 | * global window: false 6 | */ 7 | app.constant('_', _); // Lodash 8 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-hdpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-ldpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-mdpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-xhdpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-xxhdpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/_mobile/resources/android/splash/drawable-port-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-starter-kit/generator-angular-pro/HEAD/generators/app/templates/_mobile/resources/android/splash/drawable-port-xxxhdpi-screen.png -------------------------------------------------------------------------------- /generators/app/templates/sources/main/hacks.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Temporary, ugly style hacks should go here. 3 | * A good practice is to limit this file to a reasonable length (~100 lines), 4 | * and refactor hacks with proper solutions when the limit is reached. 5 | */ -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/__ionic.loading.scss: -------------------------------------------------------------------------------- 1 | // Encapsulate component style into its own "namespace "to avoid naming and css collision 2 | .ui-loading { 3 | 4 | .spinner > svg { 5 | vertical-align: middle; 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/e2e-guide.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Main = function() { 9 | // put shared selectors here 10 | }; 11 | 12 | module.exports = new Main(); 13 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/home/_home.scss: -------------------------------------------------------------------------------- 1 | // Encapsulate component style into its own "namespace "to avoid naming and css collision 2 | .home-screen { 3 | 4 | .logo { 5 | max-height: 100px; 6 | <% if (props.ui === 'material') { -%> 7 | width: auto; 8 | <% } -%> 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /generators/app/templates/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 120 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/about/__bootstrap.about.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

APP_NAME

4 |

5 | Version {{vm.version}} 6 |

7 |
8 |
9 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__ionic.about.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var About = function() { 9 | this.card = element(by.css('.card')); 10 | }; 11 | 12 | module.exports = new About(); 13 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/_theme.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Global application theme. 3 | * Framework overrides and customization goes here. 4 | */ 5 | <% if (props.ui === 'bootstrap') { -%> 6 | 7 | // UI Bootstrap fix (see https://angular-ui.github.io/bootstrap) 8 | .nav, .pagination, .carousel, .panel-title a { 9 | cursor: pointer; 10 | } 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__material.about.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var About = function() { 9 | this.jumbotron = element(by.css('.jumbotron')); 10 | }; 11 | 12 | module.exports = new About(); 13 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Global CSS helpers. 3 | * No theme-related style should goes here, only general helpers. 4 | */ 5 | 6 | // Layout helpers 7 | // -------------- 8 | 9 | // Center a block element vertically 10 | .block-vertical-center { 11 | position: relative; 12 | top: 50%; 13 | transform: translateY(-50%); 14 | } -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__bootstrap.about.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var About = function() { 9 | this.jumbotron = element(by.css('.jumbotron')); 10 | }; 11 | 12 | module.exports = new About(); 13 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__ionic.shell.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('shell', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./shell.po'); 10 | }); 11 | 12 | it('side menu should contain 2 items', function() { 13 | expect(page.sideMenuItems.count()).toBe(2); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__ionic.about.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('about', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/#/about'); 9 | page = require('./about.po'); 10 | }); 11 | 12 | it('should contain version', function() { 13 | expect(page.card.getText()).toMatch('Version'); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__bootstrap.about.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('about', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/#/about'); 9 | page = require('./about.po'); 10 | }); 11 | 12 | it('should contain version', function() { 13 | expect(page.jumbotron.getText()).toMatch('Version'); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/about/__material.about.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('about', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/#/about'); 9 | page = require('./about.po'); 10 | }); 11 | 12 | it('should contain version', function() { 13 | expect(page.jumbotron.getText()).toMatch('Version'); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__ionic.shell.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Shell = function() { 9 | this.sideMenu = element(by.css('.menu')); 10 | this.sideMenuItems = this.sideMenu.element(by.css('.list')).all(by.css('.item')); 11 | }; 12 | 13 | module.exports = new Shell(); 14 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__ionic.home.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Home = function() { 9 | this.card = element(by.css('.card')); 10 | this.title = this.card.element(by.css('h1')); 11 | this.image = this.card.element(by.css('img')); 12 | }; 13 | 14 | module.exports = new Home(); 15 | -------------------------------------------------------------------------------- /generators/app/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "baseUrl": "sources/main", 5 | "module": "commonjs", 6 | "moduleResolution": "classic", 7 | "sourceMap": true, 8 | "types": [] 9 | }, 10 | "files": [ 11 | "typings/index.d.ts" 12 | ], 13 | "exclude": [ 14 | "node_modules", 15 | "typings", 16 | "sources/libraries", 17 | "plugins", 18 | "platforms" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__ionic.home.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('home screen', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./home.po'); 10 | }); 11 | 12 | it('should include card with correct data', function() { 13 | expect(page.title.getText()).toMatch('Hello'); 14 | expect(page.image.getAttribute('src')).toMatch('angularjs'); 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__bootstrap.home.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('home screen', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./home.po'); 10 | }); 11 | 12 | it('should include jumbotron with correct data', function() { 13 | expect(page.title.getText()).toMatch('Hello'); 14 | expect(page.image.getAttribute('src')).toMatch('angularjs'); 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__material.home.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('home screen', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./home.po'); 10 | }); 11 | 12 | it('should include jumbotron with correct data', function() { 13 | expect(page.title.getText()).toMatch('Hello'); 14 | expect(page.image.getAttribute('src')).toMatch('angularjs'); 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/home/__bootstrap.home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | Hello world ! 6 |

7 |
8 |

9 | {{vm.quote}} 10 |

11 |
12 |
13 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__bootstrap.home.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Home = function() { 9 | this.jumbotron = element(by.css('.jumbotron')); 10 | this.title = this.jumbotron.element(by.css('h1')); 11 | this.image = this.jumbotron.element(by.css('img')); 12 | }; 13 | 14 | module.exports = new Home(); 15 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/__bootstrap.bootstrap-variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Override Bootstrap variables here to suite your theme in this file. 3 | * The list of variables is listed here libraries/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 4 | */ 5 | 6 | $brand-primary: darken(#428bca, 6.5%); // #337ab7 7 | $brand-success: #5cb85c; 8 | $brand-info: #5bc0de; 9 | $brand-warning: #f0ad4e; 10 | $brand-danger: #d9534f; 11 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__bootstrap.shell.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('shell', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./shell.po'); 10 | }); 11 | 12 | it('header should contain 2 links', function() { 13 | expect(page.navbarItems.count()).toBe(2); 14 | }); 15 | 16 | it('dropdown should contain 2 supported languages', function() { 17 | expect(page.languageDropdownItems.count()).toBe(2); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__material.shell.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('shell', function() { 4 | 5 | var page; 6 | 7 | beforeEach(function() { 8 | browser.get('/'); 9 | page = require('./shell.po'); 10 | }); 11 | 12 | it('header should contain 3 links', function() { 13 | expect(page.navbarItems.count()).toBe(3); 14 | }); 15 | 16 | it('dropdown should contain 2 supported languages', function() { 17 | expect(page.languageDropdownItems.count()).toBe(2); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/about/__ionic.about.html: -------------------------------------------------------------------------------- 1 | 2 | {{viewTitle}} 3 | 4 | 5 | 6 |

7 | APP_NAME 8 |

9 |

10 | Version {{vm.version}} 11 |

12 |
13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/shell/_shell.scss: -------------------------------------------------------------------------------- 1 | // Encapsulate component style into its own "namespace "to avoid naming and css collision 2 | .shell { 3 | 4 | <% if (props.ui !== 'ionic') { -%> 5 | .jumbotron { 6 | min-height: 500px; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | flex-direction: column; 11 | } 12 | <% } else { -%> 13 | .icon-large { 14 | font-size: 150%; 15 | } 16 | 17 | .medium-dark { 18 | color: darken($light, 20%); 19 | } 20 | <% } -%> 21 | 22 | } 23 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/screens/home/__material.home.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Home = function() { 9 | this.cardTitle = element(by.css('md-card-title-text')); 10 | this.title = this.cardTitle.element(by.css('.md-headline')); 11 | 12 | this.cardMedia = element(by.css('md-card-title-media')); 13 | this.image = this.cardMedia.element(by.css('img')); 14 | }; 15 | 16 | module.exports = new Home(); 17 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/_main.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Translations are injected at build phase 4 | angular.module('translations', []); 5 | 6 | export default angular.module('app', [ 7 | 'translations', 8 | 'gettext', 9 | 'ngAnimate', 10 | 'ngSanitize', 11 | <% if (props.target !== 'web') { -%> 12 | 'ngCordova', 13 | <% } -%> 14 | 'ui.router', 15 | <% if (props.ui === 'bootstrap') { -%> 16 | 'ui.bootstrap' 17 | <% } else if (props.ui === 'ionic') { -%> 18 | 'ionic' 19 | <% } else { -%> 20 | 'ngMaterial' 21 | <% } -%> 22 | ]); 23 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__bootstrap.shell.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Shell = function() { 9 | this.navbar = element(by.css('.navbar')); 10 | this.navbarItems = this.navbar.element(by.css('.navbar-nav')).all(by.css('li')); 11 | this.languageDropdown = this.navbar.element(by.css('.dropdown')); 12 | this.languageDropdownItems = this.languageDropdown.all(by.css('li')); 13 | }; 14 | 15 | module.exports = new Shell(); 16 | -------------------------------------------------------------------------------- /generators/app/options.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "skip-install", 4 | "type": "Boolean", 5 | "required": false, 6 | "desc": "Skip npm, bower and tsd install after project generation", 7 | "defaults": false 8 | }, 9 | { 10 | "name": "skip-message", 11 | "type": "Boolean", 12 | "required": false, 13 | "desc": "Skip install messages", 14 | "defaults": false 15 | }, 16 | { 17 | "name": "automate", 18 | "type": "String", 19 | "required": false, 20 | "desc": "Automate prompt answers using the specified JSON file", 21 | "defaults": "" 22 | } 23 | ] -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/home/__ionic.home.html: -------------------------------------------------------------------------------- 1 | 2 | {{viewTitle}} 3 | 4 | 5 | 6 | 7 |

Hello world !

8 |
9 | 10 |
11 | {{vm.quote}} 12 |
13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/__ionic.ionic-variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Override Ionic variables here to suite your theme in this file. 3 | * The list of variables is listed here libraries/ionic/scss/_variables.scss 4 | */ 5 | 6 | $light: #fff; 7 | $stable: #f8f8f8; 8 | $positive: #387ef5; 9 | $calm: #11c1f3; 10 | $balanced: #33cd5f; 11 | $energized: #ffc900; 12 | $assertive: #ef473a; 13 | $royal: #886aea; 14 | $dark: #444; 15 | -------------------------------------------------------------------------------- /generators/app/templates/.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | ## Web 5 | node_modules/ 6 | /.tmp/ 7 | /dist/ 8 | .sass-cache 9 | npm-debug.log 10 | 11 | ## Karma 12 | /reports/ 13 | 14 | ## Mobile 15 | /ionic.project 16 | /www/ 17 | /plugins/ 18 | /platforms/ 19 | 20 | ## Mac 21 | .DS_Store 22 | 23 | ## IntelliJ / WebStorm 24 | *.iml 25 | *.iws 26 | .idea/* 27 | !.idea/runConfigurations/ 28 | !.idea/codeStyleSettings.xml 29 | 30 | ## Xcode 31 | xcuserdata/ 32 | 33 | ## Eclipse 34 | .classpath 35 | .project 36 | .settings/ 37 | 38 | ## Maven 39 | /target/ 40 | /log/ 41 | -------------------------------------------------------------------------------- /generators/app/templates/.htmlhintrc: -------------------------------------------------------------------------------- 1 | { 2 | "tagname-lowercase": false, 3 | "attr-lowercase": false, 4 | "attr-value-double-quotes": true, 5 | "tag-pair": true, 6 | "spec-char-escape": true, 7 | "id-unique": true, 8 | "src-not-empty": true, 9 | "attr-no-duplication": true, 10 | "title-require": true, 11 | "tag-self-close": true, 12 | "head-script-disabled": true, 13 | "doctype-html5": true, 14 | "id-class-value": "dash", 15 | "style-disabled": true, 16 | "inline-style-disabled": true, 17 | "inline-script-disabled": true, 18 | "space-tab-mixed-disabled": "true", 19 | "id-class-ad-disabled": true, 20 | "attr-unsafe-chars": true 21 | } 22 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | var karma = require('karma'); 7 | 8 | function runTests(singleRun, done) { 9 | var server = new karma.Server({ 10 | configFile: path.join(__dirname, '/../karma.conf.js'), 11 | singleRun: singleRun, 12 | autoWatch: !singleRun 13 | }, done); 14 | server.start(); 15 | } 16 | 17 | gulp.task('test', ['scripts:test'], function(done) { 18 | runTests(true, done); 19 | }); 20 | 21 | gulp.task('test:auto', ['scripts:test-watch'], function(done) { 22 | runTests(false, done); 23 | }); 24 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/translations.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | gulp.task('translations:extract', ['scripts'], function() { 10 | return gulp.src([ 11 | path.join(conf.paths.tmp, '**/*.js'), 12 | path.join(conf.paths.src, '**/*.html'), 13 | path.join('!' + conf.paths.bower, '**/*.js'), 14 | path.join('!' + conf.paths.bower, '**/*.html') 15 | ]) 16 | .pipe($.angularGettext.extract('template.pot', {})) 17 | .pipe(gulp.dest(path.join(conf.paths.src, 'translations'))); 18 | }); 19 | -------------------------------------------------------------------------------- /generators/app/templates/e2e/shell/__material.shell.po.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file uses the Page Object pattern to define the main page for tests. 3 | * See docs/coding-guide/e2e-tests.md for more info. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Shell = function() { 9 | this.header = element(by.css('header')); 10 | this.navbar = this.header.element(by.css('.nav-container')); 11 | this.navbarItems = this.navbar.element(by.css('.nav-links')).all(by.css('.md-button')); 12 | this.languageDropdown = this.navbar.element(by.css('md-menu-content')); 13 | this.languageDropdownItems = this.languageDropdown.all(by.css('md-menu-item')); 14 | }; 15 | 16 | module.exports = new Shell(); 17 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/about/about.controller.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {IApplicationConfig} from 'main.constants'; 3 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 4 | 5 | /** 6 | * Displays the about screen. 7 | */ 8 | export class AboutController { 9 | 10 | version: string; 11 | 12 | private logger: ILogger; 13 | 14 | constructor(logger: LoggerService, 15 | config: IApplicationConfig) { 16 | 17 | this.logger = logger.getLogger('about'); 18 | this.version = config.version; 19 | 20 | this.logger.log('init'); 21 | } 22 | 23 | } 24 | 25 | app.controller('aboutController', AboutController); 26 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/about/__material.about.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | APP_NAME 7 |

8 | Version {{vm.version}} 9 |

10 |
11 | 12 | 13 |
14 | 15 | 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | 7 | gulp.task('watch', ['inject:watch'], function() { 8 | var options = { 9 | debounceDelay: 500 10 | }; 11 | 12 | gulp.watch(['bower.json', path.join(conf.paths.src, '/index.html')], options, ['inject:reload']); 13 | 14 | gulp.watch([ 15 | path.join(conf.paths.src, '/**/*.css'), 16 | path.join(conf.paths.src, '/**/*.scss') 17 | ], options, function(event) { 18 | if (event.type === 'changed') { 19 | gulp.start('styles:reload'); 20 | } else { 21 | gulp.start('inject:reload'); 22 | } 23 | }); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /generators/app/templates/gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your gulpfile! 3 | * The gulp tasks are split in several files in the gulp directory for better modularity. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var gulp = require('gulp'); 9 | var fs = require('fs'); 10 | 11 | /** 12 | * This will load all js files in the gulp directory in order to load all gulp tasks. 13 | */ 14 | fs.readdirSync('./gulp').filter(function(file) { 15 | return (/\.(js)$/i).test(file); 16 | }).map(function(file) { 17 | require('./gulp/' + file); 18 | }); 19 | 20 | /** 21 | * Default task clean temporaries directories and launch the main optimization build task. 22 | */ 23 | gulp.task('default', ['clean'], function () { 24 | gulp.start('build'); 25 | }); 26 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/images.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var path = require('path'); 5 | var conf = require('../gulpfile.config'); 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | gulp.task('images', function() { 10 | return gulp.src(path.join(conf.paths.src, 'images/**/*.{gif,jpg,png,svg}')) 11 | .pipe($.cache($.imagemin([ 12 | $.imagemin.gifsicle({interlaced: true}), 13 | $.imagemin.jpegtran({progressive: true}), 14 | $.imagemin.optipng({optimizationLevel: 3}), 15 | $.imagemin.svgo() 16 | ]))) 17 | .pipe(gulp.dest(path.join(conf.paths.dist, 'images'))) 18 | .pipe($.size({title: 'images'})); 19 | }); 20 | 21 | gulp.task('images:clean-cache', function(done) { 22 | return $.cache.clearAll(done); 23 | }); 24 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/loading.directive.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | 3 | /** 4 | * Loading directive: displays a loading indicator while data is being loaded. 5 | * 6 | * Example usage:
7 | * The expected value of the directive attribute is a boolean indicating whether the content 8 | * is still loading or not. 9 | * 10 | * Additional parameter attributes: 11 | * - message: the loading message to display (none by default) 12 | * 13 | * Example:
14 | */ 15 | export class LoadingDirective implements ng.IDirective { 16 | restrict = 'A'; 17 | template = require('loading.html'); 18 | scope = { 19 | message: '<', 20 | isLoading: ' new LoadingDirective()); 25 | 26 | -------------------------------------------------------------------------------- /generators/app/prompts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "string", 4 | "name": "appName", 5 | "message": "What's the name of your application?" 6 | }, 7 | { 8 | "type": "list", 9 | "name": "target", 10 | "message": "What kind of app do you want to create?", 11 | "choices": [ 12 | { 13 | "value": "web", 14 | "name": "Web app" 15 | }, 16 | { 17 | "value": "mobile", 18 | "name": "Mobile app" 19 | }, 20 | { 21 | "value": "both", 22 | "name": "Web + mobile app" 23 | } 24 | ] 25 | }, 26 | { 27 | "type": "list", 28 | "name": "ui", 29 | "message": "Which UI framework do you want?", 30 | "choices": [ 31 | { 32 | "value": "bootstrap", 33 | "name": "Bootstrap (web is your main target)" 34 | }, 35 | { 36 | "value": "ionic", 37 | "name": "Ionic (mobile is your main target)" 38 | } 39 | ] 40 | } 41 | ] -------------------------------------------------------------------------------- /generators/app/templates/docs/updating.md: -------------------------------------------------------------------------------- 1 | # Updating npm dependencies 2 | 3 | - Install update tool (if not already done) 4 | ```sh 5 | npm install -g npm-check-updates 6 | ``` 7 | 8 | - Check outdated packages 9 | ```sh 10 | npm-check-updates 11 | ``` 12 | 13 | - Update packages in `package.json` 14 | ```sh 15 | npm-check-updates -u 16 | ``` 17 | 18 | - Update local packages regarding `package.json` 19 | ```sh 20 | npm udpate 21 | ``` 22 | 23 | # Updating bower libraries 24 | 25 | - Install update tool (if not already done) 26 | ```sh 27 | npm install -g npm-check-updates 28 | ``` 29 | 30 | - Check outdated packages 31 | ```sh 32 | npm-check-updates -m bower 33 | ``` 34 | 35 | - Update packages in `bower.json` 36 | ```sh 37 | npm-check-updates -u -m bower 38 | ``` 39 | 40 | - Update local packages regarding `package.json` 41 | ```sh 42 | bower update 43 | ``` 44 | 45 | ## Locking package versions 46 | 47 | - Lock down version using `npm-shrinkwrap.json` 48 | ```sh 49 | npm shrinkwrap --dev 50 | ``` 51 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/home/home.controller.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 3 | import {QuoteService} from 'web-services/quote/quote.service'; 4 | 5 | /** 6 | * Displays the home screen. 7 | */ 8 | export class HomeController { 9 | 10 | isLoading: boolean = true; 11 | quote: string = null; 12 | 13 | private logger: ILogger; 14 | private quoteService: QuoteService; 15 | 16 | constructor(logger: LoggerService, 17 | quoteService: QuoteService) { 18 | 19 | this.logger = logger.getLogger('home'); 20 | this.quoteService = quoteService; 21 | 22 | this.logger.log('init'); 23 | 24 | this.quoteService 25 | .getRandomJoke({category: 'nerdy'}) 26 | .then((quote: string) => { 27 | this.quote = quote; 28 | }) 29 | .finally(() => { 30 | this.isLoading = false; 31 | }); 32 | } 33 | 34 | } 35 | 36 | app.controller('homeController', HomeController); 37 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/ui-components/loading/loading.directive.spec.ts: -------------------------------------------------------------------------------- 1 | describe('loading directive', () => { 2 | 3 | let $rootScope; 4 | let $compile; 5 | let element; 6 | 7 | beforeEach(() => { 8 | angular.mock.module('app'); 9 | 10 | inject((_$rootScope_: ng.IRootScopeService, 11 | _$compile_: ng.ICompileService) => { 12 | 13 | $rootScope = _$rootScope_; 14 | $compile = _$compile_; 15 | }); 16 | 17 | element = $('
'); 18 | element = $compile(element)($rootScope); 19 | $rootScope.$digest(); 20 | }); 21 | 22 | it('should be visible only when loading is in progress', () => { 23 | 24 | let div = element.children().eq(0); 25 | 26 | $rootScope.isLoading = true; 27 | $rootScope.$digest(); 28 | 29 | expect(div).not.toHaveClass('ng-hide'); 30 | 31 | $rootScope.isLoading = false; 32 | $rootScope.$digest(); 33 | 34 | expect(div).toHaveClass('ng-hide'); 35 | 36 | }); 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/screens/home/__material.home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | Hello, 7 | Material Design world ! 8 |

9 | {{vm.quote}} 10 |

11 |
12 | 13 | 14 | 15 |
16 | 17 | Read more about Material Design 18 | 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/__ionic.ionic.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Override Ionic module inclusion, to allow selecting only the needed modules. 3 | * This file content was copied from libraries/ionic/scss/ionic.scss 4 | */ 5 | 6 | @charset "UTF-8"; 7 | 8 | @import 9 | // Ionicons 10 | "ionicons/ionicons.scss", 11 | 12 | // Variables 13 | "mixins", 14 | "variables", 15 | 16 | // Base 17 | "reset", 18 | "scaffolding", 19 | "type", 20 | 21 | // Components 22 | "action-sheet", 23 | "backdrop", 24 | "bar", 25 | "tabs", 26 | "menu", 27 | "modal", 28 | "popover", 29 | "popup", 30 | "loading", 31 | "items", 32 | "list", 33 | "badge", 34 | "slide-box", 35 | "slides", 36 | "refresher", 37 | "spinner", 38 | 39 | // Forms 40 | "form", 41 | "checkbox", 42 | "toggle", 43 | "radio", 44 | "range", 45 | "select", 46 | "progress", 47 | 48 | // Buttons 49 | "button", 50 | "button-bar", 51 | 52 | // Util 53 | "grid", 54 | "util", 55 | "platform", 56 | 57 | // Animations 58 | "animations", 59 | "transitions"; 60 | 61 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | var wiredep = require('wiredep').stream; 7 | var _ = require('lodash'); 8 | var browserSync = require('browser-sync'); 9 | 10 | var $ = require('gulp-load-plugins')(); 11 | 12 | function inject() { 13 | var injectStyles = gulp.src([ 14 | path.join(conf.paths.tmp, '/**/*.css'), 15 | path.join('!' + conf.paths.tmp, '/vendor.css') 16 | ], {read: false}); 17 | 18 | var injectOptions = { 19 | ignorePath: [conf.paths.src, conf.paths.tmp], 20 | addRootSlash: false 21 | }; 22 | 23 | return gulp.src(path.join(conf.paths.src, 'index.html')) 24 | .pipe($.inject(injectStyles, injectOptions)) 25 | .pipe(wiredep(_.extend({}, conf.wiredep))) 26 | .pipe(gulp.dest(conf.paths.tmp)); 27 | } 28 | 29 | gulp.task('inject', ['scripts', 'styles', 'fonts'], inject); 30 | 31 | gulp.task('inject:watch', ['scripts:watch', 'styles', 'fonts'], inject); 32 | 33 | gulp.task('inject:reload', ['inject:watch'], function() { 34 | browserSync.reload(); 35 | }); 36 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver:update', $.protractor.webdriver_update); 13 | gulp.task('webdriver:standalone', $.protractor.webdriver_standalone); 14 | 15 | function runProtractor(done) { 16 | var params = process.argv; 17 | var args = params.length > 3 ? [params[3], params[4]] : []; 18 | 19 | gulp.src(path.join(conf.paths.e2e, '/**/*.js')) 20 | .pipe($.protractor.protractor({ 21 | configFile: 'protractor.conf.js', 22 | args: args 23 | })) 24 | .on('error', function(err) { 25 | // Make sure failed tests cause gulp to exit non-zero 26 | throw err; 27 | }) 28 | .on('end', function() { 29 | // Close browser sync server 30 | browserSync.exit(); 31 | done(); 32 | }); 33 | } 34 | 35 | gulp.task('protractor', ['serve:e2e', 'webdriver:update'], runProtractor); 36 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver:update'], runProtractor); 37 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/_main.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Entry point of application style. 3 | */ 4 | 5 | <% if (props.ui === 'bootstrap') { -%> 6 | // Our own Bootstrap inclusion, should be included before bower dependencies as other libraries may provide 7 | // additional Bootstrap styling 8 | @import "theme/theme-variables"; 9 | @import "theme/bootstrap-variables"; 10 | @import "theme/bootstrap"; 11 | 12 | <% } else if (props.ui === 'ionic') { -%> 13 | // Our own Ionic inclusion, should be included before bower dependencies as other libraries may provide 14 | // additional Ionic styling 15 | @import "theme/theme-variables"; 16 | @import "theme/ionic-variables"; 17 | @import "theme/ionic"; 18 | 19 | <% } -%> 20 | // Do not remove this comments bellow. It's the markers used by wiredep to inject 21 | // style dependencies when defined in the bower.json of your dependencies. 22 | // bower:scss 23 | // endbower 24 | 25 | // Theme customization 26 | @import "theme/theme"; 27 | 28 | // Global styling 29 | @import "hacks"; 30 | @import "helpers"; 31 | 32 | // Do not remove the comments below. It's the markers used by gulp-inject to inject all your style files 33 | // from components automatically. 34 | // inject:styles 35 | // endinject 36 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/shell/__material.shell.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 28 |
29 | 30 | 31 |
32 | 33 |
34 | -------------------------------------------------------------------------------- /generators/app/templates/docs/coding-guides/javascript.md: -------------------------------------------------------------------------------- 1 | # JavaScript coding guide 2 | 3 | As a general rule, it is a good idea to get inspiration from the community-approved 4 | [AngularJS style guide](https://github.com/johnpapa/angular-styleguide). 5 | 6 | This starter kit architecture and base template tries to comply with most of the rules described there. 7 | 8 | ## Naming convention 9 | 10 | - Use `camelCase` everywhere (properties and methods), except for: 11 | * Class names and constructors which should use `PascalCase` 12 | * Constants should be all in UPPERCASE, like `var MY_CONSTANT = 0;` 13 | - File names should always be in `kebab-case` 14 | 15 | ## Coding rules 16 | 17 | - Use single quotes `'` for strings 18 | - Dependency injection order: start with the most generic (framework, external libs) to the most specific (project 19 | modules) 20 | - Use 1 line per dependency inject/import, to ease merges and improve readability 21 | - Use the `_` prefix for internal variable names 22 | - Only expose properties / methods publicly when it's needed, do not put everything in the `$scope` 23 | - Never put anything in the global scope 24 | - Always use strict equality checks: `===` and `!==` instead of `==` or `!=` to avoid comparison pitfalls (see 25 | [JavaScript equality table](https://dorey.github.io/JavaScript-Equality-Table/)) 26 | - Use `[]` instead of `Array` 27 | -------------------------------------------------------------------------------- /generators/app/templates/sources/translations/_en-US.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Content-Type: text/plain; charset=UTF-8\n" 4 | "Content-Transfer-Encoding: 8bit\n" 5 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 6 | "Language: en-US\n" 7 | 8 | #: app.ts.js:157 9 | #: modules/shell/shell.html:30 10 | msgid "About" 11 | msgstr "About" 12 | 13 | #: app.ts.js:113 14 | #: modules/screens/about/about.html:7 15 | #: modules/shell/shell.html:17 16 | msgid "APP_NAME" 17 | msgstr "<%= props.appName || 'Awesome App' %>" 18 | 19 | #: modules/screens/home/home.html:7 20 | <% if (props.ui !== 'material') { -%> 21 | msgid "Hello world !" 22 | msgstr "Hello world !" 23 | <% } else { -%> 24 | msgid "Hello," 25 | msgstr "Hello," 26 | <% } -%> 27 | 28 | #: app.ts.js:147 29 | #: modules/shell/shell.html:24 30 | msgid "Home" 31 | msgstr "Home" 32 | 33 | <% if (props.ui === 'bootstrap') { -%> 34 | #: modules/shell/shell.html:9 35 | msgid "Toggle navigation" 36 | msgstr "Toggle navigation" 37 | 38 | <% } -%> 39 | #: modules/screens/about/about.html:10 40 | msgid "Version" 41 | msgstr "Version" 42 | 43 | <% if (props.ui === 'material') { -%> 44 | #: modules/screens/home/home.html:7 45 | msgid "Material Design world !" 46 | msgstr "Material Design world !" 47 | 48 | #: modules/screens/home/home.html:17 49 | msgid "Read more about Material Design" 50 | msgstr "Read more about Material Design" 51 | <% } -%> 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-angular-pro", 3 | "version": "2.2.4", 4 | "description": "Web/mobile Angular project generator for scalable, enterprise-grade applications (TypeScript, Sass, Bootstrap, Ionic, UI Router, Font Awesome, Gettext, Cordova...)", 5 | "repository": "angular-starter-kit/generator-angular-pro", 6 | "keywords": [ 7 | "yeoman-generator", 8 | "angular", 9 | "angularjs", 10 | "gulp", 11 | "cordova", 12 | "bootstrap", 13 | "ionic", 14 | "ios", 15 | "android", 16 | "scalable", 17 | "hybrid", 18 | "enterprise", 19 | "component", 20 | "framework", 21 | "scaffold", 22 | "boilerplate", 23 | "app", 24 | "mobile", 25 | "web", 26 | "pro" 27 | ], 28 | "author": "Yohan Lasorsa", 29 | "license": "MIT", 30 | "preferGlobal": true, 31 | "main": "index.js", 32 | "scripts": { 33 | "test": "scripts/test-generator.sh", 34 | "deploy": "scripts/update-starter-kit.sh", 35 | "postpublish": "git tag -a $npm_package_version -m '$npm_package_version' && git push --tags" 36 | }, 37 | "dependencies": { 38 | "chalk": "^1.1.1", 39 | "lodash": "^4.13.1", 40 | "node-dir": "^0.1.14", 41 | "yeoman-generator": "^1.1.0", 42 | "yosay": "^2.0.0" 43 | }, 44 | "engines": { 45 | "node": ">=6.0.0" 46 | }, 47 | "files": [ 48 | "generators/app" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This generator was inspired from the 2 | [gulp-angular](https://github.com/Swiip/generator-gulp-angular) Yeoman generator. 3 | Portions of project generator-gulp-angular are Copyright (c) 2014 Matthieu Lux & Mehdy Dara 4 | 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2015-2017 Thales Services SAS 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | git: 4 | depth: 1 5 | 6 | language: node_js 7 | node_js: 8 | - '6' 9 | - '7' 10 | - stable 11 | 12 | android: 13 | components: 14 | - android-24 15 | - platform-tools 16 | - tools 17 | 18 | addons: 19 | chrome: stable 20 | 21 | matrix: 22 | fast_finish: true 23 | 24 | env: 25 | global: 26 | secure: PimbLN6TbLkL9BLpmNgvdQQJO2NQKGm7y3iYCwgUT8AwTbeQ/lMV31pxDWDyOlut94SA4TtcvCJnTumY2Cc+TucacDTDgkSrHSaJraMCXqXbeh232jfcHij/SWmrX2hPiwjFl95FOt5csUUeBGzPLFpP42VuraBdxvc26tWBTs3O/sf5wIVRqCe3NxdUu1fZg4sZ/fYBCrKE9JhUoXWyAAM7pEdEZKkGuRmTAhoOpz8jTM9PX5wjsl838EDYDlDpCsgJnewFwZp+soryrzC2hTBUHyR6oeIfE1KgM0s0n0l4U4TgGj05QgVEc11rBI+sV4womhM9b5ycuH3XEmc5umflpcSk4nGERgF/wLoFEBZDwbK3Ly/eHlM54pqgH/a8Q+FY5KMS5Md97JVjzrJcRVDBB+Uk3PVN+Y/Ah7DtRLZR4zkmEHfZc6CeX832pfBzd2YXvqpMda/ttyd8uP6knS/SOS78UrcX5an8ABzkQJVdA0fRNuWLXRQDGpFqgzb31WwhVEPEeAPTYDQsiffAxruDcm3ncip663VKeA/iLn/UOqhiXtKqr1UdeUL5HgRlkJVw/+cqWSo+zrerIspfnpNzC0NfYiO6VLXuJccpKRPiwX1Q9dHnihI99rg4PSjADlxx7VQOuPyw6agrvvRIfZDqfF7jtKOctRGh+y0ROj8= 27 | 28 | install: 29 | - npm install -g yo gulp bower 30 | - npm install 31 | - npm link 32 | 33 | before_script: 34 | - export DISPLAY=:99.0 35 | - sh -e /etc/init.d/xvfb start 36 | - export ANDROID_HOME=$PWD/android-sdk-linux 37 | - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools 38 | 39 | script: 40 | - npm test -------------------------------------------------------------------------------- /generators/app/templates/sources/translations/_fr-FR.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Content-Type: text/plain; charset=UTF-8\n" 4 | "Content-Transfer-Encoding: 8bit\n" 5 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 6 | "Language: fr-FR\n" 7 | 8 | #: app.ts.js:157 9 | #: modules/shell/shell.html:30 10 | msgid "About" 11 | msgstr "A propos" 12 | 13 | #: app.ts.js:113 14 | #: modules/screens/about/about.html:7 15 | #: modules/shell/shell.html:17 16 | msgid "APP_NAME" 17 | msgstr "<%= props.appName || 'Awesome App' %>" 18 | 19 | #: modules/screens/home/home.html:7 20 | <% if (props.ui !== 'material') { -%> 21 | msgid "Hello world !" 22 | msgstr "Bonjour le monde !" 23 | <% } else { -%> 24 | msgid "Hello," 25 | msgstr "Bonjour," 26 | <% } -%> 27 | 28 | #: app.ts.js:147 29 | #: modules/shell/shell.html:24 30 | msgid "Home" 31 | msgstr "Accueil" 32 | 33 | <% if (props.ui === 'bootstrap') { -%> 34 | #: modules/shell/shell.html:9 35 | msgid "Toggle navigation" 36 | msgstr "Basculer la navigation" 37 | 38 | <% } -%> 39 | #: modules/screens/about/about.html:10 40 | msgid "Version" 41 | msgstr "Version" 42 | 43 | <% if (props.ui === 'material') { -%> 44 | #: modules/screens/home/home.html:7 45 | msgid "Material Design world !" 46 | msgstr "le monde Material Design !" 47 | 48 | #: modules/screens/home/home.html:17 49 | msgid "Read more about Material Design" 50 | msgstr "Plus d'infos sur Material Design" 51 | <% } -%> 52 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/web-services/quote/quote.service.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {RestService} from 'helpers/rest/rest.service'; 3 | import {ContextService} from 'helpers/context/context.service'; 4 | 5 | /** 6 | * Quote service: allows to get quote of the day. 7 | */ 8 | export class QuoteService { 9 | 10 | private ROUTES = { 11 | randomJoke: '/jokes/random?escape=javascript&limitTo=[:category]' 12 | }; 13 | 14 | constructor(private $q: ng.IQService, 15 | private restService: RestService, 16 | private contextService: ContextService) { 17 | } 18 | 19 | /** 20 | * Get a random Chuck Norris joke. 21 | * Used context properties: 22 | * - category: the joke's category: 'nerdy', 'explicit'... 23 | * @param {!Object} context The context to use. 24 | * @return {Object} The promise. 25 | */ 26 | getRandomJoke(context: any): ng.IPromise { 27 | return this.restService 28 | .get(this.contextService.inject(this.ROUTES.randomJoke, context), null, true) 29 | .then((response: any) => { 30 | if (response.data && response.data.value) { 31 | return response.data.value.joke; 32 | } 33 | return this.$q.reject(); 34 | }) 35 | .catch(() => { 36 | return 'Error, could not load joke :-('; 37 | }); 38 | } 39 | 40 | } 41 | 42 | app.service('quoteService', QuoteService); 43 | -------------------------------------------------------------------------------- /scripts/test-generator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Simple testing script, that generates all kinds of projects and checks that 4 | # generated projects build and pass tests. 5 | 6 | set -e 7 | 8 | CWD=`pwd` 9 | SCRIPT_FOLDER=`dirname "${BASH_SOURCE[0]}"` 10 | TEST_FOLDER=$CWD/sample-app 11 | CACHE_FOLDER=$CWD/cache 12 | TEST_APP_NAME="Sample App" 13 | TEST_CASES=$SCRIPT_FOLDER/test-cases/**/*.json 14 | 15 | function cleanup() { 16 | cd $CWD 17 | rm -rf $TEST_FOLDER 18 | rm -rf $CACHE_FOLDER 19 | } 20 | 21 | # Cleanup test folder in case of error 22 | trap cleanup ERR 23 | 24 | mkdir -p $CACHE_FOLDER 25 | 26 | for file in $TEST_CASES 27 | do 28 | 29 | mkdir -p $TEST_FOLDER 30 | cd $TEST_FOLDER 31 | 32 | if [ -d $CACHE_FOLDER/node_modules ]; then 33 | mv $CACHE_FOLDER/node_modules . 34 | fi 35 | 36 | echo 37 | echo ------------------------------------------------------------- 38 | echo Testing generator with $file 39 | echo ------------------------------------------------------------- 40 | echo 41 | 42 | yo angular-pro --automate "$CWD/$file" $TEST_APP_NAME 43 | 44 | gulp test 45 | gulp clean && gulp build 46 | 47 | # Dunno why, but this now fails with timeout randomly on Travis... 48 | # gulp clean && gulp protractor 49 | # gulp clean && gulp protractor:dist 50 | 51 | mv node_modules $CACHE_FOLDER 52 | 53 | cd $CWD 54 | rm -rf $TEST_FOLDER 55 | 56 | done 57 | -------------------------------------------------------------------------------- /generators/app/templates/docs/i18n.md: -------------------------------------------------------------------------------- 1 | # Internationalization 2 | 3 | The i18n of the application is managed by [angular-gettext](https://angular-gettext.rocketeer.be). 4 | 5 | ## Adding translatable strings 6 | 7 | ### In HTML code 8 | 9 | Use the `translate` directive on an HTML element to automatically translate its content: 10 | ```html 11 | This text will be translated. 12 | ``` 13 | 14 | You can also use the `translate` filter if needed: 15 | ```html 16 | 17 | ``` 18 | You should use it only when the `translate` directive is not applicable, as filters have a negative impact on 19 | performance if too many are used at the same time. 20 | 21 | ### In JavaScript code 22 | 23 | If you need to have translatable strings in JavaScript code, inject the `gettext` AngularJS dependency in wrap your 24 | string using the `gettext()` method: 25 | ```js 26 | var title = gettext('My page title'); 27 | ``` 28 | 29 | ## Extracting strings to translate 30 | 31 | Once you are ready to translate your app, just run the `gulp translations:extract` task. 32 | It will create a `template.pot` file in the `sources/translations` folder. 33 | 34 | You can then use software like [Poedit](http://www.poedit.net) to generate the `.po` files for each of your supported 35 | languages, and put them in the `sources/translations` folder. 36 | 37 | Do no forget to edit the `main.constants.*` file to add the supported languages of your application. 38 | -------------------------------------------------------------------------------- /generators/app/templates/docs/coding-guides/html.md: -------------------------------------------------------------------------------- 1 | # HTML coding guide 2 | 3 | ## Naming conventions 4 | 5 | - Everything should be named in `kebab-case` (lowercase words separated with a `-`): tags, attributes, IDs, etc 6 | - Do not use the `data-` prefix for angular directives, and feel free to add your own custom elements (yes, it will 7 | not be compliant to the W3C validator for now) 8 | - File names should always be in `kebab-case` 9 | 10 | ## Coding rules 11 | 12 | - Use HTML5 doctype: `` 13 | - Use HTML semantics according to its purpose 14 | - Use double quotes `"` around attribute values in tags 15 | - Use a new line for every block, list, or table element, and indent every such child element 16 | - Clearly Separate structure (HTML) from presentation (CSS) from behavior (JavaScript): 17 | * Never use inline CSS or JavaScript 18 | * Keep controller logic out of the HTML 19 | - `type` attribute for stylesheets and script tags should be omitted 20 | - Use valid HTML where possible 21 | 22 | ## Pitfalls 23 | 24 | - **Block**-type tags cannot be nested inside **inline**-type tags: a `
` tag cannot be nested in a `` 25 | - HTML is **not** XML: empty tags cannot be self-closing and will result in improper results 26 | * `
` will be interpreted as a simple `
` without closing tag! 27 | * The only tags that allows self-closing are the one that does not require a closing tag in first place: 28 | these are the void elements that do not not accept content `
`, `
`, ``, ``, ``, `` 29 | (and others). 30 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/_main.routes.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | 3 | /** 4 | * Configures the application routes. 5 | */ 6 | function routeConfig($stateProvider: angular.ui.IStateProvider, 7 | $urlRouterProvider: angular.ui.IUrlRouterProvider, 8 | gettext: angular.gettext.gettextFunction) { 9 | 10 | // Routes configuration 11 | $urlRouterProvider.otherwise('/'); 12 | 13 | $stateProvider 14 | .state('app', { 15 | template: require('shell/shell.html'), 16 | controller: 'shellController as shell' 17 | }) 18 | .state('app.home', { 19 | url: '/', 20 | <% if (props.ui === 'ionic') { -%> 21 | views: { 22 | 'menuContent': { 23 | template: require('screens/home/home.html'), 24 | controller: 'homeController as vm' 25 | } 26 | }, 27 | <% } else { -%> 28 | template: require('screens/home/home.html'), 29 | controller: 'homeController as vm', 30 | <% } -%> 31 | data: {title: gettext('Home')} 32 | }) 33 | .state('app.about', { 34 | url: '/about', 35 | <% if (props.ui === 'ionic') { -%> 36 | views: { 37 | 'menuContent': { 38 | template: require('screens/about/about.html'), 39 | controller: 'aboutController as vm' 40 | } 41 | }, 42 | <% } else { -%> 43 | template: require('screens/about/about.html'), 44 | controller: 'aboutController as vm', 45 | <% } -%> 46 | data: {title: gettext('About')} 47 | }); 48 | 49 | } 50 | 51 | app.config(routeConfig); 52 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/main.config.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {IApplicationConfig} from 'main.constants'; 3 | import {ILogger} from 'helpers/logger/logger'; 4 | 5 | /** 6 | * Configures the application (before running). 7 | */ 8 | function mainConfig($provide: ng.auto.IProvideService, 9 | $compileProvider: ng.ICompileProvider, 10 | $locationProvider: ng.ILocationProvider, 11 | $qProvider: any, 12 | config: IApplicationConfig) { 13 | 14 | // Extend the $exceptionHandler service to output logs. 15 | $provide.decorator('$exceptionHandler', ($delegate: any, $injector: any) => { 16 | return (exception: any, cause: any) => { 17 | $delegate(exception, cause); 18 | 19 | let logger: ILogger = $injector.get('logger').getLogger('exceptionHandler'); 20 | logger.error(exception + (cause ? ' (' + cause + ')' : '')); 21 | }; 22 | }); 23 | 24 | // Disable debug logs in production version 25 | $provide.decorator('$log', ($delegate: any) => { 26 | if (!config.environment.debug) { 27 | $delegate.log = angular.noop; 28 | $delegate.debug = angular.noop; 29 | } 30 | return $delegate; 31 | }); 32 | 33 | // Disable angular debug info in production version 34 | $compileProvider.debugInfoEnabled(config.environment.debug); 35 | 36 | // Use no hash prefix for routing 37 | $locationProvider.hashPrefix(''); 38 | 39 | // Disable exception on unhandled rejections (we have our own handler) 40 | $qProvider.errorOnUnhandledRejections(false); 41 | } 42 | 43 | app.config(mainConfig); 44 | 45 | -------------------------------------------------------------------------------- /scripts/update-starter-kit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Deploy web/bootstrap and mobile/ionic generated projects to starter-kit repository 4 | 5 | set -e 6 | 7 | CWD=`pwd` 8 | VERSION=`node -p -e "require('./package.json').version"` 9 | SCRIPT_FOLDER=$CWD/`dirname "${BASH_SOURCE[0]}"` 10 | DEPLOY_FOLDER=$CWD/deploy 11 | DEPLOY_APP_NAME="Starter Kit" 12 | REPOSITORY=https://$GITHUB_TOKEN@github.com/angular-starter-kit/starter-kit.git 13 | 14 | function cleanup() { 15 | cd $CWD 16 | rm -rf $DEPLOY_FOLDER 17 | } 18 | 19 | function prepare_repo() { 20 | mkdir -p $DEPLOY_FOLDER 21 | cd $DEPLOY_FOLDER 22 | 23 | git init 24 | git pull $REPOSITORY $BRANCH 25 | git rm -rf . 26 | git clean -fxd 27 | } 28 | 29 | function update_repo() { 30 | git reset HEAD README.md 31 | git checkout -- README.md 32 | git add -A 33 | git commit -m "Updated from generator v$VERSION" 34 | 35 | if [ "$BRANCH" == "master" ]; then 36 | git tag -a v$VERSION -m "v$VERSION"; 37 | else 38 | git tag -a v$VERSION+$BRANCH -m "v$VERSION+$BRANCH"; 39 | fi 40 | 41 | git push $REPOSITORY HEAD:$BRANCH 42 | git push $REPOSITORY HEAD:$BRANCH --tags 43 | 44 | cleanup 45 | } 46 | 47 | # Cleanup deploy folder in case of error 48 | trap cleanup ERR 49 | 50 | # Use web/bootstrap for master branch 51 | BRANCH=master 52 | prepare_repo 53 | yo angular-pro --automate "$SCRIPT_FOLDER/test-cases/web/bootstrap.json" "$DEPLOY_APP_NAME" 54 | update_repo 55 | 56 | # Use mobile/ionic for mobile branch 57 | BRANCH=mobile 58 | prepare_repo 59 | yo angular-pro --automate "$SCRIPT_FOLDER/test-cases/mobile/ionic.json" "$DEPLOY_APP_NAME" 60 | update_repo 61 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/shell/__ionic.shell.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

APP_NAME

18 |
19 | 20 | 21 | 22 | 23 | 24 | Home 25 | 26 | 27 | 28 | 29 | 30 | About 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/typings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var process = require('child_process'); 5 | var gutil = require('gulp-util'); 6 | var typings = require('../typings.json'); 7 | 8 | var $ = require('gulp-load-plugins')({ 9 | pattern: ['gulp-*', 'del'] 10 | }); 11 | 12 | gulp.task('typings', ['typings:restore'], function(done) { 13 | // Adapted from https://gist.github.com/ibratoev/0caca1b3b7a122595523f790e2620301 14 | process.exec('typings ls', function(error, _, stderr) { 15 | if (error) { 16 | done(new gutil.PluginError('typings', 'Error: ' + error)); 17 | return; 18 | } 19 | if (stderr) { 20 | var lines = stderr.match(/[^\r\n]+/g); 21 | lines.forEach(function(line) { 22 | var re = /registry:(\S*)\/(\S*)(#|$)/; 23 | var m = re.exec(line); 24 | if (m !== null) { 25 | var source = m[1]; 26 | var name = m[2]; 27 | var isGlobal = typings.globalDependencies && typings.globalDependencies[name]; 28 | var isLocal = typings.dependencies && typings.dependencies[name]; 29 | if (isGlobal === isLocal) { 30 | gutil.log('Error searching for typings: ' + name); 31 | return; 32 | } 33 | gutil.log('Updating typings for ' + name); 34 | process.execSync('typings i ' + source + '~' + name + ' -S ' + (isGlobal ? '-G' : '')); 35 | } 36 | }); 37 | done(); 38 | } 39 | else { 40 | gutil.log('Typings are up to date.'); 41 | done(); 42 | } 43 | }); 44 | }); 45 | 46 | gulp.task('typings:restore', $.shell.task('typings install')); 47 | 48 | gulp.task('typings:clean', function() { 49 | return $.del(['typings']); 50 | }); 51 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/_main.constants.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {IServerConfig} from 'helpers/rest/rest.service'; 3 | 4 | export interface IApplicationConfig { 5 | version: string; 6 | environment: IApplicationEnvironment; 7 | supportedLanguages: Array; 8 | } 9 | 10 | export interface IApplicationEnvironment { 11 | debug: boolean; 12 | server: IServerConfig; 13 | } 14 | 15 | // Do not remove the comments below, or change the values. It's the markers used by gulp build task to change the 16 | // value of the config constant when building the application, while removing the code below for all environments. 17 | // replace:environment 18 | let environment = { 19 | local: { 20 | debug: true, 21 | 22 | // REST backend configuration, used for all web services using restService 23 | server: { 24 | url: '', 25 | route: 'api' 26 | } 27 | }, 28 | production: { 29 | debug: false, 30 | server: { 31 | <% if (props.target === 'web') { -%> 32 | url: '', 33 | route: 'api' 34 | <% } else { -%> 35 | url: 'http://api.icndb.com', 36 | route: '' 37 | <% } -%> 38 | } 39 | } 40 | }; 41 | // endreplace 42 | 43 | /** 44 | * Defines app-level configuration. 45 | */ 46 | let config: IApplicationConfig = { 47 | 48 | // Do not remove the comments below, or change the values. It's the markers used by gulp build task to inject app 49 | // version from package.json and environment values. 50 | // replace:constant 51 | version: 'dev', 52 | environment: environment.local, 53 | // endreplace 54 | 55 | // Supported languages 56 | supportedLanguages: [ 57 | 'en-US', 58 | 'fr-FR' 59 | ] 60 | 61 | }; 62 | 63 | app.constant('config', config); 64 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | var wiredep = require('wiredep').stream; 7 | var _ = require('lodash'); 8 | var browserSync = require('browser-sync'); 9 | 10 | var $ = require('gulp-load-plugins')(); 11 | 12 | function buildStyles() { 13 | var mainFolder = path.join(conf.paths.src, conf.paths.main); 14 | 15 | var sassOptions = { 16 | outputStyle: 'expanded', 17 | precision: 10, 18 | includePaths: conf.sassIncludePaths 19 | }; 20 | 21 | var injectFiles = gulp.src([ 22 | path.join(mainFolder, '/**/*.scss'), 23 | path.join('!' + mainFolder, '/*.scss'), 24 | path.join('!' + mainFolder, '/theme/*.scss') 25 | ], {read: false}); 26 | 27 | var injectOptions = { 28 | transform: function(filePath) { 29 | filePath = filePath.replace(mainFolder, ''); 30 | return '@import "' + filePath + '";'; 31 | }, 32 | starttag: '// inject:styles', 33 | endtag: '// endinject', 34 | relative: true, 35 | addRootSlash: false 36 | }; 37 | 38 | return gulp.src(path.join(mainFolder, 'main.scss')) 39 | .pipe($.inject(injectFiles, injectOptions)) 40 | .pipe(wiredep(_.extend({}, conf.wiredep))) 41 | .pipe($.sourcemaps.init()) 42 | .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) 43 | .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) 44 | .pipe($.sourcemaps.write()) 45 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/css/'))); 46 | } 47 | 48 | gulp.task('styles', function() { 49 | return buildStyles(); 50 | }); 51 | 52 | gulp.task('styles:reload', ['styles'], function() { 53 | return buildStyles().pipe(browserSync.stream()); 54 | }); 55 | -------------------------------------------------------------------------------- /generators/app/templates/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globalstrict": true, 3 | "es3": false, 4 | "forin": true, 5 | "freeze": true, 6 | "immed": true, 7 | "node": true, 8 | "browser": true, 9 | "esnext": true, 10 | "bitwise": true, 11 | "camelcase": true, 12 | "curly": true, 13 | "eqeqeq": true, 14 | "indent": 2, 15 | "latedef": false, 16 | "newcap": true, 17 | "noarg": true, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": true, 21 | "strict": true, 22 | "trailing": true, 23 | "smarttabs": true, 24 | "devel": true, 25 | "maxparams": 10, 26 | "maxdepth": 5, 27 | "maxstatements": 40, 28 | "maxcomplexity": 8, 29 | "maxlen": 120, 30 | "noempty": true, 31 | "nonbsp": true, 32 | "nonew": true, 33 | "plusplus": false, 34 | "asi": false, 35 | "boss": false, 36 | "debug": false, 37 | "eqnull": true, 38 | "evil": false, 39 | "expr": false, 40 | "funcscope": false, 41 | "iterator": false, 42 | "lastsemic": false, 43 | "laxbreak": false, 44 | "laxcomma": false, 45 | "loopfunc": true, 46 | "maxerr": 50, 47 | "moz": false, 48 | "multistr": false, 49 | "notypeof": false, 50 | "proto": false, 51 | "scripturl": false, 52 | "shadow": false, 53 | "sub": true, 54 | "supernew": false, 55 | "validthis": false, 56 | "noyield": false, 57 | 58 | "globals": { 59 | "angular": false, 60 | "module": true, 61 | "cordova": false, 62 | "$": false, 63 | 64 | "jasmine": true, 65 | "inject": true, 66 | "describe": true, 67 | "beforeEach": true, 68 | "afterEach": true, 69 | "expect": true, 70 | "it": true, 71 | "spyOn": true, 72 | 73 | "browser": true, 74 | "element": true, 75 | "by": true, 76 | "protractor": true, 77 | 78 | "bower": true 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var conf = require('../gulpfile.config'); 5 | 6 | var browserSync = require('browser-sync'); 7 | var browserSyncSpa = require('browser-sync-spa'); 8 | var proxyMiddleware = require('http-proxy-middleware'); 9 | var minimist = require('minimist'); 10 | 11 | var options = minimist(process.argv.slice(2), { 12 | boolean: 'skip-open', 13 | alias: { s: 'skip-open' } 14 | }); 15 | 16 | var open = options['skip-open'] ? [] : 'default'; 17 | 18 | function browserSyncInit(baseDir, browser, done) { 19 | var server = { 20 | baseDir: baseDir, 21 | middleware: [] 22 | }; 23 | 24 | var agent = conf.corporateProxyAgent(); 25 | 26 | // We activate a server proxy if we found a configuration for it. 27 | conf.backendProxy.forEach(function(proxyRoute) { 28 | var options = proxyRoute.options; 29 | 30 | if (agent) { 31 | options.agent = agent; 32 | } 33 | 34 | server.middleware.push(proxyMiddleware(proxyRoute.context, options)); 35 | }); 36 | 37 | browserSync.instance = browserSync.init({ 38 | startPath: '/', 39 | server: server, 40 | browser: browser 41 | }, done); 42 | } 43 | 44 | browserSync.use(browserSyncSpa({ 45 | selector: '[ng-app]'// Only needed for angular apps 46 | })); 47 | 48 | gulp.task('serve', ['watch'], function(done) { 49 | browserSyncInit([conf.paths.tmp, conf.paths.src], open, done); 50 | }); 51 | 52 | gulp.task('serve:dist', ['build'], function(done) { 53 | browserSyncInit(conf.paths.dist, open, done); 54 | }); 55 | 56 | gulp.task('serve:e2e', ['inject'], function(done) { 57 | browserSyncInit([conf.paths.tmp, conf.paths.src], [], done); 58 | }); 59 | 60 | gulp.task('serve:e2e-dist', ['build'], function(done) { 61 | browserSyncInit(conf.paths.dist, [], done); 62 | }); 63 | -------------------------------------------------------------------------------- /generators/app/templates/docs/_proxy.md: -------------------------------------------------------------------------------- 1 | # Working behind a corporate proxy 2 | 3 | ## Environment 4 | 5 | Most tools (including npm, bower and git) use the `HTTP_PROXY` and `HTTPS_PROXY` environment variables to work with a 6 | corporate proxy. 7 | 8 | ### Windows 9 | 10 | In Windows environments, add the `HTTP_PROXY` and `HTTPS_PROXY` system environment variable, with these values: 11 | 12 | - HTTP_PROXY: `http://:@:` 13 | - HTTPS_PROXY: `%HTTP_PROXY%` 14 | 15 | ### Unix 16 | 17 | Add these lines to your `~/.bash_profile` or `~/.profile`: 18 | ```sh 19 | export HTTP_PROXY="http://:@:" 20 | export HTTPS_PROXY="$HTTP_PROXY" 21 | ``` 22 | 23 | ## Proxy with SSL custom certificate 24 | 25 | Some proxy like **zscaler** use a custom SSL certificate to inspect request, which may cause npm/bower commands to 26 | fail. 27 | 28 | To solve this problem, you can disable the `strict-ssl` option in both npm and bower. 29 | 30 | <% if (props.target !== 'web') { -%> 31 | Also, if you have trouble building your Cordova app for Android, see the related section in the 32 | [Cordova documentation](cordova.md). 33 | 34 | <% } -%> 35 | ## Proxy exceptions 36 | 37 | If you need to access repositories on your local network that should bypass proxy, set the `NO_PROXY` environment 38 | variable, in the same way as `HTTP_PROXY`: 39 | 40 | ### Windows 41 | 42 | - NO_PROXY: `127.0.0.1, localhost, ` 43 | 44 | ### Unix 45 | 46 | ```sh 47 | export NO_PROXY="127.0.0.1, localhost, " 48 | ``` 49 | 50 | ### Bower 51 | 52 | Add this line to the `.bowerrc` file: 53 | ```json 54 | "strict-ssl": false 55 | ``` 56 | 57 | ### Npm 58 | 59 | Run this command in your project directory: 60 | ```sh 61 | npm set strict-ssl false 62 | ``` 63 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/shell/_shell.controller.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | <% if (props.ui !== 'ionic') { -%> 3 | import {IApplicationConfig} from 'main.constants'; 4 | <% } -%> 5 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 6 | 7 | /** 8 | * Displays the SPA shell. 9 | * The shell contains the shared parts of the application: header, footer, navigation... 10 | */ 11 | export class ShellController { 12 | 13 | currentLocale: ng.ILocaleService; 14 | <% if (props.ui !== 'ionic') { -%> 15 | languages: string[]; 16 | menuHidden: boolean; 17 | <% } -%> 18 | 19 | private logger: ILogger; 20 | 21 | constructor(private $state: ng.ui.IStateService, 22 | $locale: ng.ILocaleService, 23 | private _: _.LoDashStatic, 24 | <% if (props.ui !== 'ionic') { -%> 25 | config: IApplicationConfig, 26 | <% } -%> 27 | logger: LoggerService) { 28 | 29 | this.currentLocale = $locale; 30 | this.logger = logger.getLogger('shell'); 31 | <% if (props.ui !== 'ionic') { -%> 32 | this.languages = config.supportedLanguages; 33 | this.menuHidden = true; 34 | <% } -%> 35 | 36 | this.logger.log('init'); 37 | } 38 | 39 | <% if (props.ui !== 'ionic') { -%> 40 | /** 41 | * Toggles navigation menu visibility on mobile platforms. 42 | */ 43 | toggleMenu() { 44 | this.menuHidden = !this.menuHidden; 45 | } 46 | 47 | <% } -%> 48 | /** 49 | * Checks if the specified name is contained in the current navigation state. 50 | * @param {string} name The state name to check. 51 | * @return {boolean} True if the specified name is contained in the current navigation state. 52 | */ 53 | stateContains(name: string): boolean { 54 | return this._.startsWith(this.$state.current.name, name); 55 | } 56 | 57 | } 58 | 59 | app.controller('shellController', ShellController); 60 | -------------------------------------------------------------------------------- /generators/app/templates/docs/api-proxy.md: -------------------------------------------------------------------------------- 1 | # API proxy 2 | 3 | Usually when working on a web application you consume data from custom-made APIs. 4 | 5 | To ease development with our development server integrating live reload while keeping your API calls working, we also 6 | have setup an API proxy to redirect API calls to whatever URL and port you want. This allows you: 7 | 8 | - To develop frontend features without the need to run an API backend locally 9 | - To use the development server without [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) issues 10 | when making API calls 11 | - To debug frontend code with data from testing platform directly 12 | 13 | ## How to configure 14 | 15 | In the root folder you will find a `gulpfile.config.js`, containing the API proxy configuration. 16 | 17 | The interesting part is there: 18 | ```js 19 | exports.backendProxy = [ 20 | { 21 | context: '/api', 22 | options: { 23 | pathRewrite: {'^/api': ''}, 24 | target: 'http://api.icndb.com', 25 | changeOrigin: true 26 | } 27 | } 28 | ]; 29 | ``` 30 | 31 | This is where you can setup one or more proxy rules. 32 | 33 | For the complete set of options, see the `http-proxy-middleware` 34 | [documentation](https://github.com/chimurai/http-proxy-middleware/). 35 | 36 | ### Corporate proxy support 37 | 38 | To allow API calls redirection through a corporate proxy, you will also find a `corporateProxyAgent()` function 39 | in the gulp configuration file. By default, this method configures a corporate proxy agent based on the 40 | `HTTP_PROXY` environment variable, see the [proxy documentation](proxy.md) for more details. 41 | 42 | If you need to, you can further customize this function to fit the network of your working environment. 43 | 44 | If your corporate proxy use a custom SSL certificate, your may need to add the `secure: false` option to your 45 | backend proxy configuration. 46 | -------------------------------------------------------------------------------- /generators/app/templates/protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var conf = require('./gulpfile.config'); 4 | var SpecReporter = require('jasmine-spec-reporter').SpecReporter; 5 | var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter'); 6 | 7 | var reporter = new HtmlScreenshotReporter({ 8 | dest: 'reports/e2e/html' 9 | }); 10 | 11 | // An example configuration file. 12 | exports.config = { 13 | // The address of a running selenium server. 14 | //seleniumAddress: 'http://localhost:4444/wd/hub', 15 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 16 | 17 | // Capabilities to be passed to the webdriver instance. 18 | capabilities: { 19 | 'browserName': process.env.PROTRACTOR_BROWSER || 'chrome' 20 | }, 21 | 22 | framework: 'jasmine2', 23 | 24 | // Only works with Chrome and Firefox 25 | directConnect: true, 26 | 27 | baseUrl: 'http://localhost:3000', 28 | 29 | // Spec patterns are relative to the current working directly when 30 | // protractor is called. 31 | specs: [conf.paths.e2e + '/**/*.js'], 32 | 33 | // Options to be passed to Jasmine-node. 34 | jasmineNodeOpts: { 35 | showColors: true, 36 | defaultTimeoutInterval: 30000, 37 | print: function() {} 38 | }, 39 | 40 | // Setup the report before any tests start 41 | beforeLaunch: function() { 42 | return new Promise(function(resolve){ 43 | reporter.beforeLaunch(resolve); 44 | }); 45 | }, 46 | onPrepare: function() { 47 | // Add better console spec reporter 48 | jasmine.getEnv().addReporter(new SpecReporter({})); 49 | 50 | // Reporter in html with a screenshot for each test. 51 | jasmine.getEnv().addReporter(reporter); 52 | }, 53 | 54 | // Close the report after all tests finish 55 | afterLaunch: function(exitCode) { 56 | return new Promise(function(resolve){ 57 | reporter.afterLaunch(resolve.bind(this, exitCode)); 58 | }); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/theme/__bootstrap.bootstrap.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Override Bootstrap module inclusion, to allow selecting only the needed modules. 3 | * This file content was copied from libraries/bootstrap-sass/assets/stylesheets/_bootstrap.scss 4 | */ 5 | 6 | /*! 7 | * Bootstrap v3.3.6 (http://getbootstrap.com) 8 | * Copyright 2011-2015 Twitter, Inc. 9 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 10 | */ 11 | 12 | // Core variables and mixins 13 | @import "bootstrap/variables"; 14 | @import "bootstrap/mixins"; 15 | 16 | // Reset and dependencies 17 | @import "bootstrap/normalize"; 18 | @import "bootstrap/print"; 19 | //@import "bootstrap/glyphicons"; 20 | 21 | // Core CSS 22 | @import "bootstrap/scaffolding"; 23 | @import "bootstrap/type"; 24 | @import "bootstrap/code"; 25 | @import "bootstrap/grid"; 26 | @import "bootstrap/tables"; 27 | @import "bootstrap/forms"; 28 | @import "bootstrap/buttons"; 29 | 30 | // Components 31 | @import "bootstrap/component-animations"; 32 | @import "bootstrap/dropdowns"; 33 | @import "bootstrap/button-groups"; 34 | @import "bootstrap/input-groups"; 35 | @import "bootstrap/navs"; 36 | @import "bootstrap/navbar"; 37 | @import "bootstrap/breadcrumbs"; 38 | @import "bootstrap/pagination"; 39 | @import "bootstrap/pager"; 40 | @import "bootstrap/labels"; 41 | @import "bootstrap/badges"; 42 | @import "bootstrap/jumbotron"; 43 | @import "bootstrap/thumbnails"; 44 | @import "bootstrap/alerts"; 45 | @import "bootstrap/progress-bars"; 46 | @import "bootstrap/media"; 47 | @import "bootstrap/list-group"; 48 | @import "bootstrap/panels"; 49 | @import "bootstrap/responsive-embed"; 50 | @import "bootstrap/wells"; 51 | @import "bootstrap/close"; 52 | 53 | // Components w/ JavaScript 54 | @import "bootstrap/modals"; 55 | @import "bootstrap/tooltip"; 56 | @import "bootstrap/popovers"; 57 | @import "bootstrap/carousel"; 58 | 59 | // Utility classes 60 | @import "bootstrap/utilities"; 61 | @import "bootstrap/responsive-utilities"; 62 | -------------------------------------------------------------------------------- /generators/app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.projectName %>", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "angular-animate": "~1.6.2", 6 | "angular-sanitize": "~1.6.2", 7 | "angular-ui-router": "~0.4.2", 8 | "angular": "~1.6.2", 9 | "lodash": "~4.17.0", 10 | "angular-gettext": "~2.3.0", 11 | <% if (props.target !== 'web') { -%> 12 | "ngCordova": "~0.1.27-alpha", 13 | <% } if (props.ui === 'bootstrap') { -%> 14 | <% if (props.target !== 'web') { -%> 15 | "fastclick": "^1.0.6", 16 | <% } -%> 17 | "font-awesome": "~4.7.0", 18 | "angular-bootstrap": "~2.5.0", 19 | "bootstrap-sass": "~3.3.6" 20 | <% } if (props.ui === 'material') { -%> 21 | "font-awesome": "~4.6.2", 22 | "angular-material": "~1.0.8" 23 | <% } if (props.ui === 'ionic') { -%> 24 | "ionic": "~1.3.0" 25 | <% } -%> 26 | }, 27 | "devDependencies": { 28 | "angular-mocks": "~1.6.2", 29 | "jquery": "~3.2.1", 30 | "jasmine-jquery": "~2.1.1" 31 | }, 32 | "overrides": { 33 | <% if (props.ui === 'bootstrap') { -%> 34 | "font-awesome": { 35 | "main": [ 36 | "./scss/font-awesome.scss", 37 | "./fonts/*" 38 | ] 39 | }, 40 | "bootstrap-sass": { 41 | "main": [], 42 | "dependencies": [] 43 | } 44 | } 45 | <% } if (props.ui === 'material') { -%> 46 | "font-awesome": { 47 | "main": [ 48 | "./scss/font-awesome.scss", 49 | "./fonts/*" 50 | ] 51 | }, 52 | "angular-material": { 53 | "main": [ 54 | "./angular-material.js", 55 | "./angular-material.scss" 56 | ] 57 | } 58 | } 59 | <% } if (props.ui === 'ionic') { -%> 60 | "ionic": { 61 | "main": [ 62 | "release/fonts/*", 63 | "release/js/ionic.js", 64 | "release/js/ionic-angular.js" 65 | ] 66 | } 67 | }, 68 | "resolutions": { 69 | "angular-ui-router": "~0.4.2", 70 | "angular-sanitize": "~1.6.2", 71 | "angular": "~1.6.2", 72 | "angular-animate": "~1.6.2" 73 | } 74 | <% } -%> 75 | } 76 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/context/context.service.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 3 | 4 | /** 5 | * Context service: provides URL context injection based on specified context. 6 | */ 7 | export class ContextService { 8 | 9 | private logger: ILogger; 10 | 11 | constructor(logger: LoggerService) { 12 | this.logger = logger.getLogger('contextService'); 13 | } 14 | 15 | /** 16 | * Injects the specified context into the given REST API. 17 | * The REST API should be formatted like "/api/users/:userId". 18 | * Any fragment from the REST API starting with ":" will then be replaced by a property from the context with 19 | * the same name, i.e. for "/api/users/:userId" and a context object "{ userId: 123 }", the resulting URL will 20 | * be "/api/users/123". 21 | * @param {!string} restApi The REST API to fill will context values. 22 | * @param {Object} context The context to use. 23 | * @return {string} The ready-to-use REST API to call. 24 | */ 25 | inject(restApi: string, context?: any): string { 26 | this.logger.log('Injecting context in: ' + restApi); 27 | 28 | if (!context) { 29 | throw 'inject: context must be defined'; 30 | } 31 | 32 | // Search for context properties to inject 33 | let properties = restApi.match(/(:\w+)/g); 34 | 35 | angular.forEach(properties, (property: string) => { 36 | let contextVar = property.substring(1); 37 | let contextValue = context[contextVar]; 38 | 39 | if (contextValue !== undefined) { 40 | contextValue = encodeURIComponent(contextValue); 41 | restApi = restApi.replace(property, contextValue); 42 | this.logger.log('Injected ' + contextValue + ' for ' + property); 43 | } else { 44 | throw 'inject: context.' + contextVar + ' expected but undefined'; 45 | } 46 | }); 47 | 48 | this.logger.log('Resulting REST API: ' + restApi); 49 | 50 | return restApi; 51 | } 52 | 53 | } 54 | 55 | app.service('contextService', ContextService); 56 | -------------------------------------------------------------------------------- /generators/app/templates/docs/coding-guides/typescript.md: -------------------------------------------------------------------------------- 1 | # TypeScript coding guide 2 | 3 | [TypeScript](http://www.typescriptlang.org) is a superset of JavaScript, therefore all 4 | [JavaScript conventions and good practices](javascript.md) also applies here. Exceptions or changes to these rules 5 | are noted in this file. 6 | 7 | For TypeScript-specific rules, you can take cues from the 8 | [TypeScript Deep Dive Style Guide](https://basarat.gitbooks.io/typescript/content/docs/styleguide/styleguide.html), 9 | this is a great source for community-approved conventions. 10 | 11 | ## Naming conventions 12 | 13 | - Use `PascalCase` for type names and enum values 14 | - Do not use `_` as a prefix for private properties 15 | 16 | ## Coding rules 17 | 18 | - Do not export types/functions unless you need to share it across multiple components 19 | - Do not introduce new types/values to the global namespace 20 | - Use arrow functions over anonymous function expressions 21 | - Only surround arrow function parameters when necessary. 22 | For example, `(x) => x + x` is wrong but the following are correct: 23 | * `x => x + x` 24 | * `(x,y) => x + y` 25 | * `(x: T, y: T) => x === y` 26 | 27 | ## Definitions 28 | 29 | In order to infer types from JavaScript, the TypeScript language supports external type definitions. They are located 30 | in the `typings` folder. 31 | 32 | To automatically download or update typings for your bower dependencies, use the `gulp tsd` command. Note that removed 33 | dependencies will not be removed automatically, you need to removed them manually. This is by design, so you can add 34 | custom typings if needed in the `typings` folder. 35 | 36 | If you want to further manage your types definitions, you can use the [TSD](https://github.com/Definitelytyped/tsd) 37 | tool. 38 | 39 | ## Enforcement 40 | 41 | As with JavaScript, coding rules are enforced in this project, via [TSLint](https://github.com/palantir/tslint). 42 | 43 | ## Learn more 44 | 45 | The read of [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript) is recommended, this is the definitive 46 | reference book for TypeScript (and also open-source). 47 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/shell/__bootstrap.shell.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 48 |
49 | 50 | 51 |
52 | 53 |
54 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/logger/logger.spec.ts: -------------------------------------------------------------------------------- 1 | import {LoggerService} from 'logger'; 2 | 3 | describe('logger', () => { 4 | 5 | let logger; 6 | 7 | beforeEach(() => { 8 | angular.mock.module('app'); 9 | 10 | inject((_logger_: LoggerService) => { 11 | logger = _logger_; 12 | }); 13 | }); 14 | 15 | describe('addObserver', () => { 16 | 17 | it('should add a new observer to be notified of log entry', () => { 18 | // Arrange 19 | let observerSpy = jasmine.createSpy('observerSpy'); 20 | 21 | // Act 22 | logger.addObserver(observerSpy); 23 | 24 | let loggerInstance = logger.getLogger('unit test'); 25 | loggerInstance.log('hoho'); 26 | loggerInstance.info('toto'); 27 | loggerInstance.warning('popo'); 28 | loggerInstance.error('lolo'); 29 | 30 | // Assert 31 | expect(observerSpy).toHaveBeenCalled(); 32 | expect(observerSpy.calls.count()).toBe(4); 33 | expect(observerSpy).toHaveBeenCalledWith('hoho', 'unit test', 'log', undefined); 34 | expect(observerSpy).toHaveBeenCalledWith('toto', 'unit test', 'info', undefined); 35 | expect(observerSpy).toHaveBeenCalledWith('popo', 'unit test', 'warning', undefined); 36 | expect(observerSpy).toHaveBeenCalledWith('lolo', 'unit test', 'error', undefined); 37 | }); 38 | 39 | it('should add a new observer to be notified of log entry with no source', () => { 40 | // Arrange 41 | let observerSpy = jasmine.createSpy('observerSpy'); 42 | 43 | // Act 44 | logger.addObserver(observerSpy); 45 | let loggerInstance = logger.getLogger(); 46 | loggerInstance.log('hoho'); 47 | loggerInstance.info('toto'); 48 | loggerInstance.warning('popo'); 49 | loggerInstance.error('lolo'); 50 | 51 | // Assert 52 | expect(observerSpy).toHaveBeenCalled(); 53 | expect(observerSpy.calls.count()).toBe(4); 54 | expect(observerSpy).toHaveBeenCalledWith('hoho', undefined, 'log', undefined); 55 | expect(observerSpy).toHaveBeenCalledWith('toto', undefined, 'info', undefined); 56 | expect(observerSpy).toHaveBeenCalledWith('popo', undefined, 'warning', undefined); 57 | expect(observerSpy).toHaveBeenCalledWith('lolo', undefined, 'error', undefined); 58 | }); 59 | 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /generators/app/templates/sources/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% if (props.target !== 'mobile') { -%> 6 | 7 | <% } -%> 8 | 9 | 10 | <% if (props.target !== 'web') { -%> 11 | 12 | 16 | <% } else { -%> 17 | 18 | <% } -%> 19 | <% if (props.target !== 'mobile') { -%> 20 | 21 | <% } -%> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | <% if (props.target !== 'web') { -%> 35 | 36 | 45 | 46 | <% } -%> 47 | <% if (props.target !== 'mobile') { -%> 48 | 52 | 53 | <% } -%> 54 | <% if (props.ui === 'ionic') { -%> 55 | 56 | <% } else { -%> 57 |
58 | <% } -%> 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /generators/app/templates/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "ban": [true, 4 | ["_", "extend"], 5 | ["_", "isNull"], 6 | ["_", "isDefined"] 7 | ], 8 | "class-name": true, 9 | "comment-format": [true, 10 | "check-space" 11 | ], 12 | "curly": true, 13 | "eofline": true, 14 | "forin": true, 15 | "indent": [true, 2], 16 | "interface-name": true, 17 | "jsdoc-format": true, 18 | "new-parens": true, 19 | "label-position": true, 20 | "max-line-length": [false, 120], 21 | "member-ordering": [true, 22 | "public-before-private", 23 | "static-before-instance", 24 | "variables-before-functions" 25 | ], 26 | "no-arg": true, 27 | "no-bitwise": true, 28 | "no-console": [true, 29 | "debug", 30 | "info", 31 | "time", 32 | "timeEnd", 33 | "trace" 34 | ], 35 | "no-construct": true, 36 | "no-parameter-properties": false, 37 | "no-debugger": true, 38 | "no-duplicate-variable": true, 39 | "no-empty": false, 40 | "no-eval": true, 41 | "no-string-literal": true, 42 | "no-switch-case-fall-through": true, 43 | "trailing-comma": [true, { 44 | "multiline": "never", 45 | "singleline": "never" 46 | }], 47 | "no-trailing-whitespace": true, 48 | "whitespace": [true, 49 | "check-branch", 50 | "check-decl", 51 | "check-operator", 52 | "check-module", 53 | "check-separator", 54 | "check-type" 55 | ], 56 | "no-unused-expression": true, 57 | "no-use-before-declare": true, 58 | "no-var-requires": true, 59 | "no-var-keyword": true, 60 | "no-invalid-this": true, 61 | "one-line": [true, 62 | "check-open-brace", 63 | "check-catch", 64 | "check-else", 65 | "check-whitespace" 66 | ], 67 | "quotemark": [true, "single"], 68 | "radix": true, 69 | "semicolon": true, 70 | "triple-equals": [true, "allow-null-check"], 71 | "typedef": [true, 72 | "parameter", 73 | "property-declaration" 74 | ], 75 | "typedef-whitespace": [true, 76 | ["call-signature", "nospace"], 77 | ["parameter", "nospace"], 78 | ["arrow-parameter", "nospace"], 79 | ["property-declaration", "nospace"], 80 | ["variable-declaration", "nospace"], 81 | ["member-variable-declaration", "nospace"] 82 | ], 83 | "variable-name": false 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/context/context.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {ContextService} from 'context.service'; 2 | 3 | describe('contextService', () => { 4 | 5 | let contextService; 6 | 7 | beforeEach(() => { 8 | angular.mock.module('app'); 9 | 10 | inject((_contextService_: ContextService) => { 11 | contextService = _contextService_; 12 | }); 13 | }); 14 | 15 | it('should have an inject method', () => { 16 | expect(typeof (contextService.inject)).toBe('function'); 17 | }); 18 | 19 | describe('injectContext', () => { 20 | 21 | it('should not change resulting API if the input API has no parameters', () => { 22 | // Arrange 23 | let restApi = '/projects/popopo/test'; 24 | let context = {}; 25 | 26 | // Act 27 | let resultApi = contextService.inject(restApi, context); 28 | 29 | // Assert 30 | expect(resultApi).toBe(restApi); 31 | }); 32 | 33 | it('should correctly inject input API parameters with the given context', () => { 34 | // Arrange 35 | let restApi = '/projects/:projectId'; 36 | let context = {projectId: '123'}; 37 | 38 | // Act 39 | let resultApi = contextService.inject(restApi, context); 40 | 41 | // Assert 42 | expect(resultApi).toBe('/projects/123'); 43 | }); 44 | 45 | it('should correctly escape injected input API parameters', () => { 46 | // Arrange 47 | let restApi = '/projects/:projectId'; 48 | let context = {projectId: '123+/@'}; 49 | 50 | // Act 51 | let resultApi = contextService.inject(restApi, context); 52 | 53 | // Assert 54 | expect(resultApi).toBe('/projects/123%2B%2F%40'); 55 | }); 56 | 57 | it('should throw an exception if an input API parameter is not present in the context', () => { 58 | // Arrange 59 | let restApi = '/projects/:projectId'; 60 | let context = {}; 61 | 62 | // Act 63 | let func = () => { 64 | contextService.inject(restApi, context); 65 | }; 66 | 67 | // Assert 68 | expect(func).toThrow(); 69 | }); 70 | 71 | it('should throw an exception if no context is specified', () => { 72 | // Arrange 73 | let restApi = '/projects/:projectId'; 74 | 75 | // Act 76 | let func = () => { 77 | contextService.inject(restApi, null); 78 | }; 79 | 80 | // Assert 81 | expect(func).toThrow(); 82 | }); 83 | 84 | }); 85 | 86 | }); 87 | -------------------------------------------------------------------------------- /generators/app/templates/docs/coding-guides/unit-tests.md: -------------------------------------------------------------------------------- 1 | # Unit tests coding guide 2 | 3 | The main objective of unit tests is to detect regressions and to help you design software components. A suite of 4 | *good* unit tests can be *immensely* valuable for your project and makes it easier to refactor and expand your code. 5 | But keep in mind that a suite of *bad* unit tests can also be *immensely* painful, and hurt your development by 6 | inhibiting your ability to refactor or alter your code in any way. 7 | 8 | ## What to test? 9 | 10 | We thought this over into multiple projects, and the general consensus is to cover everything that is not a 11 | controller/view of your app with unit tests. At least, all business logic code must be tested: services, helpers, 12 | models. Directives should also be covered by unit tests. 13 | 14 | Then why not the controller/views? Since your controllers should not contain business logic (as it should be in 15 | services), then it has more meaning to use [End-to-end tests](e2e-tests.md) to test their behavior. It will also avoid 16 | the need for painful and useless mocks, since most likely your controller will aggregate many other components. 17 | 18 | ## Good practices 19 | 20 | - Name your tests cleanly and consistently 21 | - Do not only test nominal cases, the most important tests are the one covering the edge cases 22 | - Each test should be independent to all the others 23 | - Avoid unnecessary assertions: it's counter-productive to assert anything covered by another test, it just increase 24 | pointless failures and maintenance workload 25 | - Test only one code unit at a time: if you cannot do this, it means you have an architecture problem in your app 26 | - Mock out all external dependencies and state: if there is too much to mock, it is often a sign that maybe you 27 | should split your tested module into several more independent modules 28 | - Clearly separate or identify these 3 stages of each unit test: *prepare*, *act* and *assert* 29 | - When you fix a bug related to unit-tested module, add a test case to prevent regression for this bug 30 | 31 | ## Pitfalls 32 | 33 | - Sometimes your architecture might mean your code modify static variables during unit tests. Avoid this if you can, 34 | but if you can't, at least make sure each test resets the relevant statics before and after your tests. 35 | - Don’t unit-test configuration settings 36 | - Improving test coverage is good, but having meaningful tests is better: start with the latter first, and **only 37 | after essential features of your code unit are tested**, your can think of improving the coverage. 38 | -------------------------------------------------------------------------------- /generators/app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.projectName %>", 3 | "version": "1.0.0", 4 | "description": "", 5 | "keywords": [], 6 | "license": "", 7 | "private": true, 8 | "scripts": { 9 | "test": "gulp test" 10 | }, 11 | "devDependencies": { 12 | <% if (props.target !== 'web') { -%> 13 | "cordova": "^7.0.0", 14 | "gulp-insert": "^0.5.0", 15 | "tostr": "^0.1.0", 16 | <% } -%> 17 | "angular-gettext-loader": "^1.0.1", 18 | "browser-sync": "^2.17.3", 19 | "browser-sync-spa": "~1.0.3", 20 | "chalk": "~1.1.1", 21 | "del": "~3.0.0", 22 | "gulp": "~3.9.1", 23 | "gulp-angular-gettext": "~2.2.0", 24 | "gulp-autoprefixer": "~4.0.0", 25 | "gulp-cache": "^0.4.3", 26 | "gulp-clean-css": "^3.5.0", 27 | "gulp-concat": "~2.6.0", 28 | "gulp-filter": "^5.0.0", 29 | "gulp-flatten": "^0.3.1", 30 | "gulp-htmlmin": "^3.0.0", 31 | "gulp-if": "^2.0.0", 32 | "gulp-imagemin": "^3.0.3", 33 | "gulp-inject": "^4.1.0", 34 | "gulp-intercept": "^0.1.0", 35 | "gulp-load-plugins": "^1.5.0", 36 | "gulp-protractor": "^4.1.0", 37 | "gulp-rename": "~1.2.2", 38 | "gulp-replace": "~0.6.1", 39 | "gulp-rev": "~7.1.2", 40 | "gulp-rev-replace": "~0.4.3", 41 | "gulp-sass": "^3.1.0", 42 | "gulp-shell": "^0.6.3", 43 | "gulp-size": "^2.1.0", 44 | "gulp-sourcemaps": "^2.4.1", 45 | "gulp-tsd": "^0.1.1", 46 | "gulp-uglify": "^3.0.0", 47 | "gulp-useref": "^3.0.8", 48 | "gulp-util": "~3.0.7", 49 | "html-minify-loader": "^1.1.0", 50 | "htmlhint-loader": "^1.0.0", 51 | "http-proxy-middleware": "^0.17.2", 52 | "https-proxy-agent": "^2.0.0", 53 | "istanbul-instrumenter-loader": "^2.0.0", 54 | "jasmine-spec-reporter": "^4.1.1", 55 | "jshint": "^2.9.3", 56 | "karma": "^1.1.2", 57 | "karma-coverage-istanbul-reporter": "^1.3.0", 58 | "karma-jasmine": "^1.0.2", 59 | "karma-junit-reporter": "^1.0.0", 60 | "karma-phantomjs-launcher": "~1.0.2", 61 | "karma-sourcemap-loader": "^0.3.7", 62 | "lodash": "^4.16.4", 63 | "main-bower-files": "^2.13.1", 64 | "merge-stream": "~1.0.0", 65 | "minimist": "^1.2.0", 66 | "ng-annotate-loader": "^0.6.1", 67 | "phantomjs-prebuilt": "^2.1.13", 68 | "protractor-jasmine2-screenshot-reporter": "~0.3.3", 69 | "raw-loader": "^0.5.1", 70 | "require-dir": "~0.3.0", 71 | "ts-loader": "^2.0.0", 72 | "tslint": "^4.4.2", 73 | "tslint-loader": "^3.4.2", 74 | "typescript": "^2.0.3", 75 | "typings": "^2.1.0", 76 | "uglify-save-license": "~0.4.1", 77 | "webpack-stream-fixed": "^3.2.2", 78 | "wiredep": "^4.0.0" 79 | }, 80 | "engines": { 81 | "node": ">=4.0.0" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /generators/app/templates/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var conf = require('./gulpfile.config'); 5 | var _ = require('lodash'); 6 | var wiredep = require('wiredep'); 7 | 8 | /* 9 | * list all files that we want to load in the browser 10 | */ 11 | function listFiles() { 12 | var wiredepOptions = _.extend({}, conf.wiredep, { 13 | dependencies: true, 14 | devDependencies: true 15 | }); 16 | return wiredep(wiredepOptions).js 17 | .concat([path.join(conf.paths.tmp, '**/*.js'), { 18 | pattern: path.join(conf.paths.src, 'images/**/*.*'), 19 | included: false 20 | }]); 21 | } 22 | 23 | module.exports = function(config) { 24 | 25 | var configuration = { 26 | 27 | // List of files/patterns to load in the browser 28 | files: listFiles(), 29 | 30 | // Redirect root (/) requests to static assets 31 | proxies: { 32 | '/libraries': '/base/sources/libraries', 33 | '/images': '/base/sources/images' 34 | }, 35 | 36 | // Continuous Integration mode 37 | // If true, it capture browsers, run tests and exit 38 | singleRun: true, 39 | 40 | // Enable or disable watching files and executing the tests whenever one of these files changes. 41 | autoWatch: false, 42 | 43 | // Level of logging, can be: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 44 | logLevel: config.LOG_INFO, 45 | 46 | // Testing framework to use (jasmine/mocha/qunit/...) 47 | frameworks: ['jasmine'], 48 | 49 | // Start these browsers, currently available: 50 | // - Chrome 51 | // - ChromeCanary 52 | // - Firefox 53 | // - Opera 54 | // - Safari (only Mac) 55 | // - PhantomJS 56 | // - IE (only Windows) 57 | browsers: ['PhantomJS'], 58 | 59 | // List of plugins to load 60 | plugins: [ 61 | 'karma-phantomjs-launcher', 62 | 'karma-jasmine', 63 | 'karma-coverage-istanbul-reporter', 64 | 'karma-junit-reporter', 65 | 'karma-sourcemap-loader' 66 | ], 67 | 68 | // A map of preprocessors to use 69 | preprocessors: ['sourcemap'], 70 | 71 | // List of reporters 72 | reporters: ['progress', 'junit', 'coverage-istanbul'], 73 | 74 | // Coverage configuration 75 | coverageIstanbulReporter: { 76 | reports: ['html', 'lcovonly', 'text-summary'], 77 | dir: 'reports/coverage', 78 | fixWebpackSourcePaths: true 79 | }, 80 | 81 | junitReporter: { 82 | outputDir: 'reports/junit/', 83 | outputFile: 'TESTS-xunit.xml', 84 | useBrowserName: false, 85 | suite: '' // suite will become the package name attribute in xml testsuite element 86 | }, 87 | 88 | // Enable or disable colors in the output (reporters and logs). 89 | color: true 90 | }; 91 | 92 | config.set(configuration); 93 | 94 | }; 95 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/gulp/cordova.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | var gutil = require('gulp-util'); 7 | var minimist = require('minimist'); 8 | 9 | var $ = require('gulp-load-plugins')({ 10 | pattern: ['gulp-*', 'del'] 11 | }); 12 | 13 | var options = minimist(process.argv.slice(2), { 14 | string: 'command', 15 | boolean: ['fast', 'device'], 16 | alias: { 17 | c: 'command', 18 | f: 'fast', 19 | d: 'device' 20 | } 21 | }); 22 | 23 | var dependencies = options['fast'] ? [] : ['build', 'cordova:resources']; 24 | 25 | function cordova(command) { 26 | return $.shell.task('cordova ' + command, {verbose: true}) 27 | } 28 | 29 | gulp.task('patch:ios-https', function() { 30 | // Allow self-signed HTTPS certificate, use only for development! 31 | var patch = 32 | '\n' + 33 | '#ifdef DEBUG\n' + 34 | '@implementation NSURLRequest(DataController)\n' + 35 | '+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host { return YES; }\n' + 36 | '@end\n' + 37 | '#endif'; 38 | 39 | var file = 'platforms/ios/App/Classes/AppDelegate.m'; 40 | 41 | gutil.log(gutil.colors.yellow('Patching iOS app to allow requests from servers using self-signed HTTPS ' + 42 | 'certificates.')); 43 | gutil.log(gutil.colors.yellow('DO NOT USE THIS FOR PRODUCTION BUILDS, it may result in your app being rejected ' + 44 | 'by Apple.')); 45 | 46 | return gulp.src(file) 47 | .pipe($.insert.append(patch)) 48 | .pipe(gulp.dest(path.dirname(file))); 49 | }); 50 | 51 | gulp.task('cordova:resources', function() { 52 | return gulp.src('resources/**/*.{gif,jpg,png,svg}') 53 | .pipe($.cache($.imagemin({ 54 | optimizationLevel: 3, 55 | progressive: true, 56 | interlaced: true 57 | }))) 58 | .pipe(gulp.dest(path.join(conf.paths.tmp, 'resources'))) 59 | .pipe($.size()); 60 | }); 61 | 62 | gulp.task('release:ios', dependencies, cordova('build ios --release --device')); 63 | 64 | gulp.task('release:android', dependencies, cordova('build android --release')); 65 | 66 | gulp.task('build:ios', dependencies, cordova('build ios ' + (options.device ? '--device' : '--emulate'))); 67 | 68 | gulp.task('build:android', dependencies, cordova('build android ' + (options.device ? '--device' : '--emulate'))); 69 | 70 | gulp.task('run:ios', dependencies, cordova('run ios ' + (options.device ? '--device' : '--emulate'))); 71 | 72 | gulp.task('run:android', dependencies, cordova('run android ' + (options.device ? '--device' : '--emulate'))); 73 | 74 | gulp.task('cordova:remove', function() { 75 | return $.del(['platforms', 'plugins']); 76 | }); 77 | 78 | gulp.task('cordova:build', dependencies, cordova('build ' + (options.device ? '--device' : '--emulate'))); 79 | 80 | gulp.task('cordova:release', ['release:ios', 'release:android']); 81 | 82 | gulp.task('cordova:prepare', dependencies, cordova('prepare')); 83 | 84 | gulp.task('cordova', cordova(options.command)); 85 | -------------------------------------------------------------------------------- /generators/app/templates/docs/build-environments.md: -------------------------------------------------------------------------------- 1 | # Managing multiple build environments 2 | 3 | Most applications pass through several environments before they are released in production. These environments often 4 | include: a local development environment, a shared development environment, a system integration environment, a user 5 | acceptance environment and a production environment. 6 | 7 | You may then need adjust your application configuration depending of the target environment, for example changing the 8 | log verbosity level and the backend server URL. 9 | 10 | By default, when running the `gulp build` task, the target is the `production` environment. 11 | You can change it if needed in the `gulpfile.config.js` file by modifying the value of `defaultBuildEnvironment`. 12 | 13 | When building your application, you can also force a specific environment by using the flag `--environment `. 14 | 15 | By doing so, the configuration defined in `main.constants.ts` corresponding to the specified environment will be used, 16 | as long a the `environment` variable has a key with that name defined. 17 | 18 | By default it looks like this: 19 | ```js 20 | let environment = { 21 | local: { 22 | debug: true, 23 | 24 | // REST backend configuration, used for all web services using restService 25 | server: { 26 | url: '', 27 | route: 'api' 28 | } 29 | }, 30 | production: { 31 | debug: false, 32 | server: { 33 | url: '', 34 | route: 'api' 35 | } 36 | } 37 | }; 38 | ``` 39 | 40 | You can see there that 2 environments are already defined for you: 41 | 42 | - `local`: used for `gulp serve` for local development 43 | - `production`: used when building your app with `gulp build` 44 | 45 | You can add whatever environment you need in this file and adjust its settings accordingly. 46 | For example if you need to add a specific configuration for our continuous integration build, you can do it like this: 47 | ```js 48 | let environment = { 49 | local: { 50 | debug: true, 51 | 52 | // REST backend configuration, used for all web services using restService 53 | server: { 54 | url: '', 55 | route: 'api' 56 | } 57 | }, 58 | integration: { 59 | debug: true, 60 | server: { 61 | url: 'https://my-ci-backend-server.com', 62 | route: 'api' 63 | } 64 | }, 65 | production: { 66 | debug: false, 67 | server: { 68 | url: '', 69 | route: 'api' 70 | } 71 | } 72 | }; 73 | ``` 74 | 75 | Then you can build your app using the command `gulp build --environment integration`. 76 | 77 | You may also have noticed the `server` object, that has 2 properties `url` and `route`. It allows you to setup your 78 | REST API root URL, that will be used by all your API calls made using the provided `restService`. 79 | 80 | If you leave empty the server URL, `localhost` will be assumed by default meaning that your REST API runs on the same 81 | domain as your application (which is always true when using `gulp serve` as it uses an [API proxy](api-proxy.md)). 82 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/web-services/quote/quote.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {RestService} from 'helpers/rest/rest.service'; 2 | import {QuoteService} from 'quote.service'; 3 | 4 | describe('quoteService', () => { 5 | 6 | // Constants 7 | let ERROR_JOKE = 'Error, could not load joke :-('; 8 | 9 | let $q; 10 | let $rootScope; 11 | let restService; 12 | let quoteService; 13 | 14 | beforeEach(() => { 15 | angular.mock.module('app'); 16 | 17 | inject((_$q_: ng.IQService, 18 | _$rootScope_: ng.IRootScopeService, 19 | _quoteService_: QuoteService, 20 | _restService_: RestService) => { 21 | 22 | $q = _$q_; 23 | $rootScope = _$rootScope_; 24 | quoteService = _quoteService_; 25 | restService = _restService_; 26 | }); 27 | 28 | }); 29 | 30 | it('should have a getRandomJoke method', () => { 31 | expect(typeof (quoteService.getRandomJoke)).toBe('function'); 32 | }); 33 | 34 | describe('getRandomJoke', () => { 35 | 36 | it('should call rest service get method and return joke', (done) => { 37 | // Prepare 38 | spyOn(restService, 'get').and.callFake(() => { 39 | let deferred = $q.defer(); 40 | deferred.resolve({ 41 | data: { 42 | value: { 43 | joke: 'hello' 44 | } 45 | } 46 | }); 47 | return deferred.promise; 48 | }); 49 | 50 | // Act 51 | let promise = quoteService.getRandomJoke({category: 'nerdy'}); 52 | 53 | // Assert 54 | promise.then((joke) => { 55 | expect(restService.get).toHaveBeenCalled(); 56 | expect(joke).toEqual('hello'); 57 | done(); 58 | }); 59 | 60 | $rootScope.$apply(); 61 | }); 62 | 63 | it('should call rest service get method and fail when there is no joke in the response', (done) => { 64 | // Prepare 65 | spyOn(restService, 'get').and.callFake(() => { 66 | let deferred = $q.defer(); 67 | deferred.resolve({}); 68 | return deferred.promise; 69 | }); 70 | 71 | // Act 72 | let promise = quoteService.getRandomJoke({category: 'nerdy'}); 73 | 74 | // Assert 75 | promise.then((joke) => { 76 | expect(restService.get).toHaveBeenCalled(); 77 | expect(joke).toEqual(ERROR_JOKE); 78 | done(); 79 | }); 80 | 81 | $rootScope.$apply(); 82 | }); 83 | 84 | it('should call rest service get method and fail to get a response', (done) => { 85 | // Prepare 86 | spyOn(restService, 'get').and.callFake(() => { 87 | return $q.reject({}); 88 | }); 89 | 90 | // Act 91 | let promise = quoteService.getRandomJoke({category: 'nerdy'}); 92 | $rootScope.$apply(); 93 | 94 | // Assert 95 | promise.then((joke) => { 96 | expect(restService.get).toHaveBeenCalled(); 97 | expect(joke).toEqual(ERROR_JOKE); 98 | done(); 99 | }); 100 | 101 | $rootScope.$apply(); 102 | }); 103 | 104 | }); 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /generators/app/templates/docs/coding-guides/css.md: -------------------------------------------------------------------------------- 1 | # CSS coding guide 2 | 3 | ## Naming conventions 4 | 5 | - In the CSS world, everything should be named in `kebab-case` (lowercase words separated with a `-`). 6 | - File names should always be in `kebab-case` 7 | 8 | ## Coding rules 9 | 10 | - When using CSS preprocessors such as Less/Sass, this nesting hierarchy should be used: 11 | ```less 12 | // The base component class acts as the namespace, to avoid naming and style collisions 13 | .my-component { 14 | // Put here all component elements (flat) 15 | .my-element { 16 | // Use a third-level only for modifiers and state variations 17 | &.active { ... } 18 | } 19 | } 20 | ``` 21 | Yes, we are aware of the [BEM naming approach](https://en.bem.info/tools/bem/bem-naming/), but we found it 22 | impractical for large projects. The nesting approach has drawbacks such as increased specificity, but it helps 23 | keeping everything nicely organized, and more importantly, *scoped*. 24 | 25 | - Use single quotes `'` for strings 26 | 27 | And keep in mind this general rules: 28 | - Always use classes selectors, never use ID or element selectors 29 | - No more than **3 levels** of nesting 30 | - No more than **3 qualifiers** 31 | 32 | ## Best practices 33 | 34 | - Use object-oriented CSS (OOCSS): 35 | * Factorize common code in base class, and extend it, for example: 36 | ```scss 37 | // Base button class 38 | .btn { ... } 39 | 40 | // Color variation 41 | .btn-warning { ... } 42 | 43 | // Size variation 44 | .btn-small { ... } 45 | ``` 46 | * Try to name class by semantic, not style nor function for better reusability: 47 | Use `.btn-warning`, not `btn-orange` nor `btn-cancel` 48 | * Avoid undoing style, refactor using common base classes and extensions 49 | 50 | - Keep your style scoped 51 | * Clearly separate **global** (think *framework*) and **modules** (*components*) style 52 | * Global style should only go in `main/theme/*` or `main/helpers.scss` (never in modules) 53 | * Avoid interactions between modules, if some style may need to be shared, refactor it as a framework component in 54 | put it in your global theme. 55 | * Avoid using wider selectors than needed (always use classes!) 56 | 57 | - Avoid rules multiplication 58 | * The less, the better (no pun intented), factorize rules whenever it's possible 59 | * CSS is code, and like any code frequent refactoring is healthy 60 | 61 | - When ugly hacks cannot be avoided, put it in `main/hacks.scss`: 62 | * These ugly hacks should only be **temporary** 63 | * Each hack should be documented with the author name, the problem and hack reason 64 | * Limit this file to a reasonable length (~100 lines) and refactor hacks with proper solutions when the limit is 65 | reached. 66 | 67 | ## Pitfalls 68 | 69 | - Never use the `!important` keyword. Ever. 70 | - Never use **inline** style in html, even *just for debugging* (because we KNOW it will end up in your commit) 71 | - Do not use browser-specific prefixes: there are tools taking care of that part 72 | ([autoprefixer](https://github.com/postcss/autoprefixer)) 73 | 74 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/hooks/after_prepare/010_add_platform_class.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Add Platform Class 4 | // v1.0 5 | // Automatically adds the platform class to the body tag 6 | // after the `prepare` command. By placing the platform CSS classes 7 | // directly in the HTML built for the platform, it speeds up 8 | // rendering the correct layout/style for the specific platform 9 | // instead of waiting for the JS to figure out the correct classes. 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | 14 | var rootdir = process.argv[2]; 15 | 16 | function addPlatformBodyTag(indexPath, platform) { 17 | // add the platform class to the body tag 18 | try { 19 | var platformClass = 'platform-' + platform; 20 | var cordovaClass = 'platform-cordova platform-webview'; 21 | 22 | var html = fs.readFileSync(indexPath, 'utf8'); 23 | 24 | var bodyTag = findBodyTag(html); 25 | if(!bodyTag) return; // no opening body tag, something's wrong 26 | 27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added 28 | 29 | var newBodyTag = bodyTag; 30 | 31 | var classAttr = findClassAttr(bodyTag); 32 | if(classAttr) { 33 | // body tag has existing class attribute, add the classname 34 | var endingQuote = classAttr.substring(classAttr.length-1); 35 | var newClassAttr = classAttr.substring(0, classAttr.length-1); 36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote; 37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr); 38 | 39 | } else { 40 | // add class attribute to the body tag 41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">'); 42 | } 43 | 44 | html = html.replace(bodyTag, newBodyTag); 45 | 46 | fs.writeFileSync(indexPath, html, 'utf8'); 47 | 48 | process.stdout.write('add to body class: ' + platformClass + '\n'); 49 | } catch(e) { 50 | process.stdout.write(e); 51 | } 52 | } 53 | 54 | function findBodyTag(html) { 55 | // get the body tag 56 | try{ 57 | return html.match(/])(.*?)>/gi)[0]; 58 | }catch(e){} 59 | } 60 | 61 | function findClassAttr(bodyTag) { 62 | // get the body tag's class attribute 63 | try{ 64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0]; 65 | }catch(e){} 66 | } 67 | 68 | if (rootdir) { 69 | 70 | // go through each of the platform directories that have been prepared 71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []); 72 | 73 | for(var x=0; x 21 | # Cordova Hooks 22 | 23 | This directory may contain scripts used to customize cordova commands. This 24 | directory used to exist at `.cordova/hooks`, but has now been moved to the 25 | project root. Any scripts you add to these directories will be executed before 26 | and after the commands corresponding to the directory name. Useful for 27 | integrating your own build systems or integrating with version control systems. 28 | 29 | __Remember__: Make your scripts executable. 30 | 31 | ## Hook Directories 32 | The following subdirectories will be used for hooks: 33 | 34 | after_build/ 35 | after_compile/ 36 | after_docs/ 37 | after_emulate/ 38 | after_platform_add/ 39 | after_platform_rm/ 40 | after_platform_ls/ 41 | after_plugin_add/ 42 | after_plugin_ls/ 43 | after_plugin_rm/ 44 | after_plugin_search/ 45 | after_prepare/ 46 | after_run/ 47 | after_serve/ 48 | before_build/ 49 | before_compile/ 50 | before_docs/ 51 | before_emulate/ 52 | before_platform_add/ 53 | before_platform_rm/ 54 | before_platform_ls/ 55 | before_plugin_add/ 56 | before_plugin_ls/ 57 | before_plugin_rm/ 58 | before_plugin_search/ 59 | before_prepare/ 60 | before_run/ 61 | before_serve/ 62 | pre_package/ <-- Windows 8 and Windows Phone only. 63 | 64 | ## Script Interface 65 | 66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: 67 | 68 | * CORDOVA_VERSION - The version of the Cordova-CLI. 69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). 70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) 71 | * CORDOVA_HOOK - Path to the hook that is being executed. 72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) 73 | 74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted. 75 | 76 | 77 | ## Writing hooks 78 | 79 | We highly recommend writting your hooks using Node.js so that they are 80 | cross-platform. Some good examples are shown here: 81 | 82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) 83 | 84 | -------------------------------------------------------------------------------- /generators/app/templates/_gulpfile.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * GULP TASKS CONFIGURATION 3 | * This file contains the variables used in gulp tasks. 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var path = require('path'); 9 | var gutil = require('gulp-util'); 10 | var fs = require('fs'); 11 | var bower = JSON.parse(fs.readFileSync('.bowerrc', 'utf8')); 12 | var HttpsProxyAgent = require('https-proxy-agent'); 13 | 14 | /** 15 | * The main paths of your project, handle these with care. 16 | */ 17 | exports.paths = { 18 | src: 'sources', 19 | <% if (props.target === 'web') { -%> 20 | dist: 'dist', 21 | <% } else { -%> 22 | dist: 'www', 23 | <% } -%> 24 | tmp: '.tmp', 25 | e2e: 'e2e', 26 | main: 'main', 27 | bower: bower.directory 28 | }; 29 | 30 | /** 31 | * Sass include paths. 32 | */ 33 | exports.sassIncludePaths = [ 34 | bower.directory, 35 | exports.paths.src, 36 | path.join(exports.paths.src, exports.paths.main), 37 | <% if (props.ui === 'bootstrap') { -%> 38 | path.join(bower.directory, 'bootstrap-sass/assets/stylesheets/') 39 | <% } if (props.ui === 'ionic') { -%> 40 | path.join(bower.directory, 'ionic/scss') 41 | <% } -%> 42 | ]; 43 | 44 | /** 45 | * Default build environment, see docs/build-environments.md for more info. 46 | */ 47 | exports.defaultBuildEnvironment = 'production'; 48 | 49 | /** 50 | * Extra files that will be copied as-is in the dist folder. 51 | * Each entry is an object with the form: 52 | * { 53 | * basePath: , 54 | * files: 55 | * } 56 | */ 57 | exports.extraFiles = []; 58 | 59 | /** 60 | * Code coverage exclusions for unit tests. 61 | */ 62 | exports.coverageExclusions = [ 63 | '.spec.ts$', // unit tests 64 | '.controller.ts$', // controllers, as we prefer to test them using end-to-end tests 65 | ]; 66 | 67 | /** 68 | * API proxy configuration. 69 | * With the given example, HTTP request to like $http.get('/api/stuff') will be automatically proxified 70 | * to the specified server. 71 | * Multiple endpoints can be configured here. 72 | * 73 | * For more details and option, see https://github.com/chimurai/http-proxy-middleware/ 74 | */ 75 | exports.backendProxy = [ 76 | { 77 | context: '/api', 78 | options: { 79 | pathRewrite: {'^/api': ''}, 80 | target: 'http://api.icndb.com', 81 | changeOrigin: true 82 | } 83 | } 84 | ]; 85 | 86 | /** 87 | * Wiredep is the lib which inject bower dependencies in your project. 88 | * Mainly used to inject script tags in the index.html but also used to inject css preprocessor 89 | * deps and js files in karma. 90 | */ 91 | exports.wiredep = { 92 | exclude: [], 93 | directory: bower.directory, 94 | bowerJson: require('./bower.json') 95 | }; 96 | 97 | /** 98 | * Configures a corporate proxy agent for the API proxy. 99 | */ 100 | exports.corporateProxyAgent = function() { 101 | var agent = null; 102 | var proxyServer = process.env.http_proxy || process.env.HTTP_PROXY; 103 | 104 | if (proxyServer) { 105 | agent = new HttpsProxyAgent(proxyServer); 106 | gutil.log(gutil.colors.cyan('Using corporate proxy server: ' + proxyServer)); 107 | } 108 | 109 | return agent; 110 | }; 111 | 112 | /** 113 | * Common implementation for an error handler of a gulp plugin. 114 | */ 115 | exports.errorHandler = function(title, skipEnd) { 116 | return function(err) { 117 | if (title) { 118 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); 119 | } 120 | if (!skipEnd) { 121 | this.emit('end'); 122 | } 123 | }; 124 | }; 125 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/scripts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('../gulpfile.config'); 6 | var webpack = require('webpack-stream-fixed'); 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | function buildScripts(watch, test, done) { 12 | var options = { 13 | resolve: { 14 | modulesDirectories: [ 15 | '.', 16 | conf.paths.main, 17 | 'libraries', 18 | conf.paths.src 19 | ], 20 | extensions: ['', '.ts'] 21 | }, 22 | debug: watch || test, 23 | watch: watch, 24 | devtool: watch || test ? 'inline-source-map' : undefined, 25 | module: { 26 | preLoaders: [ 27 | { 28 | test: /\.ts$/, 29 | exclude: /node_modules/, 30 | loader: 'tslint' 31 | }, 32 | { 33 | test: /\.html/, 34 | loader: 'htmlhint', 35 | exclude: /node_modules/ 36 | } 37 | ], 38 | loaders: [ 39 | { 40 | test: /\.ts$/, 41 | exclude: /node_modules/, 42 | loaders: ['ng-annotate', 'ts'] 43 | }, 44 | { 45 | test: /\.html$/, 46 | loader: 'raw!html-minify' 47 | }, 48 | { 49 | test: /\.json/, 50 | loader: 'raw' 51 | }, 52 | { 53 | test: /\.po$/, 54 | loader: 'angular-gettext?module=translations' 55 | } 56 | ] 57 | }, 58 | output: { 59 | filename: 'app.ts.js', 60 | devtoolModuleFilenameTemplate: '[resource-path]', 61 | devtoolFallbackModuleFilenameTemplate: '[resource-path]' 62 | }, 63 | 'html-minify-loader': { 64 | empty: true, 65 | cdata: true, 66 | comments: true, 67 | conditionals: true, 68 | quotes: true, 69 | dom: { 70 | lowerCaseAttributeNames: false, 71 | lowerCaseTags: false 72 | } 73 | }, 74 | tslint: { 75 | emitErrors: !watch, 76 | failOnHint: !watch 77 | }, 78 | htmlhint: { 79 | configFile: '.htmlhintrc' 80 | } 81 | }; 82 | 83 | var changeHandler = function(err, stats) { 84 | if (err) { 85 | conf.errorHandler('Webpack', true)(err); 86 | } 87 | 88 | var info = stats.toString({ 89 | colors: $.util.colors.supportsColor, 90 | assets: false, 91 | timings: false, 92 | chunks: false, 93 | hash: false, 94 | version: false 95 | }); 96 | 97 | if (info) { 98 | $.util.log(info); 99 | } 100 | 101 | browserSync.reload(); 102 | 103 | // Finish gulp task to avoid waiting indefinitely 104 | if (watch) { 105 | watch = false; 106 | done(); 107 | } 108 | }; 109 | 110 | var sources = [ 111 | path.join(conf.paths.src, '**/*.ts'), 112 | path.join(conf.paths.src, 'translations/*.po'), 113 | path.join('!' + conf.paths.bower, '/**/*.ts') 114 | ]; 115 | 116 | if (!test) { 117 | sources.push(path.join('!' + conf.paths.src, '/**/*.spec.ts')); 118 | sources.push(path.join('!' + conf.paths.src, '/**/*.mock.ts')); 119 | } else { 120 | var exclusions = ''; 121 | conf.coverageExclusions.forEach(function(exclusion) { 122 | exclusions += '|' + exclusion + '$'; 123 | }); 124 | options.module.postLoaders = [{ 125 | test: /\.ts$/, 126 | exclude: new RegExp('(node_modules' + exclusions + ')'), 127 | loader: 'istanbul-instrumenter-loader' 128 | }]; 129 | } 130 | 131 | return gulp.src(sources) 132 | .pipe(webpack(options, null, changeHandler)).on('error', conf.errorHandler('', watch)) 133 | .pipe(gulp.dest(path.join(conf.paths.tmp))); 134 | } 135 | 136 | gulp.task('scripts', function() { 137 | return buildScripts(false, false); 138 | }); 139 | 140 | gulp.task('scripts:watch', function(done) { 141 | return buildScripts(true, false, done); 142 | }); 143 | 144 | gulp.task('scripts:test', function() { 145 | return buildScripts(false, true); 146 | }); 147 | 148 | gulp.task('scripts:test-watch', function(done) { 149 | return buildScripts(true, true, done); 150 | }); 151 | -------------------------------------------------------------------------------- /generators/app/templates/_typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.projectName %>", 3 | "globalDependencies": { 4 | <% if (props.ui === 'ionic') { -%> 5 | "ionic": "github:DefinitelyTyped/DefinitelyTyped/ionic/ionic.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 6 | <% } else if (props.ui === 'bootstrap' && props.target !== 'web') { -%> 7 | "fastclick": "github:DefinitelyTyped/DefinitelyTyped/fastclick/fastclick.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 8 | <% } -%> 9 | "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 10 | "webpack-env": "github:DefinitelyTyped/DefinitelyTyped/webpack/webpack-env.d.ts#544a35a10866b32afda9c7f029c0764558563f4f", 11 | "angular-ui-router": "github:DefinitelyTyped/DefinitelyTyped/angular-ui-router/angular-ui-router.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 12 | "angular-gettext": "github:DefinitelyTyped/DefinitelyTyped/angular-gettext/angular-gettext.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 13 | "jasmine-jquery": "github:DefinitelyTyped/DefinitelyTyped/jasmine-jquery/jasmine-jquery.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 14 | "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 15 | "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 16 | "angular-animate": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-animate.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 17 | "angular-sanitize": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-sanitize.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 18 | "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 19 | "lodash": "github:DefinitelyTyped/DefinitelyTyped/lodash/lodash.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2"<% if (props.target !== 'web') { %>, 20 | "cordova": "github:DefinitelyTyped/DefinitelyTyped/cordova/cordova.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 21 | "BatteryStatus": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/BatteryStatus.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 22 | "Contacts": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Contacts.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 23 | "Camera": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Camera.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 24 | "Dialogs": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Dialogs.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 25 | "Device": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Device.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 26 | "DeviceOrientation": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/DeviceOrientation.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 27 | "DeviceMotion": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/DeviceMotion.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 28 | "FileSystem": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/FileSystem.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 29 | "FileTransfer": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/FileTransfer.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 30 | "Globalization": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Globalization.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 31 | "Media": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Media.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 32 | "MediaCapture": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/MediaCapture.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 33 | "Splashscreen": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Splashscreen.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 34 | "NetworkInformation": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/NetworkInformation.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 35 | "StatusBar": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/StatusBar.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 36 | "Vibration": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Vibration.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 37 | "WebSQL": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/WebSQL.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 38 | "Push": "github:DefinitelyTyped/DefinitelyTyped/cordova/plugins/Push.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 39 | "Keyboard": "github:DefinitelyTyped/DefinitelyTyped/cordova-ionic/plugins/keyboard.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 40 | "cordova-ionic": "github:DefinitelyTyped/DefinitelyTyped/cordova-ionic/cordova-ionic.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2", 41 | "keyboard": "github:DefinitelyTyped/DefinitelyTyped/cordova-ionic/plugins/keyboard.d.ts#398bd742115e2b071ab3edf8b543b6df6fa62dc2"<% } %> 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/logger/logger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides a simple logging system with the possibility of registering log observers. 3 | * In order to track the source module of message logs, 4 | * a customized logger should be instanciated using the getLogger() method just after its injection. 5 | * 6 | * 4 different log levels are provided, via corresponding methods: 7 | * - log: for debug information 8 | * - info: for informative status of the application (success, ...) 9 | * - warning: for non-critical errors that do not prevent normal application behavior 10 | * - error: for critical errors that prevent normal application behavior 11 | * 12 | * Example usage: 13 | * angular.module('myService', ['logger']).factory('myService', function (logger) { 14 | * logger = logger.getLogger('myService'); 15 | * ... 16 | * logger.log('something happened'); 17 | * } 18 | * 19 | * If you want to disable debug logs in production, add this snippet to your app configuration: 20 | * angular.module('app').config(function ($provide) { 21 | * // Disable debug logs in production version 22 | * $provide.decorator('$log', ['$delegate', function($delegate) { 23 | * if (!debug) { 24 | * $delegate.log = function() {}; 25 | * } 26 | * return $delegate; 27 | * }]); 28 | * }); 29 | * 30 | * If you want additional tasks to be performed on log entry (show toast, for example), 31 | * you can register observers using the addObserver() method. 32 | */ 33 | 34 | import app from 'main.module'; 35 | 36 | let observers: Array = []; 37 | 38 | /** 39 | * Logs a message from the specified source. 40 | * @param {string} message The message to be logged. 41 | * @param {?string=} source The source of the log. 42 | * @param {function} logFunc The base log function to use. 43 | * @param {'log'|'info'|'warning'|'error'} level The log level. 44 | * @param {Object?} options Additional log options. 45 | */ 46 | function log(message: string, source: string, logFunc: Function, level: string, options: any): void { 47 | logFunc(source ? '[' + source + ']' : '', message, ''); 48 | angular.forEach(observers, (observerFunc: any) => { 49 | observerFunc(message, source, level, options); 50 | }); 51 | } 52 | 53 | export interface ILogger { 54 | 55 | /** 56 | * Logs a message with the log level. 57 | * @param {string} message The message to be logged. 58 | * @param {Object?} options Additional log options. 59 | */ 60 | log(message: string, options?: Object): void; 61 | 62 | /** 63 | * Logs a message with the info level. 64 | * @param {string} message The message to be logged. 65 | * @param {Object?} options Additional log options. 66 | */ 67 | 68 | info(message: string, options?: Object): void; 69 | 70 | /** 71 | * Logs a message with the warning level. 72 | * @param {string} message The message to be logged. 73 | * @param {Object?} options Additional log options. 74 | */ 75 | warning(message: string, options?: Object): void; 76 | 77 | /** 78 | * Logs a message with the error level. 79 | * @param {string} message The message to be logged. 80 | * @param {Object?} options Additional log options. 81 | */ 82 | error(message: string, options?: Object): void; 83 | 84 | } 85 | 86 | export interface IObserverFunction { 87 | (message: string, source: string, level: string, options?: any): void; 88 | } 89 | 90 | class Logger implements ILogger { 91 | 92 | constructor(private $log: ng.ILogService, 93 | private moduleName: string, 94 | private logFunc: any) {} 95 | 96 | log(message: string, options: any): void { 97 | this.logFunc(message, this.moduleName, this.$log.log, 'log', options); 98 | } 99 | 100 | info(message: string, options: any): void { 101 | this.logFunc(message, this.moduleName, this.$log.info, 'info', options); 102 | } 103 | 104 | warning(message: string, options: any): void { 105 | this.logFunc(message, this.moduleName, this.$log.warn, 'warning', options); 106 | } 107 | 108 | error(message: string, options: any): void { 109 | this.logFunc(message, this.moduleName, this.$log.error, 'error', options); 110 | } 111 | 112 | } 113 | 114 | export class LoggerService { 115 | 116 | constructor(private $log: ng.ILogService) {} 117 | 118 | /** 119 | * Gets a customized logger based on the given module name. 120 | * @param {string} moduleName The module name. 121 | * @return {Logger} A logger object. 122 | */ 123 | getLogger(moduleName: string): ILogger { 124 | return new Logger(this.$log, moduleName, log); 125 | } 126 | 127 | /** 128 | * Adds a new observer function that will be called for each new log entry. 129 | * These parameters are passed to the observer function, in order: 130 | * - message {string} message The message to be logged. 131 | * - source {?string=} source The source of the log. 132 | * - level {'log'|'info'|'warning'|'error'} level The log level. 133 | * - options {Object?} options Additional log options. 134 | * @param {!function} observerFunc The observer function. 135 | */ 136 | addObserver(observerFunc: IObserverFunction): void { 137 | observers.push(observerFunc); 138 | } 139 | 140 | } 141 | 142 | app.service('logger', LoggerService); 143 | -------------------------------------------------------------------------------- /generators/app/templates/gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gutil = require('gulp-util'); 5 | var gulp = require('gulp'); 6 | var conf = require('../gulpfile.config'); 7 | var minimist = require('minimist'); 8 | 9 | var packageConfig = require('../package.json'); 10 | 11 | var $ = require('gulp-load-plugins')({ 12 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 13 | }); 14 | 15 | var options = minimist(process.argv.slice(2), { 16 | string: 'environment', 17 | boolean: 'debug', 18 | alias: { e: 'environment' } 19 | }); 20 | 21 | function replaceConstant(contents, string, replacement) { 22 | // Make sure we replace only the string located inside markers 23 | var constantRegExp = new RegExp('(// replace:constant[\\s\\S]*?)' + string + '([\\s\\S]*?// endreplace)', 'gm'); 24 | return contents.replace(constantRegExp, '$1' + replacement + '$2') 25 | } 26 | 27 | function setEnvironment(file) { 28 | var contents = file.contents.toString(); 29 | 30 | // Get the object containing all environments values 31 | var environmentRegExp = new RegExp('// replace:environment\\s*?([\\s\\S]*?)// endreplace', 'gm'); 32 | var environment = eval(environmentRegExp.exec(contents)[1] + 'environment;'); 33 | 34 | // Get the target environment value 35 | var name = options.environment || conf.defaultBuildEnvironment; 36 | var value = environment[name]; 37 | 38 | if (!value) { 39 | throw new gutil.PluginError({ 40 | plugin: 'setEnvironment', 41 | message: 'Cannot find configuration for environment "' + name + '".\n' + 42 | 'Check your environment values in file `main.constants.ts`\n' 43 | }); 44 | } 45 | 46 | gutil.log('Building for environment: ' + gutil.colors.green(name)); 47 | 48 | // Replace constant values 49 | contents = replaceConstant(contents, 'environment: environment.local', 'environment: ' + JSON.stringify(value)); 50 | contents = replaceConstant(contents, 'version: \'dev\'', 'version: \'' + packageConfig.version + '\''); 51 | 52 | // Remove all environment values and update file 53 | file.contents = new Buffer(contents.replace(environmentRegExp, '')); 54 | 55 | return file; 56 | } 57 | 58 | gulp.task('build:sources', ['inject'], function() { 59 | var htmlFilter = $.filter('*.html', {restore: true, dot: true}); 60 | var jsFilter = $.filter('**/*.js', {restore: true, dot: true}); 61 | var cssFilter = $.filter('**/*.css', {restore: true, dot: true}); 62 | 63 | var task = gulp.src(path.join(conf.paths.tmp, 'index.html')) 64 | .pipe($.replace(/`. 27 | 28 | The default build environment is `production`. See [this documentation](docs/build-environments.md) for more details 29 | about multiple build environments management. 30 | 31 | You can disable opening automatically your default browser when using the `serve` commands by using the flag 32 | `--skip-open`. 33 | 34 | ## Tests 35 | 36 | Task | Description 37 | ---------------------|------------------------------------------------------------------------------------------------ 38 | test | Launch unit tests using karma and jasmine. 39 | test:auto | Launch karma server and trigger unit tests after each change in project file. 40 | protractor | Launch e2e tests using protractor. 41 | protractor:dist | Launch e2e tests using protractor, using dist files. 42 | webdriver:update | Download/Update selenium standalone and chromedriver. 43 | webdriver:standalone | Launch a standalone selenium server. 44 | 45 | ## Translations 46 | 47 | Task | Description 48 | ---------------------|------------------------------------------------------------------------------------------------ 49 | translations | Generate translations file in .tmp that will be used by server. 50 | translations:extract | Extract Messages from Code and Templates to template.pot. 51 | 52 | ## TypeScript 53 | 54 | Task | Description 55 | ------------|--------------------------------------------------------------------------------------------------------- 56 | scripts | Convert all *.ts found in project to js in the temporary folder. 57 | tsd | Download and update all TypeScript definitions for Bower dependencies. 58 | tsd:restore | Download TypeScript definitions according to tsd.json. 59 | tsd:clean | Delete downloaded TypeScript definitions. 60 | 61 | ## Build and assets 62 | 63 | Task | Description 64 | -------------|-------------------------------------------------------------------------------------------------------- 65 | build:source | Build and optimize all source files, excluding assets. 66 | partials | Put all .html found in project folder + in temporary folder in a template cache file. 67 | styles | Generate main CSS file using project main style file. 68 | fonts | Copy fonts from bower dependencies in dist folder. 69 | images | Compress images (using imagemin) then copy them in dist folder. 70 | other | Copy project fonts and other misc files in dist folder. 71 | extra | Copy extra non-project files as specified in `gulpfile.config.js`. 72 | clean:dist | Clean the dist folder. 73 | 74 | When building your app, you can use the `--debug` flag with any build task to skip the minification process. This can 75 | be useful to debug your production builds. 76 | 77 | <% if (props.target !== 'web') { -%> 78 | ## Cordova 79 | 80 | Task | Description 81 | ------------------------------|--------------------------------------------------------------------------------------- 82 | cordova:build | Build the apps for development. 83 | cordova:release | Build the apps and sign them for app store publication. 84 | cordova:prepare | Restore cordova platforms and plugins if needed and prepare for build. 85 | cordova:remove | Remove cordova `plaforms/` and `plugins/` folders. 86 | cordova:resources | Compress resources (using imagemin) then copy in temp folder. 87 | build:<ios|android> | Build the iOS or Android app for development. 88 | run:<ios|android> [--device] | Run the iOS or Android app in emulator (or device with the `--device` option). 89 | release:<ios|android> | Build the iOS or Android app and sign it for app store publication. 90 | cordova --command="<command>" | Executes any cordova command (see [cordova-cli](https://github.com/apache/cordova-cli)). 91 | 92 | Note that all the cordova tasks support a `--fast` option that allows to skip the rebuild of the source folder and 93 | the resources compression. Use it only when your know that the sources have not changed. 94 | <% } -%> 95 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/_main.run.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {IApplicationConfig} from 'main.constants'; 3 | import {RestService} from 'helpers/rest/rest.service'; 4 | <% if (props.target !== 'web') { -%> 5 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 6 | <% } -%> 7 | 8 | /** 9 | * Entry point of the application. 10 | * Initializes application and root controller. 11 | */ 12 | function main($window: ng.IWindowService, 13 | $locale: ng.ILocaleService, 14 | $rootScope: any, 15 | $state: angular.ui.IStateService, 16 | <% if (props.target !== 'web') { -%> 17 | $timeout: ng.ITimeoutService, 18 | $cordovaKeyboard: any, 19 | <% } -%> 20 | <% if (props.ui === 'ionic') { -%> 21 | $ionicPlatform: ionic.platform.IonicPlatformService, 22 | <% } -%> 23 | gettextCatalog: angular.gettext.gettextCatalog, 24 | _: _.LoDashStatic, 25 | config: IApplicationConfig, 26 | <% if (props.target !== 'web') { -%> 27 | logger: LoggerService, 28 | <% } -%> 29 | restService: RestService) { 30 | 31 | /* 32 | * Root view model 33 | */ 34 | 35 | let vm = $rootScope; 36 | 37 | vm.pageTitle = ''; 38 | <% if (props.ui === 'ionic') { -%> 39 | vm.viewTitle = ''; 40 | <% } -%> 41 | 42 | /** 43 | * Utility method to set the language in the tools requiring it. 44 | * The current language is saved to the local storage. 45 | * If no parameter is specified, the language is loaded from local storage (if possible). 46 | * @param {string=} language The IETF language tag. 47 | */ 48 | vm.setLanguage = function(language?: string) { 49 | language = language || $window.localStorage.getItem('language'); 50 | let isSupportedLanguage = _.includes(config.supportedLanguages, language); 51 | 52 | <% if (props.target !== 'web') { -%> 53 | // If no exact match is found, search without the region 54 | if (!isSupportedLanguage && language) { 55 | let languagePart = language.split('-')[0]; 56 | language = _.find(config.supportedLanguages, 57 | (supportedLanguage: string) => _.startsWith(supportedLanguage, languagePart)); 58 | isSupportedLanguage = !!language; 59 | } 60 | 61 | <% } -%> 62 | // Fallback if language is not supported 63 | if (!isSupportedLanguage) { 64 | language = 'en-US'; 65 | } 66 | 67 | // Configure translation with gettext 68 | gettextCatalog.setCurrentLanguage(language); 69 | $locale.id = language; 70 | $window.localStorage.setItem('language', language); 71 | }; 72 | 73 | /** 74 | * Updates title on view change. 75 | */ 76 | vm.$on('$stateChangeSuccess', (event: any, toState: angular.ui.IState) => { 77 | updateTitle(toState.data ? toState.data.title : null); 78 | }); 79 | 80 | /** 81 | * Updates title on language change. 82 | */ 83 | vm.$on('gettextLanguageChanged', () => { 84 | updateTitle($state.current.data ? $state.current.data.title : null); 85 | }); 86 | 87 | init(); 88 | 89 | /* 90 | * Internal 91 | */ 92 | 93 | /** 94 | * Initializes the root controller. 95 | */ 96 | function init() { 97 | <% if (props.target !== 'web') { -%> 98 | let _logger: ILogger = logger.getLogger('main'); 99 | <% } -%> 100 | // Enable debug mode for translations 101 | gettextCatalog.debug = config.environment.debug; 102 | 103 | vm.setLanguage(); 104 | 105 | // Set REST server configuration 106 | restService.setServer(config.environment.server); 107 | <% if (props.target !== 'web') { -%> 108 | 109 | // Cordova platform and plugins init 110 | <% if (props.ui !== 'ionic') { -%> 111 | $window.document.addEventListener('deviceready', () => { 112 | <% if (props.ui === 'bootstrap') { -%> 113 | 114 | // Remove 300ms delay 115 | FastClick.attach($window.document.body); 116 | <% } -%> 117 | <% } else { -%> 118 | $ionicPlatform.ready(() => { 119 | <% } -%> 120 | 121 | // Hide splash screen 122 | let splashScreen = $window.navigator.splashscreen; 123 | if (splashScreen) { 124 | $timeout(() => { 125 | splashScreen.hide(); 126 | }, 1000); 127 | } 128 | 129 | // Detect and set default language 130 | let globalization = $window.navigator.globalization; 131 | if (globalization) { 132 | // Use cordova plugin to retrieve device's locale 133 | globalization.getPreferredLanguage((language) => { 134 | _logger.log('Setting device locale "' + language.value + '" as default language'); 135 | vm.$apply(() => { 136 | vm.setLanguage(language.value); 137 | }); 138 | }, null); 139 | } 140 | 141 | if ($window.cordova && $window.cordova.plugins.Keyboard) { 142 | $cordovaKeyboard.disableScroll(true); 143 | } 144 | 145 | }<% if (props.ui !== 'ionic') { %>, false<% } %>); 146 | <% } -%> 147 | } 148 | 149 | /** 150 | * Updates the title. 151 | * @param {?string=} stateTitle Title of current state, to be translated. 152 | */ 153 | function updateTitle(stateTitle?: string) { 154 | vm.pageTitle = gettextCatalog.getString('APP_NAME'); 155 | 156 | if (stateTitle) { 157 | <% if (props.ui === 'ionic') { -%> 158 | vm.viewTitle = gettextCatalog.getString(stateTitle); 159 | vm.pageTitle += ' | ' + vm.viewTitle; 160 | <% } else { -%> 161 | vm.pageTitle += ' | ' + gettextCatalog.getString(stateTitle); 162 | <% } -%> 163 | } 164 | } 165 | 166 | } 167 | 168 | app.run(main); 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generator-angular-pro 2 | 3 | [![NPM version](https://img.shields.io/npm/v/generator-angular-pro.svg)](https://www.npmjs.com/package/generator-angular-pro) 4 | [![Build status](https://img.shields.io/travis/angular-starter-kit/generator-angular-pro/master.svg)](https://travis-ci.org/angular-starter-kit/generator-angular-pro) 5 | [![Downloads](https://img.shields.io/npm/dt/generator-angular-pro.svg)](https://npmjs.org/package/generator-angular-pro) 6 | 7 | Web/mobile Angular project generator for *scalable*, *enterprise-grade* applications. 8 | 9 | Includes modern (and stable) tools and workflow, best practices, base template and an exhaustive documentation. 10 | Get started quickly even with beginner teams, in any work environment (proxy included). 11 | 12 | Built on experience with large web projects, with architecture choices aiming for a clean, no-brainer development 13 | experience. 14 | 15 | See generated project example [here](https://github.com/angular-starter-kit/starter-kit). 16 | 17 | ![logo](https://raw.githubusercontent.com/angular-starter-kit/starter-kit/gh-pages/assets/angular-starter-kit-256.png) 18 | 19 | # Getting started 20 | 21 | 1. Install required tools: 22 | ``` 23 | npm install -g yo gulp bower generator-angular-pro 24 | ``` 25 | 26 | 2. Create your application: 27 | ``` 28 | yo angular-pro 29 | ``` 30 | 31 | # Project structure 32 | ``` 33 | gulp/ individual gulp tasks 34 | sources/ project source code 35 | |- data/ other project data, will be copied as-is 36 | |- fonts/ project fonts 37 | |- images/ project images 38 | |- libraries/ Bower dependencies 39 | |- main/ app components 40 | | |- main.config.ts app configuration code 41 | | |- main.constants.ts app configuration constants 42 | | |- main.module.ts app module definition 43 | | |- main.routes.ts app routes 44 | | |- main.run.ts app entry point 45 | | |- main.wrappers.ts AngularJS module wrappers for external libraries 46 | | |- main.scss style entry point 47 | | |- helpers/ helper services 48 | | |- screens/ application screens 49 | | |- shell/ application shell 50 | | |- ui-components/ shared UI components 51 | | |- web-services/ web services 52 | | +- ... additional components 53 | |- translations/ translations files 54 | +- index.html html entry point 55 | e2e/ end-to-end tests 56 | dist/ compiled version (www/ for mobile projects) 57 | typings/ TypeScript definitions 58 | reports/ test and coverage reports + generated documentation 59 | platforms/ Cordova platform-specific projects (for mobile projects) 60 | plugins/ Cordova plugins (for mobile projects) 61 | resources/ icon and splash screen resources (for mobile projects) 62 | gulpfile.config.js gulp tasks configuration 63 | ``` 64 | 65 | # Coding guides 66 | 67 | - [JavaScript](generators/app/templates/docs/coding-guides/javascript.md) 68 | - [TypeScript](generators/app/templates/docs/coding-guides/typescript.md) 69 | - [CSS](generators/app/templates/docs/coding-guides/css.md) 70 | - [HTML](generators/app/templates/docs/coding-guides/html.md) 71 | - [Unit tests](generators/app/templates/docs/coding-guides/unit-tests.md) 72 | - [End-to-end tests](generators/app/templates/docs/coding-guides/e2e-tests.md) 73 | 74 | # Additional documentation 75 | 76 | - [Cordova](generators/app/templates/_mobile/docs/cordova.md) (for mobile projects) 77 | - [Build environments](generators/app/templates/docs/build-environments.md) 78 | - [i18n](generators/app/templates/docs/i18n.md) 79 | - [Proxy configuration](generators/app/templates/docs/proxy.md) 80 | - [Updating dependencies](generators/app/templates/docs/updating.md) 81 | 82 | # Features 83 | 84 | - [TypeScript](http://www.typescriptlang.org), [Sass](http://sass-lang.com/), pure HTML 85 | - [Gettext](https://angular-gettext.rocketeer.be) for translations 86 | - [TSLint](https://github.com/palantir/tslint) 87 | - Unit tests ([Jasmine](http://jasmine.github.io)) 88 | - End-to-end tests ([Protractor](https://github.com/angular/protractor)) 89 | - Development server with API proxy and live reload ([BrowserSync](http://www.browsersync.io)) 90 | - Automatic CSS browser support with [autoprefixer](https://github.com/sindresorhus/gulp-autoprefixer) 91 | - Automatic Angular modules annotation ([ngAnnotate](https://github.com/Kagami/gulp-ng-annotate)) 92 | - Production code and assets optimization: 93 | * Bundling with [useref](https://github.com/jonkemp/gulp-useref) 94 | * Minification of JavaScript, CSS and HTML 95 | * Images optimization ([imagemin](https://github.com/sindresorhus/gulp-imagemin)) 96 | * Asset revisionning ([rev](https://github.com/sindresorhus/gulp-rev)) 97 | - i18n workflow (https://angular-gettext.rocketeer.be) 98 | - Multiple build environments management 99 | - Task automation with [gulp](http://gulpjs.com) 100 | 101 | # Libraries 102 | 103 | - [AngularJS](https://angularjs.org) 104 | - [Angular-gettext](https://angular-gettext.rocketeer.be) 105 | - [AngularUI Router](https://github.com/angular-ui/ui-router) 106 | - [Lodash](https://lodash.com) 107 | - [ngCordova](http://ngcordova.com/) (for mobile projects) 108 | - UI based on Bootstrap... 109 | * [UI Bootsrap](https://angular-ui.github.io/bootstrap) 110 | * [Bootstrap](http://getbootstrap.com) 111 | * [Font Awesome](http://fortawesome.github.io/Font-Awesome) 112 | - ... or Ionic 113 | * [Ionic](http://ionicframework.com/) 114 | 115 | # License 116 | 117 | MIT 118 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/cache/cache.service.ts: -------------------------------------------------------------------------------- 1 | import app from 'main.module'; 2 | import {ILogger, LoggerService} from 'helpers/logger/logger'; 3 | 4 | export interface ICacheData { 5 | date: Date; 6 | data: any; 7 | } 8 | 9 | export interface ICache { 10 | [name: string]: ICacheData; 11 | } 12 | 13 | /** 14 | * Cache service: manages cached data for GET requests. 15 | * By default, the cache is only persisted in memory, but you can change this behavior using the setPersistence() 16 | * method. 17 | */ 18 | export class CacheService { 19 | 20 | private logger: ILogger; 21 | private cachedData: ICache = {}; 22 | private storage: any = null; 23 | 24 | constructor(private $window: ng.IWindowService, 25 | logger: LoggerService) { 26 | 27 | this.logger = logger.getLogger('cacheService'); 28 | 29 | /** 30 | * Initializes service. 31 | */ 32 | this.loadCacheData(); 33 | } 34 | 35 | /** 36 | * Sets the cache data for the specified request. 37 | * @param {!string} url URL of the REST service call. 38 | * @param {map=} params Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be 39 | * JSONified. 40 | * @param {Object} data The received data. 41 | * @param {Date=} date The cache date, now date is used if not specified. 42 | */ 43 | setCacheData(url: string, params: any, data: any, date?: Date): void { 44 | let cacheKey = this.getCacheKey(url, params); 45 | 46 | this.cachedData[cacheKey] = { 47 | date: date || new Date(), 48 | data: data 49 | }; 50 | 51 | this.logger.log('Cache set for key: "' + cacheKey + '"'); 52 | 53 | this.saveCacheData(); 54 | } 55 | 56 | /** 57 | * Gets the cached data (if possible) for the specified request. 58 | * @param {!string} url URL of the REST service call. 59 | * @param {?map=} params Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be 60 | * JSONified. 61 | * @return {?Object} The cached data or null if no cached data exists for this request. 62 | */ 63 | getCacheData(url: string, params?: any): any { 64 | let cacheKey = this.getCacheKey(url, params); 65 | let cacheEntry = this.cachedData[cacheKey]; 66 | 67 | if (cacheEntry) { 68 | this.logger.log('Cache hit for key: "' + cacheKey + '"'); 69 | return cacheEntry.data; 70 | } 71 | 72 | return null; 73 | } 74 | 75 | /** 76 | * Gets the cached data date (if possible) for the specified request. 77 | * @param {!string} url URL of the REST service call. 78 | * @param {?map=} params Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be 79 | * JSONified. 80 | * @return {?Object} The cached data date or null if no cached data exists for this request. 81 | */ 82 | getCacheDate(url: string, params?: any): Date { 83 | let cacheKey = this.getCacheKey(url, params); 84 | let cacheEntry = this.cachedData[cacheKey]; 85 | return cacheEntry ? cacheEntry.date : null; 86 | } 87 | 88 | /** 89 | * Clears the cached data (if exists) for the specified request. 90 | * @param {!string} url URL of the REST service call. 91 | * @param {?map=} params Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be 92 | * JSONified. 93 | */ 94 | clearCacheData(url: string, params?: any): void { 95 | let cacheKey = this.getCacheKey(url, params); 96 | this.cachedData[cacheKey] = undefined; 97 | this.logger.log('Cache cleared for key: "' + cacheKey + '"'); 98 | this.saveCacheData(); 99 | } 100 | 101 | /** 102 | * Cleans cache entries older than the specified date. 103 | * @param {date=} expirationDate The cache expiration date. If no date is specified, all cache is cleared. 104 | */ 105 | cleanCache(expirationDate?: Date): void { 106 | if (expirationDate) { 107 | angular.forEach(this.cachedData, (value: any, key: string) => { 108 | if (expirationDate >= value.date) { 109 | this.cachedData[key] = undefined; 110 | } 111 | }); 112 | } else { 113 | this.cachedData = {}; 114 | } 115 | this.saveCacheData(); 116 | } 117 | 118 | /** 119 | * Sets the cache persistence. 120 | * Note that changing the cache persistence will also clear the cache from its previous storage. 121 | * @param {'local'|'session'=} persistence How the cache should be persisted, it can be either 122 | * in the local or session storage, or if no parameters is provided it will be only in-memory (default). 123 | */ 124 | setPersistence(persistence?: string): void { 125 | this.cleanCache(); 126 | this.storage = persistence === 'local' || persistence === 'session' ? 127 | this.$window[persistence + 'Storage'] : null; 128 | 129 | this.loadCacheData(); 130 | }; 131 | 132 | /** 133 | * Gets the cache key for the specified url and parameters. 134 | * @param {!string} url The request URL. 135 | * @param {?map=} params Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be 136 | * JSONified. 137 | * @return {string} The corresponding cache key. 138 | */ 139 | private getCacheKey(url: string, params?: any): string { 140 | return url + (params ? angular.toJson(params) : ''); 141 | } 142 | 143 | /** 144 | * Saves the current cached data into persisted storage. 145 | */ 146 | private saveCacheData(): void { 147 | if (this.storage) { 148 | this.storage.cachedData = angular.toJson(this.cachedData); 149 | } 150 | } 151 | 152 | /** 153 | * Loads cached data from persisted storage. 154 | */ 155 | private loadCacheData(): void { 156 | let data = this.storage ? this.storage.cachedData : null; 157 | this.cachedData = data ? angular.fromJson(data) : {}; 158 | } 159 | 160 | } 161 | 162 | app.service('cacheService', CacheService); 163 | -------------------------------------------------------------------------------- /generators/app/templates/_mobile/_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | App 4 | 5 | A mobile app based on Ionic and Cordova. 6 | 7 | 8 | Your Name Here 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <% if (props.ui === 'bootstrap') { -%> 21 | 22 | <% } -%> 23 | 24 | 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 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const yosay = require('yosay'); 5 | const chalk = require('chalk'); 6 | const dir = require('node-dir'); 7 | const path = require('path'); 8 | const Generator = require('yeoman-generator'); 9 | 10 | const options = require('./options.json'); 11 | const prompts = require('./prompts.json'); 12 | const pkg = require('../../package.json'); 13 | 14 | const excludeFiles = [ 15 | '.DS_Store', 16 | 'Thumbs.db' 17 | ]; 18 | 19 | const nameRules = { 20 | _mobile: (props) => props.target !== 'web', 21 | _web: (props) => props.target !== 'mobile', 22 | _bootstrap: (props) => props.ui === 'bootstrap', 23 | _material: (props) => props.ui === 'material', 24 | _ionic: (props) => props.ui === 'ionic' 25 | }; 26 | 27 | module.exports = class extends Generator { 28 | 29 | constructor(args, opts) { 30 | super(args, opts); 31 | 32 | this.argument('appName', { 33 | desc: 'Name of the application to scaffold', 34 | type: String, 35 | required: false 36 | }); 37 | 38 | this.version = pkg.version; 39 | 40 | // Use options from json 41 | options.forEach((option) => { 42 | this.option(option.name, { 43 | type: global[option.type], 44 | required: option.required, 45 | desc: option.desc, 46 | defaults: option.defaults 47 | }); 48 | }); 49 | } 50 | 51 | info() { 52 | this.log(yosay( 53 | chalk.red('Welcome!\n') + 54 | chalk.yellow('You\'re about to scaffold an awesome application based on Angular!') 55 | )); 56 | } 57 | 58 | ask() { 59 | let processProps = (props) => { 60 | props.appName = props.appName || this.options.appName; 61 | props.projectName = _.kebabCase(props.appName); 62 | 63 | this.props = props; 64 | }; 65 | 66 | if (this.options.automate) { 67 | // Do no prompt, use json file instead 68 | let props = require(path.resolve(this.options.automate)); 69 | processProps(props); 70 | } else { 71 | let namePrompt = _.find(prompts, {name: 'appName'}); 72 | namePrompt.default = path.basename(process.cwd()); 73 | namePrompt.when = () => { 74 | return !this.options.appName; 75 | }; 76 | 77 | // Use prompts from json 78 | return this.prompt(prompts).then((props) => { 79 | processProps(props); 80 | }); 81 | } 82 | } 83 | 84 | prepare() { 85 | return new Promise((resolve) => { 86 | let filesPath = path.join(__dirname, 'templates'); 87 | 88 | dir.files(filesPath, (err, files) => { 89 | if (err) throw err; 90 | 91 | // Removes excluded files 92 | _.remove(files, (file) => { 93 | return !_.every(excludeFiles, (excludeFile) => { 94 | return !_.includes(file, excludeFile); 95 | }); 96 | }); 97 | 98 | this.files = _.map(files, (file) => { 99 | let src = path.relative(filesPath, file); 100 | let isTemplate = _.startsWith(path.basename(src), '_'); 101 | let hasFileCondition = _.startsWith(path.basename(src), '__'); 102 | let hasFolderCondition = _.startsWith(path.dirname(src), '_'); 103 | let dest = path.relative(hasFolderCondition ? path.dirname(src).split(path.sep)[0] : '.', src); 104 | 105 | if (hasFileCondition) { 106 | let fileName = path.basename(src).replace(/__.*?[.]/, '_'); 107 | dest = path.join(path.dirname(src), fileName); 108 | } 109 | 110 | if (isTemplate) { 111 | dest = path.join(path.dirname(dest), path.basename(dest).slice(1)); 112 | } 113 | 114 | return { 115 | src: src, 116 | dest: dest, 117 | template: isTemplate, 118 | hasFileCondition: hasFileCondition, 119 | hasFolderCondition: hasFolderCondition 120 | }; 121 | }); 122 | 123 | resolve(); 124 | }); 125 | }); 126 | } 127 | 128 | config() { 129 | // Generate .yo-rc.json 130 | this.config.set('version', this.version); 131 | this.config.set('props', this.props); 132 | this.config.save(); 133 | } 134 | 135 | write() { 136 | this.files.forEach((file) => { 137 | let write = !file.hasFolderCondition || _.every(nameRules, (rule, folder) => { 138 | return !_.startsWith(path.dirname(file.src), folder) || rule(this.props); 139 | }); 140 | 141 | write = write && (!file.hasFileCondition || _.every(nameRules, (rule, prefix) => { 142 | return !_.startsWith(path.basename(file.src), '_' + prefix) || rule(this.props); 143 | })); 144 | 145 | if (write) { 146 | try { 147 | if (file.template) { 148 | this.fs.copyTpl(this.templatePath(file.src), this.destinationPath(file.dest), this); 149 | } else { 150 | this.fs.copy(this.templatePath(file.src), this.destinationPath(file.dest)); 151 | } 152 | } catch (error) { 153 | console.error('Template processing error on file', file.src); 154 | throw error; 155 | } 156 | } 157 | }); 158 | } 159 | 160 | install() { 161 | // Launch npm, bower and tsd installs if not skipped 162 | this.installDependencies({ 163 | skipInstall: this.options['skip-install'], 164 | skipMessage: this.options['skip-message'], 165 | callback: () => { 166 | if (!this.options['skip-install']) { 167 | this.spawnCommandSync('gulp', ['typings:restore']); 168 | 169 | // Prepare Cordova platforms 170 | if (this.props.target !== 'web') { 171 | this.spawnCommandSync('gulp', ['cordova:prepare']); 172 | } 173 | } 174 | } 175 | }); 176 | } 177 | 178 | end() { 179 | this.log('\nAll done! Get started with these gulp tasks:'); 180 | this.log('- `$ ' + chalk.green('gulp') + '` to build an optimized version of your application'); 181 | this.log('- `$ ' + chalk.green('gulp serve') + '` to start dev server on your source files with live reload'); 182 | this.log('- `$ ' + chalk.green('gulp serve:dist') + '` to start dev server on your optimized application without live reload'); 183 | this.log('- `$ ' + chalk.green('gulp test') + '` to run your unit tests'); 184 | this.log('- `$ ' + chalk.green('gulp test:auto') + '` to run your unit tests with in watch mode'); 185 | this.log('- `$ ' + chalk.green('gulp protractor') + '` to launch your e2e tests'); 186 | this.log('- `$ ' + chalk.green('gulp protractor:dist') + '` to launch your e2e tests on your optimized application'); 187 | this.log('\nSee more in docs and coding guides:'); 188 | 189 | if (this.props.target !== 'web') { 190 | this.log(chalk.underline('https://github.com/angular-starter-kit/starter-kit/tree/mobile\n')); 191 | } else { 192 | this.log(chalk.underline('https://github.com/angular-starter-kit/starter-kit\n')); 193 | } 194 | } 195 | 196 | }; 197 | -------------------------------------------------------------------------------- /generators/app/templates/sources/main/helpers/cache/cache.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {CacheService} from 'cache.service'; 2 | 3 | describe('cacheService', () => { 4 | 5 | let cacheService: CacheService; 6 | 7 | beforeEach(() => { 8 | angular.mock.module('app'); 9 | 10 | // Start fresh :-) 11 | window.sessionStorage.removeItem('cachedData'); 12 | window.localStorage.removeItem('cachedData'); 13 | 14 | inject((_cacheService_: CacheService) => { 15 | cacheService = _cacheService_; 16 | }); 17 | }); 18 | 19 | afterEach(() => { 20 | cacheService.cleanCache(); 21 | }); 22 | 23 | it('should have a setCacheData method', () => { 24 | expect(typeof (cacheService.setCacheData)).toBe('function'); 25 | }); 26 | 27 | it('should have a getCacheData method', () => { 28 | expect(typeof (cacheService.getCacheData)).toBe('function'); 29 | }); 30 | 31 | it('should have a getCacheDate method', () => { 32 | expect(typeof (cacheService.getCacheDate)).toBe('function'); 33 | }); 34 | 35 | it('should have a clearCacheData method', () => { 36 | expect(typeof (cacheService.clearCacheData)).toBe('function'); 37 | }); 38 | 39 | it('should have a cleanCache method', () => { 40 | expect(typeof (cacheService.cleanCache)).toBe('function'); 41 | }); 42 | 43 | it('should have a setPersistence method', () => { 44 | expect(typeof (cacheService.setPersistence)).toBe('function'); 45 | }); 46 | 47 | describe('setCacheData', () => { 48 | 49 | it('should set cache data', () => { 50 | // Act 51 | cacheService.setCacheData('/popo', null, 'data'); 52 | 53 | // Assert 54 | expect(cacheService.getCacheData('/popo')).toBe('data'); 55 | }); 56 | 57 | it('should replace existing data', () => { 58 | // Act 59 | cacheService.setCacheData('/popo', null, 'data'); 60 | cacheService.setCacheData('/popo', null, 'newdata'); 61 | 62 | // Assert 63 | expect(cacheService.getCacheData('/popo')).toBe('newdata'); 64 | }); 65 | 66 | it('should set cache date correctly', () => { 67 | // Act 68 | let date = new Date(123); 69 | cacheService.setCacheData('/popo', null, 'data', date); 70 | cacheService.setCacheData('/hoho', null, 'data'); 71 | 72 | // Assert 73 | expect(cacheService.getCacheDate('/popo')).toBe(date); 74 | expect(cacheService.getCacheDate('/hoho')).not.toBe(date); 75 | }); 76 | 77 | }); 78 | 79 | describe('getCacheData', () => { 80 | 81 | it('should return null if no cache', () => { 82 | expect(cacheService.getCacheData('/hoho', null)).toBe(null); 83 | }); 84 | 85 | it('should return cached data if exists', () => { 86 | // Act 87 | cacheService.setCacheData('/hoho', null, 'data'); 88 | 89 | // Assert 90 | expect(cacheService.getCacheData('/hoho')).toBe('data'); 91 | }); 92 | 93 | it('should return cached data with url parameters if exists', () => { 94 | // Act 95 | cacheService.setCacheData('/hoho', {pif: 'paf'}, 'data'); 96 | 97 | // Assert 98 | expect(cacheService.getCacheData('/hoho', {pif: 'paf'})).toBe('data'); 99 | }); 100 | 101 | }); 102 | 103 | describe('getCacheDate', () => { 104 | 105 | it('should return null if no cache', () => { 106 | expect(cacheService.getCacheDate('/hoho', null)).toBe(null); 107 | }); 108 | 109 | it('should return cached data date if exists', () => { 110 | // Act 111 | let date = new Date(123); 112 | cacheService.setCacheData('/hoho', null, 'data', date); 113 | 114 | // Assert 115 | expect(cacheService.getCacheDate('/hoho')).toBe(date); 116 | }); 117 | 118 | }); 119 | 120 | describe('clearCacheData', () => { 121 | 122 | it('should clear existing cache data', () => { 123 | // Set cache 124 | cacheService.setCacheData('/hoho', null, 'data'); 125 | expect(cacheService.getCacheData('/hoho')).toBe('data'); 126 | 127 | // Clear cache 128 | cacheService.clearCacheData('/hoho', null); 129 | expect(cacheService.getCacheData('/hoho', null)).toBe(null); 130 | }); 131 | 132 | it('should do nothing if no cache exists', () => { 133 | expect(cacheService.getCacheData('/lolo', null)).toBe(null); 134 | cacheService.clearCacheData('/hoho', null); 135 | expect(cacheService.getCacheData('/lolo', null)).toBe(null); 136 | }); 137 | 138 | }); 139 | 140 | describe('cleanCache', () => { 141 | 142 | it('should clear all cache if no date is specified', () => { 143 | // Set cache 144 | cacheService.setCacheData('/hoho', null, 'data'); 145 | cacheService.setCacheData('/popo', null, 'data'); 146 | expect(cacheService.getCacheData('/hoho')).toBe('data'); 147 | expect(cacheService.getCacheData('/popo')).toBe('data'); 148 | 149 | // Clean cache 150 | cacheService.cleanCache(); 151 | expect(cacheService.getCacheData('/hoho', null)).toBe(null); 152 | expect(cacheService.getCacheData('/popo', null)).toBe(null); 153 | }); 154 | 155 | it('should clear existing since specified date', () => { 156 | // Set cache 157 | cacheService.setCacheData('/hoho', null, 'data'); 158 | expect(cacheService.getCacheData('/hoho')).toBe('data'); 159 | 160 | // Clean cache 161 | cacheService.cleanCache(new Date()); 162 | expect(cacheService.getCacheData('/hoho', null)).toBe(null); 163 | }); 164 | 165 | it('should not affect cache entries newer than specified date', () => { 166 | // Set cache 167 | cacheService.setCacheData('/hoho', null, 'data'); 168 | expect(cacheService.getCacheData('/hoho')).toBe('data'); 169 | 170 | // Clean cache 171 | let date = new Date(); 172 | cacheService.setCacheData('/lolo', null, 'data', new Date(date.getTime() + 10)); 173 | cacheService.cleanCache(date); 174 | 175 | // Assert 176 | expect(cacheService.getCacheData('/hoho', null)).toBe(null); 177 | expect(cacheService.getCacheData('/lolo', null)).toBe('data'); 178 | }); 179 | 180 | }); 181 | 182 | describe('setPersistence', () => { 183 | 184 | beforeEach(() => { 185 | cacheService.setPersistence(); 186 | cacheService.cleanCache = jasmine.createSpy('cleanCache'); 187 | }); 188 | 189 | it('should clear previous cache data when persistence value change', () => { 190 | cacheService.setPersistence('local'); 191 | expect(cacheService.cleanCache).toHaveBeenCalledWith(); 192 | }); 193 | 194 | it('should persist cache to local storage', () => { 195 | expect(window.localStorage.getItem('cachedData')).toBeNull(); 196 | 197 | cacheService.setPersistence('local'); 198 | cacheService.setCacheData('/hoho', null, 'data'); 199 | 200 | expect(window.localStorage.getItem('cachedData')).not.toBeNull(); 201 | }); 202 | 203 | it('should persist cache to session storage', () => { 204 | expect(window.sessionStorage.getItem('cachedData')).toBeNull(); 205 | 206 | cacheService.setPersistence('session'); 207 | cacheService.setCacheData('/hoho', null, 'data'); 208 | 209 | expect(window.sessionStorage.getItem('cachedData')).not.toBeNull(); 210 | }); 211 | 212 | }); 213 | 214 | }); 215 | -------------------------------------------------------------------------------- /generators/app/templates/_README.md: -------------------------------------------------------------------------------- 1 | # <%= props.appName || 'Awesome App' %> 2 | 3 | An awesome project scaffolded by the [angular-pro](https://github.com/angular-starter-kit/generator-angular-pro) Yeoman generator! 4 | 5 | # Getting started 6 | 7 | 1. Install required tools `gulp` and `bower`: 8 | ``` 9 | npm install -g gulp bower 10 | ``` 11 | 12 | 2. Install project tools, go to project folder: 13 | ``` 14 | npm install 15 | ``` 16 | <% if (props.target !== 'web') { -%> 17 | 18 | - To build the iOS version, you need to install [XCode](https://itunes.apple.com/app/xcode/id497799835) 19 | - To build the Android version, you need to install the 20 | [Android SDK](http://developer.android.com/sdk/installing/index.html) 21 | <% } -%> 22 | 23 | 3. Launch development server: 24 | ``` 25 | gulp serve 26 | ``` 27 | <% if (props.target !== 'web') { -%> 28 | 29 | 4. Prepare Cordova platforms and plugins 30 | ``` 31 | gulp cordova:prepare 32 | ``` 33 | 34 | 5. Run on device 35 | ``` 36 | gulp run: --device 37 | ``` 38 | <% } -%> 39 | 40 | # Project structure 41 | ``` 42 | gulp/ individual gulp tasks 43 | sources/ project source code 44 | |- data/ other project data, will be copied as-is 45 | |- fonts/ project fonts 46 | |- images/ project images 47 | |- libraries/ Bower dependencies 48 | |- main/ app components 49 | | |- main.config.ts app configuration code 50 | | |- main.constants.ts app configuration constants 51 | | |- main.module.ts app module definition 52 | | |- main.routes.ts app routes 53 | | |- main.run.ts app entry point 54 | | |- main.wrappers.ts AngularJS module wrappers for external libraries 55 | | |- main.scss style entry point 56 | | |- helpers/ helper services 57 | | |- screens/ application screens 58 | | |- shell/ application shell 59 | | |- ui-components/ shared UI components 60 | | |- web-services/ web services 61 | | +- ... additional components 62 | |- translations/ translations files 63 | +- index.html html entry point 64 | e2e/ end-to-end tests 65 | <% if (props.target === 'web') { -%> 66 | dist/ compiled version 67 | <% } else { -%> 68 | www/ compiled version 69 | <% } -%> 70 | typings/ TypeScript definitions 71 | reports/ test and coverage reports 72 | <% if (props.target !== 'web') { -%> 73 | hooks/ Cordova build hooks 74 | platforms/ Cordova platform-specific projects 75 | plugins/ Cordova plugins 76 | resources/ icon and splash screen resources 77 | <% } -%> 78 | gulpfile.config.js gulp tasks configuration 79 | ``` 80 | 81 | # Main gulp tasks 82 | 83 | Tasks | Description 84 | ------------|------------------------------------------------------------------------------- 85 | default | run `clean`, then `build` 86 | serve | Launch a web server with live reload and API proxy, then open app in browser. 87 | serve:dist | Launch a web server using dist files. 88 | build | Build and optimize the current project, ready for deployment. This includes linting as well as image, script, stylesheet and HTML optimization and minification. 89 | clean | Delete temporary files and dist files. 90 | test | Launch unit tests using karma and jasmine. 91 | test:auto | Launch karma server and launch unit tests after each change in project files. 92 | protractor | Launch e2e tests using protractor. 93 | tsd | Download and update all TypeScript definitions for Bower dependencies. 94 | 95 | When building the application, you can specify the target environment using the flag `--environment `. 96 | 97 | The default build environment is `production`. See [this documentation](docs/build-environments.md) for more details 98 | about multiple build environments management. 99 | 100 | You can disable opening automatically your default browser when using the `serve` commands by using the flag 101 | `--skip-open`. 102 | 103 | # Coding guides 104 | 105 | - [JavaScript](docs/coding-guides/javascript.md) 106 | - [TypeScript](docs/coding-guides/typescript.md) 107 | - [CSS](docs/coding-guides/css.md) 108 | - [HTML](docs/coding-guides/html.md) 109 | - [Unit tests](docs/coding-guides/unit-tests.md) 110 | - [End-to-end tests](docs/coding-guides/e2e-tests.md) 111 | 112 | # Additional documentation 113 | 114 | <% if (props.target !== 'web') { -%> 115 | - [Cordova](docs/cordova.md) 116 | <% } -%> 117 | - [Build environments](docs/build-environments.md) 118 | - [i18n](docs/i18n.md) 119 | - [Proxy configuration](docs/proxy.md) 120 | - [All gulp tasks](docs/tasks.md) 121 | - [Updating dependencies](docs/updating.md) 122 | 123 | # Features 124 | 125 | #### Languages 126 | - [TypeScript](http://www.typescriptlang.org), JavaScript 127 | - [Sass](http://sass-lang.com/), CSS 128 | - [Gettext](https://angular-gettext.rocketeer.be) (for translations) 129 | 130 | #### Quality 131 | - [TSLint](https://github.com/palantir/tslint) 132 | - [HTMLHint](http://htmlhint.com) 133 | - Unit tests ([Jasmine](http://jasmine.github.io)) 134 | - End-to-end tests ([Protractor](https://github.com/angular/protractor)) 135 | 136 | #### Development 137 | - Automation with [gulp](http://gulpjs.com) 138 | - [Webpack](https://webpack.github.io) build 139 | - Development server with API proxy and live reload ([BrowserSync](http://www.browsersync.io)) 140 | 141 | #### Build 142 | - JS+CSS+HTML bundling and minification ([useref](https://github.com/jonkemp/gulp-useref), 143 | [uglify](https://github.com/terinjokes/gulp-uglify), 144 | [html-minify](https://github.com/bestander/html-minify-loader), 145 | [clean-css](https://www.npmjs.com/package/gulp-clean-css) 146 | - CSS browser support ([autoprefixer](https://github.com/sindresorhus/gulp-autoprefixer)) 147 | - Images optimization ([imagemin](https://github.com/sindresorhus/gulp-imagemin)) 148 | - Automatic angular module annotation ([ngAnnotate](https://www.npmjs.com/package/ng-annotate-loader)) 149 | - Asset revisionning ([rev](https://github.com/sindresorhus/gulp-rev)) 150 | 151 | #### Libraries 152 | - [AngularJS](https://angularjs.org) 153 | - [Angular-gettext](https://angular-gettext.rocketeer.be) 154 | - [AngularUI Router](https://github.com/angular-ui/ui-router) 155 | <% if (props.ui === 'bootstrap') { -%> 156 | - [UI Bootsrap](https://angular-ui.github.io/bootstrap) 157 | - [Bootstrap](http://getbootstrap.com) 158 | - [Font Awesome](http://fortawesome.github.io/Font-Awesome) 159 | <% } else if (props.ui === 'ionic') { -%> 160 | - [Ionic](http://ionicframework.com/) 161 | <% } -%> 162 | - [Lodash](https://lodash.com) 163 | <% if (props.target !== 'web') { -%> 164 | - [ngCordova](http://ngcordova.com/) 165 | 166 | #### Cordova plugins 167 | - [ionic-plugin-keyboard](https://github.com/driftyco/ionic-plugin-keyboard) 168 | - [cordova-plugin-statusbar](https://github.com/apache/cordova-plugin-statusbar) 169 | - [cordova-plugin-device](https://github.com/apache/cordova-plugin-device) 170 | - [cordova-plugin-splashscreen](https://github.com/apache/cordova-plugin-splashscreen) 171 | - [cordova-plugin-globalization](https://github.com/apache/cordova-plugin-globalization) 172 | - [cordova-plugin-whitelist](https://github.com/apache/cordova-plugin-whitelist) 173 | - [cordova-plugin-crosswalk-webview](https://github.com/crosswalk-project/cordova-plugin-crosswalk-webview) 174 | - [cordova-plugin-wkwebview-engine](https://github.com/apache/cordova-plugin-wkwebview-engine) 175 | <% } -%> 176 | --------------------------------------------------------------------------------