├── EOL04 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ └── model │ │ │ └── recipe.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL07 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL08.0 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL08 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL09 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── misc │ │ │ ├── highlightnewrecipe.directive.ts │ │ │ └── swearing.pipe.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL10.1 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── misc │ │ │ ├── highlightnewrecipe.directive.ts │ │ │ └── swearing.pipe.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL10.2 └── rapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── edit-new-recipe │ │ │ │ ├── edit-new-recipe.component.css │ │ │ │ ├── edit-new-recipe.component.html │ │ │ │ ├── edit-new-recipe.component.spec.ts │ │ │ │ └── edit-new-recipe.component.ts │ │ │ ├── recipe-detals │ │ │ │ ├── recipe-detals.component.css │ │ │ │ ├── recipe-detals.component.html │ │ │ │ ├── recipe-detals.component.spec.ts │ │ │ │ └── recipe-detals.component.ts │ │ │ ├── recipe-list │ │ │ │ ├── recipe-list.component.css │ │ │ │ ├── recipe-list.component.html │ │ │ │ ├── recipe-list.component.spec.ts │ │ │ │ └── recipe-list.component.ts │ │ │ └── recipe-summary │ │ │ │ ├── recipe-summary.component.css │ │ │ │ ├── recipe-summary.component.html │ │ │ │ ├── recipe-summary.component.spec.ts │ │ │ │ └── recipe-summary.component.ts │ │ ├── misc │ │ │ ├── highlightnewrecipe.directive.ts │ │ │ └── swearing.pipe.ts │ │ ├── model │ │ │ └── recipe.ts │ │ └── services │ │ │ ├── recipe.service.spec.ts │ │ │ └── recipe.service.ts │ ├── assets │ │ └── emptybowl.jpg │ ├── bootstrap.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── EOL11 └── testingapp │ ├── .editorconfig │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json │ ├── karma.conf.js │ ├── package.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── message │ │ │ ├── message.component.css │ │ │ ├── message.component.html │ │ │ ├── message.component.spec.ts │ │ │ └── message.component.ts │ │ ├── recipe.service.ts │ │ └── recipe.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json └── README.md /EOL04/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL04/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL04/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL04/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL04/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL04/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL04/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL04/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL04/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL04/rapp/src/app/app.component.css -------------------------------------------------------------------------------- /EOL04/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { RecipeListComponent } from './components/recipe-list/recipe-list.component'; 6 | import { RecipeSummaryComponent } from './components/recipe-summary/recipe-summary.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent, 11 | RecipeListComponent, 12 | RecipeSummaryComponent, 13 | ], 14 | imports: [ 15 | BrowserModule 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule { } 21 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | h2.title { 2 | font-size: 150%; 3 | margin-bottom: 30px; 4 | } 5 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

These are the recipes available:

2 | 3 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-list', 6 | templateUrl: './recipe-list.component.html', 7 | styleUrls: ['./recipe-list.component.css'] 8 | }) 9 | export class RecipeListComponent { 10 | 11 | recipes: Recipe[]; 12 | 13 | constructor() { 14 | this.recipes = [ 15 | new Recipe('Banana bread', 16 | 'This is very delicious banana bread that we used to make back home when I was a child.', 17 | 4, 60, null, null, null), 18 | new Recipe('Farmstead tofu', 19 | 'A very spicy tofu dish from Hunan province with spicy peppers, some meat, and all sorts of yummy sauce', 20 | 2, 15, null, null, null), 21 | new Recipe('Spaghetti Carbonara', 22 | 'Delicious cheese, eggs, and spaghetti -- preparation can be tricky though, so be sure to practice!', 23 | 2, 25, null, null, null) 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe { 13 | float: left; 14 | margin-right: 10px; 15 | margin-bottom: 10px; 16 | width: 600px; 17 | } 18 | 19 | div.recipe h4 { 20 | font-size: 120% 21 | } 22 | 23 | div.recipe p { 24 | margin: 10px 20px; 25 | } 26 | 27 | @media only screen 28 | and (min-device-width: 768px) 29 | and (max-device-width: 1024px) and (orientation: portrait) { 30 | div.recipe { 31 | float: none; 32 | width: 100%; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ recipe.title }}

