├── app-a ├── .angular-cli.json ├── .editorconfig ├── .gitignore ├── README.md ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src │ ├── app │ │ ├── a │ │ │ ├── a.component.css │ │ │ ├── a.component.html │ │ │ ├── a.component.spec.ts │ │ │ └── a.component.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ └── b │ │ │ ├── b.component.css │ │ │ ├── b.component.html │ │ │ ├── b.component.spec.ts │ │ │ └── b.component.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json ├── app-b ├── .angular-cli.json ├── .editorconfig ├── .gitignore ├── README.md ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json ├── child-app.js ├── index.css ├── index.html ├── polyfills.js ├── readme.md └── router.js /app-a/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "app-a" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "src/tsconfig.app.json", 40 | "exclude": "**/node_modules/**" 41 | }, 42 | { 43 | "project": "src/tsconfig.spec.json", 44 | "exclude": "**/node_modules/**" 45 | }, 46 | { 47 | "project": "e2e/tsconfig.e2e.json", 48 | "exclude": "**/node_modules/**" 49 | } 50 | ], 51 | "test": { 52 | "karma": { 53 | "config": "./karma.conf.js" 54 | } 55 | }, 56 | "defaults": { 57 | "styleExt": "css", 58 | "component": {} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app-a/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://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 | -------------------------------------------------------------------------------- /app-a/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /app-a/README.md: -------------------------------------------------------------------------------- 1 | # AppA 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.5.4. 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 | -------------------------------------------------------------------------------- /app-a/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('app-a App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /app-a/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app-a/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app-a/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/cli'], 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/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /app-a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-a", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "^5.0.0", 16 | "@angular/common": "^5.0.0", 17 | "@angular/compiler": "^5.0.0", 18 | "@angular/core": "^5.0.0", 19 | "@angular/forms": "^5.0.0", 20 | "@angular/http": "^5.0.0", 21 | "@angular/platform-browser": "^5.0.0", 22 | "@angular/platform-browser-dynamic": "^5.0.0", 23 | "@angular/router": "^5.0.0", 24 | "core-js": "^2.4.1", 25 | "rxjs": "^5.5.2", 26 | "zone.js": "^0.8.14" 27 | }, 28 | "devDependencies": { 29 | "@angular/cli": "1.5.4", 30 | "@angular/compiler-cli": "^5.0.0", 31 | "@angular/language-service": "^5.0.0", 32 | "@types/jasmine": "~2.5.53", 33 | "@types/jasminewd2": "~2.0.2", 34 | "@types/node": "~6.0.60", 35 | "codelyzer": "^4.0.1", 36 | "jasmine-core": "~2.6.2", 37 | "jasmine-spec-reporter": "~4.1.0", 38 | "karma": "~1.7.0", 39 | "karma-chrome-launcher": "~2.1.1", 40 | "karma-cli": "~1.0.1", 41 | "karma-coverage-istanbul-reporter": "^1.2.1", 42 | "karma-jasmine": "~1.1.0", 43 | "karma-jasmine-html-reporter": "^0.2.2", 44 | "protractor": "~5.1.2", 45 | "ts-node": "~3.2.0", 46 | "tslint": "~5.7.0", 47 | "typescript": "~2.4.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app-a/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /app-a/src/app/a/a.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-a/src/app/a/a.component.css -------------------------------------------------------------------------------- /app-a/src/app/a/a.component.html: -------------------------------------------------------------------------------- 1 |

2 | a works! 3 |

4 | -------------------------------------------------------------------------------- /app-a/src/app/a/a.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AComponent } from './a.component'; 4 | 5 | describe('AComponent', () => { 6 | let component: AComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /app-a/src/app/a/a.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-a', 5 | templateUrl: './a.component.html', 6 | styleUrls: ['./a.component.css'] 7 | }) 8 | export class AComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app-a/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-a/src/app/app.component.css -------------------------------------------------------------------------------- /app-a/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Welcome to A!

5 |
6 | A | 7 | B 8 |
9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quam, tenetur nulla explicabo corrupti iure delectus illum iusto aperiam rem est amet sapiente beatae soluta ipsa corporis accusantium nostrum vel blanditiis. 19 | Quisquam nam, vero obcaecati, magni quibusdam totam, nemo incidunt quidem laudantium natus doloremque praesentium neque? Dolorum cumque, totam similique quas nam aliquid quos ipsa provident necessitatibus aliquam accusantium, odio nemo! 20 | Nostrum itaque laborum ipsa natus dolore repellat atque, aliquam iusto aliquid est vitae ducimus eum ipsam fuga molestiae officia nam. Non, quaerat voluptatem. Cumque dignissimos nobis adipisci numquam quidem labore. 21 | Quisquam, dolores hic harum fuga assumenda perferendis libero est animi voluptas deleniti quam tenetur necessitatibus totam ipsa maiores temporibus. Eveniet ipsam perferendis voluptates praesentium consectetur quia id non repellat. Impedit? 22 | Doloribus tempora dolorem corrupti natus, asperiores sint excepturi dicta repellendus modi maiores quaerat culpa ut commodi quibusdam libero atque quod veritatis nulla? Tempore iste odit asperiores velit cumque perferendis repellat. 23 | Recusandae nisi accusantium sed quo illum est quasi dolores consequatur. Molestias, illum sequi? Neque modi saepe fugiat voluptate aliquid fugit doloremque numquam eligendi exercitationem, laboriosam accusamus porro eius velit laborum. 24 | Dignissimos eum consequatur eaque voluptatum voluptas! Nulla veritatis possimus eligendi maxime rem. Eos quam quasi impedit neque incidunt sapiente doloremque voluptatibus odio rem porro, accusantium illum eligendi at distinctio omnis! 25 | Dolorum odio necessitatibus iusto sint qui ratione, reiciendis aliquam assumenda eum est provident! Natus nam laudantium dolores dignissimos voluptatum quasi repellendus, ab quis facilis minima consequuntur a aliquid magnam nesciunt. 26 | Nam repellendus unde, beatae, inventore voluptatum tenetur ut deserunt architecto necessitatibus voluptatibus veritatis eos harum tempore totam ipsam temporibus eveniet accusantium cupiditate aperiam quas similique fuga optio nulla? Voluptatem, iure. 27 | Vel, enim ad. Quas aliquid, aspernatur tenetur itaque ipsa minima possimus iste blanditiis eaque repellat ad explicabo optio sunt, numquam cumque est accusantium? Architecto sed facere laboriosam ea, modi neque. 28 | 29 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quam, tenetur nulla explicabo corrupti iure delectus illum iusto aperiam rem est amet sapiente beatae soluta ipsa corporis accusantium nostrum vel blanditiis. 30 | Quisquam nam, vero obcaecati, magni quibusdam totam, nemo incidunt quidem laudantium natus doloremque praesentium neque? Dolorum cumque, totam similique quas nam aliquid quos ipsa provident necessitatibus aliquam accusantium, odio nemo! 31 | Nostrum itaque laborum ipsa natus dolore repellat atque, aliquam iusto aliquid est vitae ducimus eum ipsam fuga molestiae officia nam. Non, quaerat voluptatem. Cumque dignissimos nobis adipisci numquam quidem labore. 32 | Quisquam, dolores hic harum fuga assumenda perferendis libero est animi voluptas deleniti quam tenetur necessitatibus totam ipsa maiores temporibus. Eveniet ipsam perferendis voluptates praesentium consectetur quia id non repellat. Impedit? 33 | Doloribus tempora dolorem corrupti natus, asperiores sint excepturi dicta repellendus modi maiores quaerat culpa ut commodi quibusdam libero atque quod veritatis nulla? Tempore iste odit asperiores velit cumque perferendis repellat. 34 | Recusandae nisi accusantium sed quo illum est quasi dolores consequatur. Molestias, illum sequi? Neque modi saepe fugiat voluptate aliquid fugit doloremque numquam eligendi exercitationem, laboriosam accusamus porro eius velit laborum. 35 | Dignissimos eum consequatur eaque voluptatum voluptas! Nulla veritatis possimus eligendi maxime rem. Eos quam quasi impedit neque incidunt sapiente doloremque voluptatibus odio rem porro, accusantium illum eligendi at distinctio omnis! 36 | Dolorum odio necessitatibus iusto sint qui ratione, reiciendis aliquam assumenda eum est provident! Natus nam laudantium dolores dignissimos voluptatum quasi repellendus, ab quis facilis minima consequuntur a aliquid magnam nesciunt. 37 | Nam repellendus unde, beatae, inventore voluptatum tenetur ut deserunt architecto necessitatibus voluptatibus veritatis eos harum tempore totam ipsam temporibus eveniet accusantium cupiditate aperiam quas similique fuga optio nulla? Voluptatem, iure. 38 | Vel, enim ad. Quas aliquid, aspernatur tenetur itaque ipsa minima possimus iste blanditiis eaque repellat ad explicabo optio sunt, numquam cumque est accusantium? Architecto sed facere laboriosam ea, modi neque. 39 | 40 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quam, tenetur nulla explicabo corrupti iure delectus illum iusto aperiam rem est amet sapiente beatae soluta ipsa corporis accusantium nostrum vel blanditiis. 41 | Quisquam nam, vero obcaecati, magni quibusdam totam, nemo incidunt quidem laudantium natus doloremque praesentium neque? Dolorum cumque, totam similique quas nam aliquid quos ipsa provident necessitatibus aliquam accusantium, odio nemo! 42 | Nostrum itaque laborum ipsa natus dolore repellat atque, aliquam iusto aliquid est vitae ducimus eum ipsam fuga molestiae officia nam. Non, quaerat voluptatem. Cumque dignissimos nobis adipisci numquam quidem labore. 43 | Quisquam, dolores hic harum fuga assumenda perferendis libero est animi voluptas deleniti quam tenetur necessitatibus totam ipsa maiores temporibus. Eveniet ipsam perferendis voluptates praesentium consectetur quia id non repellat. Impedit? 44 | Doloribus tempora dolorem corrupti natus, asperiores sint excepturi dicta repellendus modi maiores quaerat culpa ut commodi quibusdam libero atque quod veritatis nulla? Tempore iste odit asperiores velit cumque perferendis repellat. 45 | Recusandae nisi accusantium sed quo illum est quasi dolores consequatur. Molestias, illum sequi? Neque modi saepe fugiat voluptate aliquid fugit doloremque numquam eligendi exercitationem, laboriosam accusamus porro eius velit laborum. 46 | Dignissimos eum consequatur eaque voluptatum voluptas! Nulla veritatis possimus eligendi maxime rem. Eos quam quasi impedit neque incidunt sapiente doloremque voluptatibus odio rem porro, accusantium illum eligendi at distinctio omnis! 47 | Dolorum odio necessitatibus iusto sint qui ratione, reiciendis aliquam assumenda eum est provident! Natus nam laudantium dolores dignissimos voluptatum quasi repellendus, ab quis facilis minima consequuntur a aliquid magnam nesciunt. 48 | Nam repellendus unde, beatae, inventore voluptatum tenetur ut deserunt architecto necessitatibus voluptatibus veritatis eos harum tempore totam ipsam temporibus eveniet accusantium cupiditate aperiam quas similique fuga optio nulla? Voluptatem, iure. 49 | Vel, enim ad. Quas aliquid, aspernatur tenetur itaque ipsa minima possimus iste blanditiis eaque repellat ad explicabo optio sunt, numquam cumque est accusantium? Architecto sed facere laboriosam ea, modi neque. 50 | 51 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quam, tenetur nulla explicabo corrupti iure delectus illum iusto aperiam rem est amet sapiente beatae soluta ipsa corporis accusantium nostrum vel blanditiis. 52 | Quisquam nam, vero obcaecati, magni quibusdam totam, nemo incidunt quidem laudantium natus doloremque praesentium neque? Dolorum cumque, totam similique quas nam aliquid quos ipsa provident necessitatibus aliquam accusantium, odio nemo! 53 | Nostrum itaque laborum ipsa natus dolore repellat atque, aliquam iusto aliquid est vitae ducimus eum ipsam fuga molestiae officia nam. Non, quaerat voluptatem. Cumque dignissimos nobis adipisci numquam quidem labore. 54 | Quisquam, dolores hic harum fuga assumenda perferendis libero est animi voluptas deleniti quam tenetur necessitatibus totam ipsa maiores temporibus. Eveniet ipsam perferendis voluptates praesentium consectetur quia id non repellat. Impedit? 55 | Doloribus tempora dolorem corrupti natus, asperiores sint excepturi dicta repellendus modi maiores quaerat culpa ut commodi quibusdam libero atque quod veritatis nulla? Tempore iste odit asperiores velit cumque perferendis repellat. 56 | Recusandae nisi accusantium sed quo illum est quasi dolores consequatur. Molestias, illum sequi? Neque modi saepe fugiat voluptate aliquid fugit doloremque numquam eligendi exercitationem, laboriosam accusamus porro eius velit laborum. 57 | Dignissimos eum consequatur eaque voluptatum voluptas! Nulla veritatis possimus eligendi maxime rem. Eos quam quasi impedit neque incidunt sapiente doloremque voluptatibus odio rem porro, accusantium illum eligendi at distinctio omnis! 58 | Dolorum odio necessitatibus iusto sint qui ratione, reiciendis aliquam assumenda eum est provident! Natus nam laudantium dolores dignissimos voluptatum quasi repellendus, ab quis facilis minima consequuntur a aliquid magnam nesciunt. 59 | Nam repellendus unde, beatae, inventore voluptatum tenetur ut deserunt architecto necessitatibus voluptatibus veritatis eos harum tempore totam ipsam temporibus eveniet accusantium cupiditate aperiam quas similique fuga optio nulla? Voluptatem, iure. 60 | Vel, enim ad. Quas aliquid, aspernatur tenetur itaque ipsa minima possimus iste blanditiis eaque repellat ad explicabo optio sunt, numquam cumque est accusantium? Architecto sed facere laboriosam ea, modi neque. 61 | 62 |
63 |
64 | -------------------------------------------------------------------------------- /app-a/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /app-a/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Router, NavigationEnd } from '@angular/router'; 2 | import { Component } from '@angular/core'; 3 | import { filter } from 'rxjs/operators'; 4 | 5 | declare let childApp: any; 6 | 7 | @Component({ 8 | selector: 'app-root', 9 | templateUrl: './app.component.html', 10 | styleUrls: ['./app.component.css'] 11 | }) 12 | export class AppComponent { 13 | title = 'app'; 14 | 15 | constructor(private router: Router) { 16 | this.initChildRouter(); 17 | } 18 | 19 | // Sync Subroutes 20 | initChildRouter() { 21 | this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe((e: NavigationEnd) => { 22 | childApp.sendRoute(e.url); 23 | }); 24 | 25 | childApp.registerForRouteChange(url => this.router.navigateByUrl(url)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app-a/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule } from '@angular/router'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { NgModule } from '@angular/core'; 4 | 5 | import { AppComponent } from './app.component'; 6 | import { AComponent } from './a/a.component'; 7 | import { BComponent } from './b/b.component'; 8 | 9 | 10 | @NgModule({ 11 | declarations: [ 12 | AppComponent, 13 | AComponent, 14 | BComponent 15 | ], 16 | imports: [ 17 | BrowserModule, 18 | RouterModule.forRoot([ 19 | { path: 'a', component: AComponent }, 20 | { path: 'b', component: BComponent }, 21 | { path: '**', redirectTo: 'a' } 22 | ], { useHash: true }) 23 | ], 24 | providers: [], 25 | bootstrap: [AppComponent] 26 | }) 27 | export class AppModule { } 28 | -------------------------------------------------------------------------------- /app-a/src/app/b/b.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-a/src/app/b/b.component.css -------------------------------------------------------------------------------- /app-a/src/app/b/b.component.html: -------------------------------------------------------------------------------- 1 |

2 | b works! 3 |

4 | -------------------------------------------------------------------------------- /app-a/src/app/b/b.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BComponent } from './b.component'; 4 | 5 | describe('BComponent', () => { 6 | let component: BComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ BComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /app-a/src/app/b/b.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-b', 5 | templateUrl: './b.component.html', 6 | styleUrls: ['./b.component.css'] 7 | }) 8 | export class BComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app-a/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-a/src/assets/.gitkeep -------------------------------------------------------------------------------- /app-a/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /app-a/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /app-a/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-a/src/favicon.ico -------------------------------------------------------------------------------- /app-a/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppA 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app-a/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.log(err)); 13 | -------------------------------------------------------------------------------- /app-a/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | import 'core-js/es6/symbol'; 23 | import 'core-js/es6/object'; 24 | import 'core-js/es6/function'; 25 | import 'core-js/es6/parse-int'; 26 | import 'core-js/es6/parse-float'; 27 | import 'core-js/es6/number'; 28 | import 'core-js/es6/math'; 29 | import 'core-js/es6/string'; 30 | import 'core-js/es6/date'; 31 | import 'core-js/es6/array'; 32 | import 'core-js/es6/regexp'; 33 | import 'core-js/es6/map'; 34 | import 'core-js/es6/weak-map'; 35 | import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | 56 | 57 | /*************************************************************************************************** 58 | * Zone JS is required by Angular itself. 59 | */ 60 | import 'zone.js/dist/zone'; // Included with Angular CLI. 61 | 62 | 63 | 64 | /*************************************************************************************************** 65 | * APPLICATION IMPORTS 66 | */ 67 | 68 | /** 69 | * Date, currency, decimal and percent pipes. 70 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 71 | */ 72 | // import 'intl'; // Run `npm install --save intl`. 73 | /** 74 | * Need to import at least one locale-data with intl. 75 | */ 76 | // import 'intl/locale-data/jsonp/en'; 77 | -------------------------------------------------------------------------------- /app-a/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /app-a/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/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /app-a/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /app-a/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /app-a/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /app-a/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app-a/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs", 19 | "rxjs/Rx" 20 | ], 21 | "import-spacing": true, 22 | "indent": [ 23 | true, 24 | "spaces" 25 | ], 26 | "interface-over-type-literal": true, 27 | "label-position": true, 28 | "max-line-length": [ 29 | true, 30 | 140 31 | ], 32 | "member-access": false, 33 | "member-ordering": [ 34 | true, 35 | { 36 | "order": [ 37 | "static-field", 38 | "instance-field", 39 | "static-method", 40 | "instance-method" 41 | ] 42 | } 43 | ], 44 | "no-arg": true, 45 | "no-bitwise": true, 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-construct": true, 55 | "no-debugger": true, 56 | "no-duplicate-super": true, 57 | "no-empty": false, 58 | "no-empty-interface": true, 59 | "no-eval": true, 60 | "no-inferrable-types": [ 61 | true, 62 | "ignore-params" 63 | ], 64 | "no-misused-new": true, 65 | "no-non-null-assertion": true, 66 | "no-shadowed-variable": true, 67 | "no-string-literal": false, 68 | "no-string-throw": true, 69 | "no-switch-case-fall-through": true, 70 | "no-trailing-whitespace": true, 71 | "no-unnecessary-initializer": true, 72 | "no-unused-expression": true, 73 | "no-use-before-declare": true, 74 | "no-var-keyword": true, 75 | "object-literal-sort-keys": false, 76 | "one-line": [ 77 | true, 78 | "check-open-brace", 79 | "check-catch", 80 | "check-else", 81 | "check-whitespace" 82 | ], 83 | "prefer-const": true, 84 | "quotemark": [ 85 | true, 86 | "single" 87 | ], 88 | "radix": true, 89 | "semicolon": [ 90 | true, 91 | "always" 92 | ], 93 | "triple-equals": [ 94 | true, 95 | "allow-null-check" 96 | ], 97 | "typedef-whitespace": [ 98 | true, 99 | { 100 | "call-signature": "nospace", 101 | "index-signature": "nospace", 102 | "parameter": "nospace", 103 | "property-declaration": "nospace", 104 | "variable-declaration": "nospace" 105 | } 106 | ], 107 | "typeof-compare": true, 108 | "unified-signatures": true, 109 | "variable-name": false, 110 | "whitespace": [ 111 | true, 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type" 117 | ], 118 | "directive-selector": [ 119 | true, 120 | "attribute", 121 | "app", 122 | "camelCase" 123 | ], 124 | "component-selector": [ 125 | true, 126 | "element", 127 | "app", 128 | "kebab-case" 129 | ], 130 | "angular-whitespace": [true, "check-interpolation"], 131 | "no-output-on-prefix": true, 132 | "use-input-property-decorator": true, 133 | "use-output-property-decorator": true, 134 | "use-host-property-decorator": true, 135 | "no-input-rename": true, 136 | "no-output-rename": true, 137 | "use-life-cycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "component-class-suffix": true, 140 | "directive-class-suffix": true 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app-b/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "app-b" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "src/tsconfig.app.json", 40 | "exclude": "**/node_modules/**" 41 | }, 42 | { 43 | "project": "src/tsconfig.spec.json", 44 | "exclude": "**/node_modules/**" 45 | }, 46 | { 47 | "project": "e2e/tsconfig.e2e.json", 48 | "exclude": "**/node_modules/**" 49 | } 50 | ], 51 | "test": { 52 | "karma": { 53 | "config": "./karma.conf.js" 54 | } 55 | }, 56 | "defaults": { 57 | "styleExt": "css", 58 | "component": {} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app-b/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://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 | -------------------------------------------------------------------------------- /app-b/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /app-b/README.md: -------------------------------------------------------------------------------- 1 | # AppB 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.5.4. 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 | -------------------------------------------------------------------------------- /app-b/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('app-b App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /app-b/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app-b/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app-b/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/cli'], 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/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /app-b/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-b", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "^5.0.0", 16 | "@angular/common": "^5.0.0", 17 | "@angular/compiler": "^5.0.0", 18 | "@angular/core": "^5.0.0", 19 | "@angular/forms": "^5.0.0", 20 | "@angular/http": "^5.0.0", 21 | "@angular/platform-browser": "^5.0.0", 22 | "@angular/platform-browser-dynamic": "^5.0.0", 23 | "@angular/router": "^5.0.0", 24 | "core-js": "^2.4.1", 25 | "rxjs": "^5.5.2", 26 | "zone.js": "^0.8.14" 27 | }, 28 | "devDependencies": { 29 | "@angular/cli": "1.5.4", 30 | "@angular/compiler-cli": "^5.0.0", 31 | "@angular/language-service": "^5.0.0", 32 | "@types/jasmine": "~2.5.53", 33 | "@types/jasminewd2": "~2.0.2", 34 | "@types/node": "~6.0.60", 35 | "codelyzer": "^4.0.1", 36 | "jasmine-core": "~2.6.2", 37 | "jasmine-spec-reporter": "~4.1.0", 38 | "karma": "~1.7.0", 39 | "karma-chrome-launcher": "~2.1.1", 40 | "karma-cli": "~1.0.1", 41 | "karma-coverage-istanbul-reporter": "^1.2.1", 42 | "karma-jasmine": "~1.1.0", 43 | "karma-jasmine-html-reporter": "^0.2.2", 44 | "protractor": "~5.1.2", 45 | "ts-node": "~3.2.0", 46 | "tslint": "~5.7.0", 47 | "typescript": "~2.4.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app-b/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /app-b/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-b/src/app/app.component.css -------------------------------------------------------------------------------- /app-b/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Welcome to {{ title }}! 5 |

6 | Angular Logo 7 |
8 |

Here are some links to help you start:

9 | 20 | 21 | -------------------------------------------------------------------------------- /app-b/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /app-b/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 = 'app'; 10 | } 11 | -------------------------------------------------------------------------------- /app-b/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | 5 | import { AppComponent } from './app.component'; 6 | 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | imports: [ 13 | BrowserModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { } 19 | -------------------------------------------------------------------------------- /app-b/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-b/src/assets/.gitkeep -------------------------------------------------------------------------------- /app-b/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /app-b/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /app-b/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfredsteyer/microservice-angular-iframe/aa8423948d4db9f44f525e35824486467473dc1c/app-b/src/favicon.ico -------------------------------------------------------------------------------- /app-b/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppB 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app-b/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.log(err)); 13 | -------------------------------------------------------------------------------- /app-b/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | import 'core-js/es6/symbol'; 23 | import 'core-js/es6/object'; 24 | import 'core-js/es6/function'; 25 | import 'core-js/es6/parse-int'; 26 | import 'core-js/es6/parse-float'; 27 | import 'core-js/es6/number'; 28 | import 'core-js/es6/math'; 29 | import 'core-js/es6/string'; 30 | import 'core-js/es6/date'; 31 | import 'core-js/es6/array'; 32 | import 'core-js/es6/regexp'; 33 | import 'core-js/es6/map'; 34 | import 'core-js/es6/weak-map'; 35 | import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | 56 | 57 | /*************************************************************************************************** 58 | * Zone JS is required by Angular itself. 59 | */ 60 | import 'zone.js/dist/zone'; // Included with Angular CLI. 61 | 62 | 63 | 64 | /*************************************************************************************************** 65 | * APPLICATION IMPORTS 66 | */ 67 | 68 | /** 69 | * Date, currency, decimal and percent pipes. 70 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 71 | */ 72 | // import 'intl'; // Run `npm install --save intl`. 73 | /** 74 | * Need to import at least one locale-data with intl. 75 | */ 76 | // import 'intl/locale-data/jsonp/en'; 77 | -------------------------------------------------------------------------------- /app-b/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /app-b/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/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /app-b/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /app-b/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /app-b/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /app-b/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app-b/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs", 19 | "rxjs/Rx" 20 | ], 21 | "import-spacing": true, 22 | "indent": [ 23 | true, 24 | "spaces" 25 | ], 26 | "interface-over-type-literal": true, 27 | "label-position": true, 28 | "max-line-length": [ 29 | true, 30 | 140 31 | ], 32 | "member-access": false, 33 | "member-ordering": [ 34 | true, 35 | { 36 | "order": [ 37 | "static-field", 38 | "instance-field", 39 | "static-method", 40 | "instance-method" 41 | ] 42 | } 43 | ], 44 | "no-arg": true, 45 | "no-bitwise": true, 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-construct": true, 55 | "no-debugger": true, 56 | "no-duplicate-super": true, 57 | "no-empty": false, 58 | "no-empty-interface": true, 59 | "no-eval": true, 60 | "no-inferrable-types": [ 61 | true, 62 | "ignore-params" 63 | ], 64 | "no-misused-new": true, 65 | "no-non-null-assertion": true, 66 | "no-shadowed-variable": true, 67 | "no-string-literal": false, 68 | "no-string-throw": true, 69 | "no-switch-case-fall-through": true, 70 | "no-trailing-whitespace": true, 71 | "no-unnecessary-initializer": true, 72 | "no-unused-expression": true, 73 | "no-use-before-declare": true, 74 | "no-var-keyword": true, 75 | "object-literal-sort-keys": false, 76 | "one-line": [ 77 | true, 78 | "check-open-brace", 79 | "check-catch", 80 | "check-else", 81 | "check-whitespace" 82 | ], 83 | "prefer-const": true, 84 | "quotemark": [ 85 | true, 86 | "single" 87 | ], 88 | "radix": true, 89 | "semicolon": [ 90 | true, 91 | "always" 92 | ], 93 | "triple-equals": [ 94 | true, 95 | "allow-null-check" 96 | ], 97 | "typedef-whitespace": [ 98 | true, 99 | { 100 | "call-signature": "nospace", 101 | "index-signature": "nospace", 102 | "parameter": "nospace", 103 | "property-declaration": "nospace", 104 | "variable-declaration": "nospace" 105 | } 106 | ], 107 | "typeof-compare": true, 108 | "unified-signatures": true, 109 | "variable-name": false, 110 | "whitespace": [ 111 | true, 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type" 117 | ], 118 | "directive-selector": [ 119 | true, 120 | "attribute", 121 | "app", 122 | "camelCase" 123 | ], 124 | "component-selector": [ 125 | true, 126 | "element", 127 | "app", 128 | "kebab-case" 129 | ], 130 | "angular-whitespace": [true, "check-interpolation"], 131 | "no-output-on-prefix": true, 132 | "use-input-property-decorator": true, 133 | "use-output-property-decorator": true, 134 | "use-host-property-decorator": true, 135 | "no-input-rename": true, 136 | "no-output-rename": true, 137 | "use-life-cycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "component-class-suffix": true, 140 | "directive-class-suffix": true 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /child-app.js: -------------------------------------------------------------------------------- 1 | var childApp = { 2 | sendHeight: function() { 3 | var that = this; 4 | var body = document.body, html = document.documentElement; 5 | 6 | /* 7 | var height = Math.max( body.scrollHeight, body.offsetHeight, 8 | html.clientHeight, html.scrollHeight, html.offsetHeight ); 9 | console.debug('heights', body.scrollHeight, body.offsetHeight, 10 | html.clientHeight, html.scrollHeight, html.offsetHeight); 11 | */ 12 | 13 | var height = html.offsetHeight; 14 | parent.postMessage({ message: 'set-height', appPath: that.childConfig.appId, height: height}, '*'); 15 | }, 16 | config: function(config) { 17 | this.childConfig = config; 18 | }, 19 | sendRoute: function(url) { 20 | parent.postMessage({ message: 'routed', appPath: this.childConfig.appId, route: url }, '*'); 21 | }, 22 | registerForRouteChange: function(callback) { 23 | window.addEventListener('message', (e) => { 24 | if (e.data && e.data.message === 'sub-route') { 25 | callback(e.data.route); 26 | } 27 | }, true); 28 | }, 29 | init: function() { 30 | if (!parent) return; 31 | window.addEventListener('load', this.sendHeight.bind(this), true); 32 | window.addEventListener('resize', this.sendHeight.bind(this), true); 33 | } 34 | } -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | iframe.outlet-frame { 2 | width:100%; 3 | background:#FFF; 4 | border:none; 5 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppA 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Route to A | 16 | Route to B | 17 | Jump to A within A | 18 | Jump to B within A 19 | 20 |
21 | 22 | 23 | 24 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /polyfills.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Selected ES 6 polyfills for IE 3 | */ 4 | 5 | if (!Array.prototype.forEach) { 6 | Array.prototype.forEach = function(f) { 7 | for (var i=0; i 0) { 11 | var defaultRoute = this.config[0]; 12 | this.go(defaultRoute.path); 13 | } 14 | else { 15 | this.routeByUrl(); 16 | } 17 | }, 18 | handleMessage: function(event) { 19 | if (!event.data) return; 20 | 21 | if (event.data.message == 'routed') { 22 | this.setRouteInHash(event.data.appPath, event.data.route); 23 | } 24 | else if (event.data.message == 'set-height') { 25 | this.resizeIframe(event.data.appPath, event.data.height); 26 | } 27 | }, 28 | resizeIframe: function(appPath, height) { 29 | let iframe = document.getElementById(appPath); 30 | if (!iframe) return; 31 | iframe.style.height = height + 'px'; 32 | }, 33 | go: function(path, subRoute) { 34 | var route = this.config.find(function(route) { 35 | return route.path === path; 36 | } ); 37 | if (!route) throw Error('route not found: ' + route); 38 | 39 | this.ensureIframeCreated(route, subRoute); 40 | this.activateRoute(route, subRoute); 41 | }, 42 | ensureIframeCreated: function(route, subRoute) { 43 | if (!this.getIframe(route)) { 44 | 45 | var url = ''; 46 | 47 | if (subRoute) { 48 | url = route.app + '#' + this.additionalConfig.hashPrefix + subRoute; 49 | } 50 | else { 51 | url = route.app; 52 | } 53 | 54 | var iframe = document.createElement('iframe'); 55 | iframe.style['display'] = 'none'; 56 | iframe.src = url; 57 | iframe.id = route.path; 58 | iframe.className = 'outlet-frame'; 59 | 60 | let outlet = this.getOutlet(); 61 | if (!outlet) throw new Error('outlet not found'); 62 | 63 | outlet.appendChild(iframe); 64 | } 65 | }, 66 | activateRoute: function(routeToActivate, subRoute) { 67 | var that = this; 68 | this.config.forEach(function(route) { 69 | var iframe = that.getIframe(route); 70 | if (iframe) { 71 | iframe.style['display'] = route === routeToActivate ? 'block' : 'none'; 72 | } 73 | }); 74 | 75 | if (subRoute) { 76 | var activatedIframe = this.getIframe(routeToActivate); 77 | activatedIframe.contentWindow.postMessage({message: 'sub-route', route: subRoute }, '*' ); 78 | } 79 | 80 | this.setRouteInHash(routeToActivate.path, subRoute); 81 | this.activatedRoute = routeToActivate; 82 | }, 83 | setRouteInHash: function(path, subRoute) { 84 | 85 | if (subRoute && subRoute.startsWith('/')) { 86 | subRoute = subRoute.substr(1); 87 | } 88 | 89 | var hash = ''; 90 | 91 | if (subRoute) { 92 | hash = path + '/' + subRoute; 93 | } 94 | else { 95 | hash = path; 96 | } 97 | history.replaceState(null, null, document.location.pathname + '#' + hash); 98 | }, 99 | getIframe: function(route) { 100 | return document.getElementById(route.path); 101 | }, 102 | getOutlet: function() { 103 | return document.getElementById('outlet'); 104 | }, 105 | routeByUrl: function() { 106 | if (!location.hash) return; 107 | var path = location.hash.substr(1); 108 | if (!path) return; 109 | var segments = path.split('/'); 110 | var appPath = segments[0]; 111 | var rest = segments.slice(1).join('/'); 112 | this.go(appPath, rest); 113 | }, 114 | preload: function() { 115 | var that = this; 116 | this.config.forEach(function(route) { 117 | that.ensureIframeCreated(route); 118 | }) 119 | } 120 | }; --------------------------------------------------------------------------------