3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
-------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent implements OnInit { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | constructor() { } 15 | 16 | ngOnInit() { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /EOL04/rapp/src/app/model/recipe.ts: -------------------------------------------------------------------------------- 1 | export interface Ingredient { 2 | ingredient: string; 3 | measure: string; 4 | } 5 | 6 | export interface Instruction { 7 | instruction: string; 8 | photo: string; 9 | } 10 | 11 | export class Recipe { 12 | public title: string; 13 | public description: string; 14 | public feeds_this_many: number; // ppl 15 | public preparation_time: number; // minutes 16 | public ingredients: Ingredient[]; 17 | public instructions: Instruction[]; 18 | public cover_photo: string; 19 | 20 | constructor(t: string, d: string, ftm: number, pt: number, ing: Ingredient[], ins: Instruction[], cp: string) { 21 | this.title = t; 22 | this.description = d; 23 | this.feeds_this_many = ftm; 24 | this.preparation_time = pt; 25 | this.ingredients = ing; 26 | this.instructions = ins; 27 | this.cover_photo = cp; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /EOL04/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL04/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL04/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL04/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL04/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL04/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL04/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL04/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL04/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 10px; 3 | } -------------------------------------------------------------------------------- /EOL04/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL04/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL04/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL04/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL07/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL07/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL07/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL07/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL07/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL07/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL07/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL07/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL07/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL07/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL07/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | } 10 | 11 | div.newrecipe { 12 | width: 600px; 13 | } 14 | 15 | div.newrecipe textarea { 16 | margin-bottom: 10px; 17 | } 18 | 19 | div.input-group { 20 | margin-bottom: 10px; 21 | } 22 | 23 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 24 | color: white; 25 | } 26 | div.newrecipe div.add-form-button-holder { 27 | margin-top: 30px; 28 | } 29 | 30 | 31 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 32 | border-left: 5px solid #a94442; 33 | } 34 | 35 | input.ng-valid, textarea.ng-valid { 36 | border-left: 5px solid #42a948; 37 | } 38 | 39 | 40 | @media only screen 41 | and (min-device-width: 768px) 42 | and (max-device-width: 1024px) and (orientation: portrait) { 43 | div.cover-photo-holder { 44 | float: none; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 250px; 8 | height: 250px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe h4 { 13 | font-size: 120%; 14 | margin: 30px 0; 15 | } 16 | 17 | div.recipe p { 18 | margin-bottom: 10px; 19 | } 20 | 21 | div.recipe div.sub-title { 22 | float: left; 23 | font-weight: bold; 24 | width: 150px; 25 | } 26 | 27 | div.ingredients li, div.instructions li { 28 | padding: 2px 0; 29 | } 30 | 31 | div.ingredients { 32 | border: 1pxsolid #cccccc; 33 | background-color: #eeeeee; 34 | float: left; 35 | max-width: 350px; 36 | margin: 20px 0; 37 | padding: 5px; 38 | } 39 | 40 | div.ingredients span.measure { 41 | color: grey; 42 | } 43 | 44 | div.instructions { 45 | float: left; 46 | max-width: 400px; 47 | margin: 20px 0; 48 | padding: 5px 10px; 49 | } 50 | 51 | @media only screen 52 | and (min-device-width: 768px) 53 | and (max-device-width: 1024px) and (orientation: portrait) { 54 | div.recipe { 55 | float: none; 56 | width: 100%; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-detals/recipe-detals.component.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | Your Recipe is still loading... 4 |

5 | 6 |

7 | There was a problem loading your recipe: {{ load_error.error }} 8 |

9 |
10 |

{{ recipe.title }}

11 |
12 | 13 |
14 |

{{ recipe.description }}

15 |
16 |
Preparation Time:
17 |
{{ recipe.preparation_time }}
18 |
Feeds this Many:
19 |
{{ recipe.feeds_this_many }}
20 |
21 | 22 |
23 |

Ingredients

24 |
    25 |
  • 26 | {{ ingredient.ingredient }} ({{ ingredient.measure }}) 27 |
  • 28 |
29 |
30 |
31 |

Preparation Instructions

32 |
    33 |
  1. 34 | {{ instruction.instruction }} 35 |
  2. 36 |
37 |
38 | 39 |
-------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe { 13 | cursor: pointer; 14 | float: left; 15 | margin-right: 10px; 16 | margin-bottom: 10px; 17 | width: 600px; 18 | } 19 | 20 | div.recipe h4 { 21 | font-size: 120% 22 | } 23 | 24 | div.recipe p { 25 | margin-bottom: 10px; 26 | } 27 | 28 | div.recipe div.sub-title { 29 | float: left; 30 | font-weight: bold; 31 | width: 150px; 32 | } 33 | 34 | @media only screen 35 | and (min-device-width: 768px) 36 | and (max-device-width: 1024px) and (orientation: portrait) { 37 | div.recipe { 38 | float: none; 39 | width: 100%; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /EOL07/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL07/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL07/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL07/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL07/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL07/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL07/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL07/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL07/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL07/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL07/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL07/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL07/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL07/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL08.0/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL08.0/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL08.0/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL08.0/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL08.0/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL08.0/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL08.0/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL08.0/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL08.0/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^8.2.10", 15 | "@angular/common": "^8.2.10", 16 | "@angular/compiler": "^8.2.10", 17 | "@angular/core": "^8.2.10", 18 | "@angular/forms": "^8.2.10", 19 | "@angular/platform-browser": "^8.2.10", 20 | "@angular/platform-browser-dynamic": "^8.2.10", 21 | "@angular/router": "^8.2.10", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "^8.2.10", 30 | "@angular/language-service": "^8.2.10", 31 | "@types/jasmine": "~3.3.8", 32 | "@types/jasminewd2": "^2.0.8", 33 | "@types/node": "~8.9.4", 34 | "codelyzer": "^5.1.2", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL08.0/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | } 10 | 11 | div.newrecipe { 12 | width: 600px; 13 | } 14 | 15 | div.newrecipe textarea { 16 | margin-bottom: 10px; 17 | } 18 | 19 | div.input-group { 20 | margin-bottom: 10px; 21 | } 22 | 23 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 24 | color: white; 25 | } 26 | div.newrecipe div.add-form-button-holder { 27 | margin-top: 30px; 28 | } 29 | 30 | 31 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 32 | border-left: 5px solid #a94442; 33 | } 34 | 35 | input.ng-valid, textarea.ng-valid { 36 | border-left: 5px solid #42a948; 37 | } 38 | 39 | 40 | @media only screen 41 | and (min-device-width: 768px) 42 | and (max-device-width: 1024px) and (orientation: portrait) { 43 | div.cover-photo-holder { 44 | float: none; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 250px; 8 | height: 250px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe h4 { 13 | font-size: 120%; 14 | margin: 30px 0; 15 | } 16 | 17 | div.recipe p { 18 | margin-bottom: 10px; 19 | } 20 | 21 | div.recipe div.sub-title { 22 | float: left; 23 | font-weight: bold; 24 | width: 150px; 25 | } 26 | 27 | div.ingredients li, div.instructions li { 28 | padding: 2px 0; 29 | } 30 | 31 | div.ingredients { 32 | border: 1pxsolid #cccccc; 33 | background-color: #eeeeee; 34 | float: left; 35 | max-width: 350px; 36 | margin: 20px 0; 37 | padding: 5px; 38 | } 39 | 40 | div.ingredients span.measure { 41 | color: grey; 42 | } 43 | 44 | div.instructions { 45 | float: left; 46 | max-width: 400px; 47 | margin: 20px 0; 48 | padding: 5px 10px; 49 | } 50 | 51 | @media only screen 52 | and (min-device-width: 768px) 53 | and (max-device-width: 1024px) and (orientation: portrait) { 54 | div.recipe { 55 | float: none; 56 | width: 100%; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-detals/recipe-detals.component.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | Your Recipe is still loading... 4 |

5 | 6 |

7 | There was a problem loading your recipe: {{ load_error.error }} 8 |

9 |
10 |

{{ recipe.title }}

11 |
12 | 13 |
14 |

{{ recipe.description }}

15 |
16 |
Preparation Time:
17 |
{{ recipe.preparation_time }}
18 |
Feeds this Many:
19 |
{{ recipe.feeds_this_many }}
20 |
21 | 22 |
23 |

Ingredients

24 |
    25 |
  • 26 | {{ ingredient.ingredient }} ({{ ingredient.measure }}) 27 |
  • 28 |
29 |
30 |
31 |

Preparation Instructions

32 |
    33 |
  1. 34 | {{ instruction.instruction }} 35 |
  2. 36 |
37 |
38 | 39 |
-------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe { 13 | cursor: pointer; 14 | float: left; 15 | margin-right: 10px; 16 | margin-bottom: 10px; 17 | width: 600px; 18 | } 19 | 20 | div.recipe h4 { 21 | font-size: 120% 22 | } 23 | 24 | div.recipe p { 25 | margin-bottom: 10px; 26 | } 27 | 28 | div.recipe div.sub-title { 29 | float: left; 30 | font-weight: bold; 31 | width: 150px; 32 | } 33 | 34 | @media only screen 35 | and (min-device-width: 768px) 36 | and (max-device-width: 1024px) and (orientation: portrait) { 37 | div.recipe { 38 | float: none; 39 | width: 100%; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL08.0/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL08.0/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL08.0/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL08.0/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL08.0/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL08.0/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL08.0/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL08.0/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL08.0/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL08/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL08/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL08/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL08/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL08/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL08/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL08/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL08/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL08/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL08/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL08/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | object-fit: cover; 10 | } 11 | 12 | div.instruction img { 13 | float: right; 14 | width: 100px; 15 | height: 100px; 16 | object-fit: cover; 17 | border-radius: 8px; 18 | } 19 | 20 | 21 | div.newrecipe { 22 | width: 600px; 23 | } 24 | 25 | div.newrecipe textarea { 26 | margin-bottom: 10px; 27 | } 28 | 29 | div.input-group { 30 | margin-bottom: 10px; 31 | } 32 | 33 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 34 | color: white; 35 | } 36 | div.newrecipe div.add-form-button-holder { 37 | margin-top: 30px; 38 | } 39 | 40 | 41 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 42 | border-left: 5px solid #a94442; 43 | } 44 | 45 | input.ng-valid, textarea.ng-valid { 46 | border-left: 5px solid #42a948; 47 | } 48 | 49 | 50 | @media only screen 51 | and (min-device-width: 768px) 52 | and (max-device-width: 1024px) and (orientation: portrait) { 53 | div.cover-photo-holder { 54 | float: none; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 250px; 8 | height: 250px; 9 | margin: 5px; 10 | object-fit: cover; 11 | } 12 | 13 | div.recipe h4 { 14 | font-size: 120%; 15 | margin: 30px 0; 16 | } 17 | 18 | div.recipe p { 19 | margin-bottom: 10px; 20 | } 21 | 22 | div.recipe div.sub-title { 23 | float: left; 24 | font-weight: bold; 25 | width: 150px; 26 | } 27 | 28 | div.ingredients li, div.instructions li { 29 | padding: 2px 0; 30 | } 31 | 32 | div.ingredients { 33 | border: 1pxsolid #cccccc; 34 | background-color: #eeeeee; 35 | float: left; 36 | max-width: 350px; 37 | margin: 20px 0; 38 | padding: 5px; 39 | } 40 | 41 | div.ingredients span.measure { 42 | color: grey; 43 | } 44 | 45 | div.instructions { 46 | float: left; 47 | max-width: 400px; 48 | margin: 20px 0; 49 | padding: 5px 10px; 50 | } 51 | 52 | div.instructions img { 53 | float: right; 54 | width: 100px; 55 | height: 100px; 56 | object-fit: cover; 57 | border-radius: 8px; 58 | } 59 | 60 | 61 | @media only screen 62 | and (min-device-width: 768px) 63 | and (max-device-width: 1024px) and (orientation: portrait) { 64 | div.recipe { 65 | float: none; 66 | width: 100%; 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | } 11 | 12 | div.recipe { 13 | cursor: pointer; 14 | float: left; 15 | margin-right: 10px; 16 | margin-bottom: 10px; 17 | width: 600px; 18 | } 19 | 20 | div.recipe h4 { 21 | font-size: 120% 22 | } 23 | 24 | div.recipe p { 25 | margin-bottom: 10px; 26 | } 27 | 28 | div.recipe div.sub-title { 29 | float: left; 30 | font-weight: bold; 31 | width: 150px; 32 | } 33 | 34 | @media only screen 35 | and (min-device-width: 768px) 36 | and (max-device-width: 1024px) and (orientation: portrait) { 37 | div.recipe { 38 | float: none; 39 | width: 100%; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | imagePath(): string { 24 | return this.recipe.cover_photo 25 | ? 'http://localhost:8080/images/' + this.recipe.cover_photo 26 | : '/assets/emptybowl.jpg'; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /EOL08/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL08/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL08/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL08/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL08/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL08/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL08/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL08/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL08/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL08/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL08/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL08/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL08/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL08/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL09/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL09/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL09/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL09/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL09/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL09/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL09/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL09/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL09/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL09/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | }, 7 | "/images/*": { 8 | "target": "http://localhost:8080", 9 | "secure": false, 10 | "logLevel": "debug" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL09/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | border-radius: 5px; 10 | object-fit: cover; 11 | } 12 | 13 | div.instruction img { 14 | width: 100px; 15 | height: 100px; 16 | margin: 5px; 17 | border-radius: 5px; 18 | object-fit: cover; 19 | float: right; 20 | } 21 | 22 | 23 | div.newrecipe { 24 | width: 600px; 25 | } 26 | 27 | div.newrecipe textarea { 28 | margin-bottom: 10px; 29 | } 30 | 31 | div.input-group { 32 | margin-bottom: 10px; 33 | } 34 | 35 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 36 | color: white; 37 | } 38 | div.newrecipe div.add-form-button-holder { 39 | margin-top: 30px; 40 | } 41 | 42 | 43 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 44 | border-left: 5px solid #a94442; 45 | } 46 | 47 | input.ng-valid, textarea.ng-valid { 48 | border-left: 5px solid #42a948; 49 | } 50 | 51 | 52 | @media only screen 53 | and (min-device-width: 768px) 54 | and (max-device-width: 1024px) and (orientation: portrait) { 55 | div.cover-photo-holder { 56 | float: none; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 250px; 8 | height: 250px; 9 | margin: 5px; 10 | object-fit: cover; 11 | border-radius: 5px; 12 | } 13 | 14 | li.instruction img { 15 | width: 100px; 16 | height: 100px; 17 | margin: 5px; 18 | object-fit: cover; 19 | border-radius: 5px; 20 | float: right; 21 | } 22 | 23 | div.recipe h4 { 24 | font-size: 120%; 25 | margin: 30px 0; 26 | } 27 | 28 | div.recipe p { 29 | margin-bottom: 10px; 30 | } 31 | 32 | div.recipe div.sub-title { 33 | float: left; 34 | font-weight: bold; 35 | width: 150px; 36 | } 37 | 38 | div.ingredients li, div.instructions li { 39 | padding: 2px 0; 40 | } 41 | 42 | div.ingredients { 43 | border: 1pxsolid #cccccc; 44 | background-color: #eeeeee; 45 | float: left; 46 | max-width: 350px; 47 | margin: 20px 0; 48 | padding: 5px; 49 | } 50 | 51 | div.ingredients span.measure { 52 | color: grey; 53 | } 54 | 55 | div.instructions { 56 | float: left; 57 | width: 400px; 58 | margin: 20px 0; 59 | padding: 5px 10px; 60 | } 61 | 62 | @media only screen 63 | and (min-device-width: 768px) 64 | and (max-device-width: 1024px) and (orientation: portrait) { 65 | div.recipe { 66 | float: none; 67 | width: 100%; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | border-radius: 5px; 11 | object-fit: cover; 12 | } 13 | 14 | div.recipe { 15 | cursor: pointer; 16 | float: left; 17 | margin-right: 10px; 18 | margin-bottom: 10px; 19 | width: 600px; 20 | } 21 | 22 | div.recipe h4 { 23 | font-size: 120% 24 | } 25 | 26 | div.recipe p { 27 | margin-bottom: 10px; 28 | } 29 | 30 | div.recipe div.sub-title { 31 | float: left; 32 | font-weight: bold; 33 | width: 150px; 34 | } 35 | 36 | @media only screen 37 | and (min-device-width: 768px) 38 | and (max-device-width: 1024px) and (orientation: portrait) { 39 | div.recipe { 40 | float: none; 41 | width: 100%; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title | titlecase }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | imagePath(): string { 24 | console.log(this.recipe); 25 | 26 | if (this.recipe.cover_photo) { 27 | console.log(this.recipe.cover_photo); 28 | return 'http://localhost:4200/images/' + this.recipe.cover_photo; 29 | } else { 30 | return '/assets/emptybowl.jpg'; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/misc/highlightnewrecipe.directive.ts: -------------------------------------------------------------------------------- 1 | import { OnInit, Directive, ElementRef, Renderer, Input } from '@angular/core'; 2 | import { Recipe } from '../model/recipe'; 3 | 4 | @Directive({ selector: '[appHighlightNewRecipe]'}) 5 | export class HighlightNewRecipeDirective implements OnInit { 6 | 7 | @Input('appHighlightNewRecipe') 8 | recipe_to_test: Recipe; 9 | 10 | @Input('appHighlightNewRecipe_colour') 11 | highlight_color: string; 12 | 13 | constructor(private el: ElementRef, private renderer: Renderer) { 14 | 15 | this.highlight_color = 'yellow'; 16 | } 17 | 18 | ngOnInit() { 19 | console.log(this.recipe_to_test); 20 | const date_added = new Date(this.recipe_to_test.date_added).getTime(); 21 | if (new Date().getTime() - 4 * 86400000 < date_added) { 22 | this.renderer.setElementStyle(this.el.nativeElement, 'background-color', this.highlight_color); 23 | } 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/app/misc/swearing.pipe.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Pipe } from '@angular/core'; 2 | 3 | @Pipe({ name: 'noswearing' }) 4 | export class SwearingFilter implements PipeTransform { 5 | 6 | bad_words: string[] = [ 7 | 'poop', 8 | 'crap', 9 | 'darn', 10 | 'butt' 11 | ]; 12 | 13 | transform(value: string, replacement: string = '(oh dear!)'): string { 14 | for (const bad_word of this.bad_words) { 15 | value = value.replace(bad_word, replacement); 16 | } 17 | 18 | return value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /EOL09/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL09/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL09/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL09/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL09/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL09/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL09/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL09/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL09/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL09/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL09/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL09/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL09/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL09/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL10.1/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL10.1/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL10.1/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL10.1/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL10.1/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL10.1/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL10.1/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL10.1/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL10.1/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL10.1/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | }, 7 | "/images/*": { 8 | "target": "http://localhost:8080", 9 | "secure": false, 10 | "logLevel": "debug" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | border-radius: 5px; 10 | object-fit: cover; 11 | } 12 | 13 | div.instruction img { 14 | width: 100px; 15 | height: 100px; 16 | margin: 5px; 17 | border-radius: 5px; 18 | object-fit: cover; 19 | float: right; 20 | } 21 | 22 | 23 | div.newrecipe { 24 | width: 600px; 25 | } 26 | 27 | div.newrecipe textarea { 28 | margin-bottom: 10px; 29 | } 30 | 31 | div.input-group { 32 | margin-bottom: 10px; 33 | } 34 | 35 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 36 | color: white; 37 | } 38 | div.newrecipe div.add-form-button-holder { 39 | margin-top: 30px; 40 | } 41 | 42 | 43 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 44 | border-left: 5px solid #a94442; 45 | } 46 | 47 | input.ng-valid, textarea.ng-valid { 48 | border-left: 5px solid #42a948; 49 | } 50 | 51 | 52 | @media only screen 53 | and (min-device-width: 768px) 54 | and (max-device-width: 1024px) and (orientation: portrait) { 55 | div.cover-photo-holder { 56 | float: none; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 250px; 8 | height: 250px; 9 | margin: 5px; 10 | object-fit: cover; 11 | border-radius: 5px; 12 | } 13 | 14 | li.instruction img { 15 | width: 100px; 16 | height: 100px; 17 | margin: 5px; 18 | object-fit: cover; 19 | border-radius: 5px; 20 | float: right; 21 | } 22 | 23 | div.recipe h4 { 24 | font-size: 120%; 25 | margin: 30px 0; 26 | } 27 | 28 | div.recipe p { 29 | margin-bottom: 10px; 30 | } 31 | 32 | div.recipe div.sub-title { 33 | float: left; 34 | font-weight: bold; 35 | width: 150px; 36 | } 37 | 38 | div.ingredients li, div.instructions li { 39 | padding: 2px 0; 40 | } 41 | 42 | div.ingredients { 43 | border: 1pxsolid #cccccc; 44 | background-color: #eeeeee; 45 | float: left; 46 | max-width: 350px; 47 | margin: 20px 0; 48 | padding: 5px; 49 | } 50 | 51 | div.ingredients span.measure { 52 | color: grey; 53 | } 54 | 55 | div.instructions { 56 | float: left; 57 | width: 400px; 58 | margin: 20px 0; 59 | padding: 5px 10px; 60 | } 61 | 62 | @media only screen 63 | and (min-device-width: 768px) 64 | and (max-device-width: 1024px) and (orientation: portrait) { 65 | div.recipe { 66 | float: none; 67 | width: 100%; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | border-radius: 5px; 11 | object-fit: cover; 12 | } 13 | 14 | div.recipe { 15 | cursor: pointer; 16 | float: left; 17 | margin-right: 10px; 18 | margin-bottom: 10px; 19 | width: 600px; 20 | } 21 | 22 | div.recipe h4 { 23 | font-size: 120% 24 | } 25 | 26 | div.recipe p { 27 | margin-bottom: 10px; 28 | } 29 | 30 | div.recipe div.sub-title { 31 | float: left; 32 | font-weight: bold; 33 | width: 150px; 34 | } 35 | 36 | @media only screen 37 | and (min-device-width: 768px) 38 | and (max-device-width: 1024px) and (orientation: portrait) { 39 | div.recipe { 40 | float: none; 41 | width: 100%; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title | titlecase }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | imagePath(): string { 24 | console.log(this.recipe); 25 | 26 | if (this.recipe.cover_photo) { 27 | console.log(this.recipe.cover_photo); 28 | return 'http://localhost:4200/images/' + this.recipe.cover_photo; 29 | } else { 30 | return '/assets/emptybowl.jpg'; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/misc/highlightnewrecipe.directive.ts: -------------------------------------------------------------------------------- 1 | import { OnInit, Directive, ElementRef, Renderer, Input } from '@angular/core'; 2 | import { Recipe } from '../model/recipe'; 3 | 4 | @Directive({ selector: '[appHighlightNewRecipe]'}) 5 | export class HighlightNewRecipeDirective implements OnInit { 6 | 7 | @Input('appHighlightNewRecipe') 8 | recipe_to_test: Recipe; 9 | 10 | @Input('appHighlightNewRecipe_colour') 11 | highlight_color: string; 12 | 13 | constructor(private el: ElementRef, private renderer: Renderer) { 14 | this.highlight_color = 'yellow'; 15 | } 16 | 17 | ngOnInit() { 18 | console.log(this.recipe_to_test); 19 | const date_added = new Date(this.recipe_to_test.date_added).getTime(); 20 | if (new Date().getTime() - 4 * 86400000 < date_added) { 21 | this.renderer.setElementStyle(this.el.nativeElement, 'background-color', this.highlight_color); 22 | } 23 | 24 | } 25 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/misc/swearing.pipe.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Pipe } from '@angular/core'; 2 | 3 | @Pipe({ name: 'noswearing' }) 4 | export class SwearingFilter implements PipeTransform { 5 | 6 | bad_words: string[] = [ 7 | 'poop', 8 | 'crap', 9 | 'darn', 10 | 'butt' 11 | ]; 12 | 13 | transform(value: string, replacement: string = '(oh dear!)'): string { 14 | for (const bad_word of this.bad_words) { 15 | value = value.replace(bad_word, replacement); 16 | } 17 | 18 | return value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL10.1/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL10.1/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL10.1/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL10.1/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL10.1/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL10.1/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL10.1/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL10.1/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL10.1/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL10.2/rapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL10.2/rapp/README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL10.2/rapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL10.2/rapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL10.2/rapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to rapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL10.2/rapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL10.2/rapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL10.2/rapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/rapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL10.2/rapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.0", 15 | "@angular/common": "~8.2.0", 16 | "@angular/compiler": "~8.2.0", 17 | "@angular/core": "~8.2.0", 18 | "@angular/forms": "~8.2.0", 19 | "@angular/platform-browser": "~8.2.0", 20 | "@angular/platform-browser-dynamic": "~8.2.0", 21 | "@angular/router": "~8.2.0", 22 | "rxjs": "~6.4.0", 23 | "tslib": "^1.10.0", 24 | "zone.js": "~0.9.1" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "~0.802.2", 28 | "@angular/cli": "~8.2.2", 29 | "@angular/compiler-cli": "~8.2.0", 30 | "@angular/language-service": "~8.2.0", 31 | "@types/node": "~8.9.4", 32 | "@types/jasmine": "~3.3.8", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^5.0.0", 35 | "jasmine-core": "~3.4.0", 36 | "jasmine-spec-reporter": "~4.2.1", 37 | "karma": "~4.1.0", 38 | "karma-chrome-launcher": "~2.2.0", 39 | "karma-coverage-istanbul-reporter": "~2.0.1", 40 | "karma-jasmine": "~2.0.1", 41 | "karma-jasmine-html-reporter": "^1.4.0", 42 | "protractor": "~5.4.0", 43 | "ts-node": "~7.0.0", 44 | "tslint": "~5.15.0", 45 | "typescript": "~3.5.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EOL10.2/rapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/v1/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "logLevel": "debug" 6 | }, 7 | "/images/*": { 8 | "target": "http://localhost:8080", 9 | "secure": false, 10 | "logLevel": "debug" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Add a background color to the top navigation */ 2 | .topnav { 3 | background-color: #983C29; 4 | overflow: hidden; 5 | margin-bottom: 10px; 6 | } 7 | 8 | /* Style the links inside the navigation bar */ 9 | .topnav a { 10 | float: left; 11 | display: block; 12 | color: white; 13 | text-align: center; 14 | padding: 14px 16px; 15 | text-decoration: none; 16 | font-size: 17px; 17 | } 18 | 19 | /* Change the color of links on hover */ 20 | @media (min-width: 850px) { 21 | .topnav a:hover { 22 | background-color: white; 23 | color: #983C29; 24 | } 25 | } 26 | 27 | /* Add a color to the active/current link */ 28 | .topnav a.active { 29 | background-color: #4CAF50; 30 | color: white; 31 | } 32 | 33 | div#main_body { 34 | margin: 10px; 35 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 | New Recipe 4 |
5 | 6 |
7 | 8 |
-------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'rapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('rapp'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to rapp!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.css: -------------------------------------------------------------------------------- 1 | div.cover-photo-holder { 2 | float: right; 3 | } 4 | 5 | div.cover-photo-holder img { 6 | width: 250px; 7 | height: 250px; 8 | margin: 5px; 9 | border-radius: 5px; 10 | object-fit: cover; 11 | } 12 | 13 | div.instruction img { 14 | width: 100px; 15 | height: 100px; 16 | margin: 5px; 17 | border-radius: 5px; 18 | object-fit: cover; 19 | float: right; 20 | } 21 | 22 | 23 | div.newrecipe { 24 | width: 600px; 25 | } 26 | 27 | div.newrecipe textarea { 28 | margin-bottom: 10px; 29 | } 30 | 31 | div.input-group { 32 | margin-bottom: 10px; 33 | } 34 | 35 | div.newrecipe div.ingredient .btn-secondary, div.newrecipe div.instruction .btn-secondary { 36 | color: white; 37 | } 38 | div.newrecipe div.add-form-button-holder { 39 | margin-top: 30px; 40 | } 41 | 42 | 43 | input.ng-touched.ng-invalid, textarea.ng-touched.ng-invalid { 44 | border-left: 5px solid #a94442; 45 | } 46 | 47 | input.ng-valid, textarea.ng-valid { 48 | border-left: 5px solid #42a948; 49 | } 50 | 51 | 52 | @media only screen 53 | and (min-device-width: 768px) 54 | and (max-device-width: 1024px) and (orientation: portrait) { 55 | div.cover-photo-holder { 56 | float: none; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/edit-new-recipe/edit-new-recipe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditNewRecipeComponent } from './edit-new-recipe.component'; 4 | 5 | describe('EditNewRecipeComponent', () => { 6 | let component: EditNewRecipeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ EditNewRecipeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EditNewRecipeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-detals/recipe-detals.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | a, a:visited { color: blue; } 7 | 8 | div.cover-photo-holder img { 9 | width: 250px; 10 | height: 250px; 11 | margin: 5px; 12 | object-fit: cover; 13 | border-radius: 5px; 14 | } 15 | 16 | li.instruction img { 17 | width: 100px; 18 | height: 100px; 19 | margin: 5px; 20 | object-fit: cover; 21 | border-radius: 5px; 22 | float: right; 23 | } 24 | 25 | div.recipe h4 { 26 | font-size: 120%; 27 | margin: 30px 0; 28 | } 29 | 30 | div.recipe p { 31 | margin-bottom: 10px; 32 | } 33 | 34 | div.recipe div.sub-title { 35 | float: left; 36 | font-weight: bold; 37 | width: 150px; 38 | } 39 | 40 | div.ingredients li, div.instructions li { 41 | padding: 2px 0; 42 | } 43 | 44 | div.ingredients { 45 | border: 1pxsolid #cccccc; 46 | background-color: #eeeeee; 47 | float: left; 48 | max-width: 350px; 49 | margin: 20px 0; 50 | padding: 5px; 51 | } 52 | 53 | div.ingredients span.measure { 54 | color: grey; 55 | } 56 | 57 | div.instructions { 58 | float: left; 59 | width: 400px; 60 | margin: 20px 0; 61 | padding: 5px 10px; 62 | } 63 | 64 | @media only screen 65 | and (min-device-width: 768px) 66 | and (max-device-width: 1024px) and (orientation: portrait) { 67 | div.recipe { 68 | float: none; 69 | width: 100%; 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-detals/recipe-detals.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeDetalsComponent } from './recipe-detals.component'; 4 | 5 | describe('RecipeDetalsComponent', () => { 6 | let component: RecipeDetalsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeDetalsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeDetalsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-list/recipe-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | h1 { 3 | font-size: 150%; 4 | padding: 15px 5px; 5 | margin-bottom: 15px; 6 | } 7 | 8 | .darkbg { 9 | background-color: #aaaaaa; 10 | } 11 | 12 | .fade_to_white { 13 | background-color: white; 14 | /* -webkit-transition: background-color 1000ms linear; 15 | -ms-transition: background-color 1000ms linear; 16 | transition: background-color 1000ms linear;*/ 17 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-list/recipe-list.component.html: -------------------------------------------------------------------------------- 1 |

This is a list of all available recipes

2 | 3 |

4 | Recipes are loading, please wait for a moment. 5 |

6 | 7 |

8 | There was a problem loading the recipe list from the server: {{ load_error.error }} 9 |

10 | 11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-list/recipe-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeListComponent } from './recipe-list.component'; 4 | 5 | describe('RecipeListComponent', () => { 6 | let component: RecipeListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-list/recipe-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { Recipe } from 'src/app/model/recipe'; 5 | import { RecipeService } from '../../services/recipe.service'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-recipe-list', 10 | templateUrl: './recipe-list.component.html', 11 | styleUrls: ['./recipe-list.component.css'] 12 | }) 13 | export class RecipeListComponent implements OnInit { 14 | 15 | recipes_loaded: boolean; 16 | load_error: object; 17 | recipes: Recipe[]; 18 | 19 | constructor(private router: Router, 20 | private recipe_service: RecipeService) { } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getAllRecipes() 24 | .subscribe( 25 | (recipepayload) => { 26 | this.recipes = recipepayload.data; 27 | this.recipes_loaded = true; 28 | console.log(recipepayload.error); 29 | }, 30 | (error) => { 31 | this.load_error = error; 32 | console.log(JSON.stringify(error, null, 2)); 33 | } 34 | ); 35 | } 36 | 37 | recipeClicked(recipe_id): void { 38 | this.router.navigateByUrl('/recipes/' + recipe_id); 39 | } 40 | 41 | addNewRecipeClicked(): void { 42 | this.router.navigateByUrl('/editnewrecipe'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-summary/recipe-summary.component.css: -------------------------------------------------------------------------------- 1 | 2 | div.cover-photo-holder { 3 | float: right; 4 | } 5 | 6 | div.cover-photo-holder img { 7 | width: 150px; 8 | height: 150px; 9 | margin: 5px; 10 | border-radius: 5px; 11 | object-fit: cover; 12 | } 13 | 14 | div.recipe { 15 | cursor: pointer; 16 | float: left; 17 | margin-right: 10px; 18 | margin-bottom: 10px; 19 | width: 600px; 20 | } 21 | 22 | div.recipe h4 { 23 | font-size: 120% 24 | } 25 | 26 | div.recipe p { 27 | margin-bottom: 10px; 28 | } 29 | 30 | div.recipe div.sub-title { 31 | float: left; 32 | font-weight: bold; 33 | width: 150px; 34 | } 35 | 36 | @media only screen 37 | and (min-device-width: 768px) 38 | and (max-device-width: 1024px) and (orientation: portrait) { 39 | div.recipe { 40 | float: none; 41 | width: 100%; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-summary/recipe-summary.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ recipe.title | titlecase }}
3 |
4 |
5 | 6 |
7 |

{{ recipe.description }}

8 |
9 |
Preparation Time:
10 |
{{ recipe.preparation_time }}
11 |
Feeds this Many:
12 |
{{ recipe.feeds_this_many }}
13 |
14 |
15 |
-------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-summary/recipe-summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeSummaryComponent } from './recipe-summary.component'; 4 | 5 | describe('RecipeSummaryComponent', () => { 6 | let component: RecipeSummaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RecipeSummaryComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RecipeSummaryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/components/recipe-summary/recipe-summary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { Recipe } from 'src/app/model/recipe'; 3 | 4 | @Component({ 5 | selector: 'app-recipe-summary', 6 | templateUrl: './recipe-summary.component.html', 7 | styleUrls: ['./recipe-summary.component.css'] 8 | }) 9 | export class RecipeSummaryComponent { 10 | 11 | @Input() 12 | recipe: Recipe; 13 | 14 | @Output() 15 | recipeClicked: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { } 18 | 19 | userClickedOnRecipe(): void { 20 | this.recipeClicked.emit(this.recipe.id); 21 | } 22 | 23 | imagePath(): string { 24 | console.log(this.recipe); 25 | 26 | if (this.recipe.cover_photo) { 27 | console.log(this.recipe.cover_photo); 28 | return 'http://localhost:4200/images/' + this.recipe.cover_photo; 29 | } else { 30 | return '/assets/emptybowl.jpg'; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/misc/highlightnewrecipe.directive.ts: -------------------------------------------------------------------------------- 1 | import { OnInit, Directive, ElementRef, Renderer, Input } from '@angular/core'; 2 | import { Recipe } from '../model/recipe'; 3 | 4 | @Directive({ selector: '[appHighlightNewRecipe]'}) 5 | export class HighlightNewRecipeDirective implements OnInit { 6 | 7 | @Input('appHighlightNewRecipe') 8 | recipe_to_test: Recipe; 9 | 10 | @Input('appHighlightNewRecipe_colour') 11 | highlight_color: string; 12 | 13 | constructor(private el: ElementRef, private renderer: Renderer) { 14 | this.highlight_color = 'yellow'; 15 | } 16 | 17 | ngOnInit() { 18 | console.log(this.recipe_to_test); 19 | const date_added = new Date(this.recipe_to_test.date_added).getTime(); 20 | if (new Date().getTime() - 4 * 86400000 < date_added) { 21 | this.renderer.setElementStyle(this.el.nativeElement, 'background-color', this.highlight_color); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/misc/swearing.pipe.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Pipe } from '@angular/core'; 2 | 3 | @Pipe({ name: 'noswearing' }) 4 | export class SwearingFilter implements PipeTransform { 5 | 6 | bad_words: string[] = [ 7 | 'poop', 8 | 'crap', 9 | 'darn', 10 | 'butt' 11 | ]; 12 | 13 | transform(value: string, replacement: string = '(oh dear!)'): string { 14 | for (const bad_word of this.bad_words) { 15 | value = value.replace(bad_word, replacement); 16 | } 17 | 18 | return value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/app/services/recipe.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RecipeService } from './recipe.service'; 4 | 5 | describe('RecipeService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: RecipeService = TestBed.get(RecipeService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/assets/emptybowl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL10.2/rapp/src/assets/emptybowl.jpg -------------------------------------------------------------------------------- /EOL10.2/rapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL10.2/rapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL10.2/rapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL10.2/rapp/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } -------------------------------------------------------------------------------- /EOL10.2/rapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL10.2/rapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL10.2/rapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL10.2/rapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL11/testingapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /EOL11/testingapp/README.md: -------------------------------------------------------------------------------- 1 | # Testingapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /EOL11/testingapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /EOL11/testingapp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /EOL11/testingapp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to testingapp!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /EOL11/testingapp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EOL11/testingapp/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EOL11/testingapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/testingapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL11/testingapp/src/app/app.component.css -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | import { MessageComponent } from './message/message.component'; 4 | import { HttpClient } from '@angular/common/http'; 5 | import { RecipeService } from './recipe.service'; 6 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 7 | 8 | describe('AppComponent', () => { 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | imports: [ HttpClientTestingModule ], 12 | declarations: [ 13 | AppComponent, 14 | MessageComponent 15 | ], 16 | providers: [ RecipeService, HttpClient ] 17 | }).compileComponents(); 18 | })); 19 | 20 | it('should create the app', () => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app).toBeTruthy(); 24 | }); 25 | 26 | it(`should have as title 'testingapp'`, () => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | const app = fixture.debugElement.componentInstance; 29 | expect(app.title).toEqual('testingapp'); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'testingapp'; 10 | } 11 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { MessageComponent } from './message/message.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | AppComponent, 10 | MessageComponent 11 | ], 12 | imports: [ 13 | BrowserModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { } 19 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/message/message.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL11/testingapp/src/app/message/message.component.css -------------------------------------------------------------------------------- /EOL11/testingapp/src/app/message/message.component.html: -------------------------------------------------------------------------------- 1 |

2 | {{ message }} 3 |

4 | 5 | 6 |
7 | {{ letter }} 8 |
-------------------------------------------------------------------------------- /EOL11/testingapp/src/app/message/message.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Recipe, RecipePayload } from '../recipe'; 3 | import { RecipeService } from '../recipe.service'; 4 | 5 | @Component({ 6 | selector: 'app-message', 7 | templateUrl: './message.component.html', 8 | styleUrls: ['./message.component.css'] 9 | }) 10 | export class MessageComponent implements OnInit { 11 | 12 | message: string; 13 | 14 | recipe: Recipe; 15 | 16 | letters = [ 'a', 'b', 'c', 'd', 'e' ]; 17 | 18 | constructor(private recipe_service: RecipeService) { 19 | this.message = 'Hello there!'; 20 | } 21 | 22 | ngOnInit() { 23 | this.recipe_service.getRecipeById(5) 24 | .subscribe((recipepayload: RecipePayload) => this.recipe = recipepayload.data); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularLiveLessons/a2d3e180738e097d8f4a5638183c41344970e09d/EOL11/testingapp/src/favicon.ico -------------------------------------------------------------------------------- /EOL11/testingapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Testingapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /EOL11/testingapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /EOL11/testingapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /EOL11/testingapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /EOL11/testingapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AngularLiveLessons 2 | This is the source code to accompany the "Learning Angular LiveLessons". It 3 | covers Angular versions 8 and aove. If you are looking for the source to accompany 4 | "Learning AngularJS LiveLessons", please see the repo "LearningAngularJS". 5 | 6 | Some notes: 7 | 8 | * Lessons 4 and 5 are relatively simple, so I've just folded the code for those into Lesson 7 9 | * For Lesson 8, I've created two folders for the different types of forms (see the Lesson) 10 | 11 | If there are any bugs or problems with this source, please file a bug or—even 12 | better—a pull request, and I'll get to it as soon as I can. 13 | 14 | Thanks for watching, I really appreciate it. Please feel free to send me feedback. I'd like to know how I can make these better! 15 | --------------------------------------------------------------------------------