<!DOCTYPE html>
<html>
<head>
<title>Angular Quickstart</title>
<script data-require="jquery@2.2.4" data-semver="2.2.4" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script>document.write('<base href="' + document.location + '" />');</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {color:#369;font-family: Arial,Helvetica,sans-serif;}
</style>
<link href="style.css" rel="stylesheet" media="screen" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet" media="screen" />
<!-- Polyfills -->
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent content here ...</my-app>
</body>
</html>
.sheet-holder .sheet-container:nth-last-of-type(1) .sheet-overlay {
opacity: 0;
visibility: hidden;
}
.sheet-holder .sheet-container:nth-last-of-type(2) .sheet-overlay {
opacity: .12;
visibility: visible;
}
.sheet-holder .sheet-container:nth-last-of-type(3) .sheet-overlay {
opacity: .12;
visibility: visible;
}
.sheet-holder .sheet-container:last-of-type .sheet {
transition-delay: 0s,.4s,.4s;
opacity: 0;
pointer-events: none;
transition: transform .4s,box-shadow 0s,opacity 0s;
}
.sheet-holder .sheet-container:nth-last-of-type(2) .sheet {
box-shadow: 0 0 10px -5px rgba(0, 0, 0, 0.2), 0 0 24px 2px rgba(0, 0, 0, 0.14), 0 0 30px 5px rgba(0, 0, 0, 0.12);
}
.sheet-holder .sheet-overlay {
opacity: .12;
transition: all .4s;
background: black;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
visibility: hidden;
z-index: 2002;
}
.sheet-holder .sheet {
transition: transform .4s;
background: #f3f3f4;
bottom: 0;
left: 0;
max-width: 100%;
overflow-x: hidden;
overflow-y: auto;
position: fixed;
top: 0;
width: 100%;
z-index: 2002;
flex-direction: column;
display: flex;
flex-wrap: nowrap;
}
.sheet-holder .sheet .sheet-content {
flex: 1 1 auto;
order: 3;
overflow-y: auto;
position: relative;
margin: 0 auto;
padding: 24px 24px 16px;
}
@media (min-width: 768px) {
.sheet-holder .sheet .sheet-content {
width: 768px;
}
}
@media (min-width: 1160px) {
.sheet-holder .sheet .sheet-content {
width: 960px;
}
}
.sheet-holder .sheet .sheet-header {
order: 0;
background: #fff;
border-bottom: 1px solid transparent;
border-bottom-color: #e1e1e1;
border-radius: 2px;
position: relative;
box-shadow: none;
}
.sheet-holder .sheet .sheet-header-actions {
font-size: 0;
padding-right: 24px;
text-align: right;
display: inline-block;
}
.sheet-holder .sheet .sheet-scrollpane {
order: 3;
overflow-y: auto;
position: relative;
flex: 1 1 auto;
}
.sheet-holder .sheet .sheet-scrollpane .sheet-content {
overflow-y: visible;
}
.sheet-btn {
margin: 13px 0 !important;
}
/**
* WEB ANGULAR VERSION
* (based on systemjs.config.js in angular.io)
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
// Copy of compiler options in standard tsconfig.json
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
meta: {
'typescript': {
"exports": "ts"
}
},
paths: {
// paths serve as alias
'npm:': 'https://unpkg.com/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
'app': 'app',
// angular bundles
'@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js',
'@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
// other libraries
'rxjs': 'npm:rxjs@5.0.1',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js',
'typescript': 'npm:typescript@2.3.2/lib/typescript.js',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts',
meta: {
'./*.ts': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
module.exports.translate = function(load){
if (load.source.indexOf('moduleId') != -1) return load;
var url = document.createElement('a');
url.href = load.address;
var basePathParts = url.pathname.split('/');
basePathParts.pop();
var basePath = basePathParts.join('/');
var baseHref = document.createElement('a');
baseHref.href = this.baseURL;
baseHref = baseHref.pathname;
if (!baseHref.startsWith('/base/')) { // it is not karma
basePath = basePath.replace(baseHref, '');
}
load.source = load.source
.replace(templateUrlRegex, function(match, quote, url){
var resolvedUrl = url;
if (url.startsWith('.')) {
resolvedUrl = basePath + url.substr(1);
}
return 'templateUrl: "' + resolvedUrl + '"';
})
.replace(stylesRegex, function(match, relativeUrls) {
var urls = [];
while ((match = stringRegex.exec(relativeUrls)) !== null) {
if (match[2].startsWith('.')) {
urls.push('"' + basePath + match[2].substr(1) + '"');
} else {
urls.push('"' + match[2] + '"');
}
}
return "styleUrls: [" + urls.join(', ') + "]";
});
return load;
};
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { SheetComponent } from './sheet.component';
import { SheetListComponent } from './sheet-list.component';
import { SheetListService } from './sheet-list.service';
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
HelloComponent,
SheetComponent,
SheetListComponent
],
providers: [
SheetListService
],
entryComponents: [HelloComponent, SheetListComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
import { Component, ViewContainerRef, ViewChild, OnInit } from '@angular/core';
import { SheetListComponent } from './sheet-list.component';
import { SheetListService } from './sheet-list.service';
import { HelloComponent } from './hello.component';
@Component({
selector: 'my-app',
template: `
<h1>Hello {{name}}</h1>
<button (click)="showHello()" class="btn">Hello</button>
<ng-template #sheetListContainer></ng-template>
`
})
export class AppComponent implements OnInit {
name = 'Angular';
sheetList: SheetListComponent;
@ViewChild('sheetListContainer', {read: ViewContainerRef}) sheetListContainer;
constructor(
private sheetListService: SheetListService
) {}
ngOnInit() {
this.sheetListInit();
}
private sheetListInit() {
this.sheetList = this.sheetListService.initOrGetSheetList(this.sheetListContainer);
this.sheetList.onComponentCreated.subscribe(
(params) => {
this.componentCreated(params);
}
)
}
componentCreated(params) {
const component = params.cmp;
const name = params.name;
if (name === 'HelloComponent') {
(<HelloComponent>component.instance);
}
}
showHello() {
const inputParams = {
name: 'angular sheet',
};
this.sheetList.addSheet(HelloComponent, 'HelloComponent', inputParams);
}
}
import {
AfterViewInit, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef,
EventEmitter, Input, OnChanges, OnDestroy,
OnInit, Output, Type,
ViewChild, ViewContainerRef,
} from '@angular/core';
import { SheetService } from './sheet.service';
export interface Config {
type: Type<Component>,
componentName: string,
inputParams: any
}
@Component({
selector: '[widget-sheet]',
template: `
<div class="sheet-overlay" (click)="closeSheet()"></div>
<div class="sheet">
<ng-template #sheet></ng-template>
</div>
`,
providers: [SheetService]
})
export class SheetComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
@ViewChild("sheet", {read: ViewContainerRef}) sheet;
@Output() onComponentCreate = new EventEmitter<any>();
@Output() onCloseModal = new EventEmitter<any>();
@Input() config: Config;
cmpRef: ComponentRef<Component>;
private isViewInitialized: boolean = false;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private _changeDetectionRef: ChangeDetectorRef,
private sheetService: SheetService,
) {}
ngOnInit() {}
ngAfterViewInit() {
this.sheetService.updateSheetWidth();
this.isViewInitialized = true;
this.updateComponent();
this._changeDetectionRef.detectChanges();
}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
this.sheet.clear();
let factory = this.componentFactoryResolver.resolveComponentFactory(this.config.type);
this.cmpRef = this.sheet.createComponent(factory);
const emitComponent = {cmp: this.cmpRef, name: this.config.componentName, params: this.config.inputParams};
const component = emitComponent.cmp;
const paramsOptional = emitComponent.params;
if (Object.keys(paramsOptional).length !== 0) {
const keysParams = Object.keys(paramsOptional);
for (let key of keysParams) {
(component.instance)[key] = paramsOptional[key];
}
}
this.onComponentCreate.emit(emitComponent);
}
closeSheet() {
this.onCloseModal.emit(true);
}
ngOnChanges() {
this.updateComponent();
}
ngOnDestroy() {
this.cmpRef.destroy();
}
}
import { Injectable } from '@angular/core';
declare var jQuery: any;
@Injectable()
export class SheetService {
maxWidth;
transform;
constructor() {}
updateSheetWidth(hide = true) {
if (hide) {
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('display', 'none');
}
this.calculWidth();
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('transform', `translate(${jQuery(document).width()}px, 0px)`);
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('max-width', this.maxWidth);
}
closeSheet(sheetList) {
this.calculWidth();
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet-overlay').fadeOut(150);
const self = this;
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('transform', `translate(${jQuery(document).width()}px, 0px)`);
jQuery('.sheet-container:nth-last-of-type(3)').find('.sheet').css('transform', `translate(${self.transform}px, 0px)`);
setTimeout(() => {
sheetList.pop();
}, 500);
}
display() {
this.calculWidth();
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('display', '');
setTimeout(() => {
jQuery('.sheet-container:nth-last-of-type(2)').find('.sheet').css('transform', `translate(${this.transform}px, 0px)`);
}, 100);
jQuery('.sheet-container:nth-last-of-type(3)').find('.sheet').css('transform', `translate(0px, 0px)`);
}
private calculWidth() {
this.transform = Math.round(jQuery(document).width() / 4);
this.maxWidth = jQuery(document).width() - this.transform;
}
}
import {
Component, EventEmitter, OnInit, Output
} from '@angular/core';
import { SheetService } from './sheet.service';
import { Config } from './sheet.component';
@Component({
selector: 'app-sheet-list',
template: `
<div class="sheet-holder">
<div widget-sheet *ngFor="let sheet of sheetList" class="sheet-container"
[config]="sheet"
(onComponentCreate)="componentCreated($event)"
(onCloseModal)="closeSheet($event)">
</div>
<div class="sheet-container">
<div class="sheet-overlay"></div>
<div class="sheet"></div>
</div>
</div>
`,
providers: [SheetService]
})
export class SheetListComponent implements OnInit {
sheetList = [];
@Output() onComponentCreated = new EventEmitter<any>();
constructor(private sheetService: SheetService) {}
ngOnInit() {}
addSheet(componentType, name, params?) {
const toInsert: Config = {
type: componentType,
componentName: name,
inputParams: params || {}
};
this.sheetList.push(toInsert);
}
componentCreated(emitComponent) {
this.onComponentCreated.emit(emitComponent);
this.sheetService.display();
}
closeSheet() {
this.sheetService.closeSheet(this.sheetList);
}
}
import {
ComponentFactoryResolver, ViewContainerRef,
OnDestroy, Injectable, ReflectiveInjector
} from '@angular/core';
import { SheetListComponent } from './sheet-list.component';
@Injectable()
export class SheetListService implements OnDestroy {
private componentRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
initOrGetSheetList(vCref: ViewContainerRef) {
if (this.componentRef) {
return this.getComponent();
}
let factory = this.componentFactoryResolver.resolveComponentFactory(SheetListComponent);
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
let ref = factory.create(injector);
vCref.insert(ref.hostView);
this.componentRef = (<SheetListComponent>ref.instance);
return this.getComponent();
}
getComponent() {
return this.componentRef;
}
ngOnDestroy() {
this.componentRef.destroy();
}
}
import { Component, ViewContainerRef, ViewChild, OnInit } from '@angular/core';
import { SheetListComponent } from './sheet-list.component';
import { SheetListService } from './sheet-list.service';
@Component({
selector: 'my-app',
template: `
<nav class="sheet-header navbar navbar-static-top" role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<a class="btn btn-primary" (click)="sheetList.closeSheet()">
close
</a>
</div>
</nav>
<div class="sheet-scrollpane">
<div class="sheet-content sheet-padding">
Hello {{ name }}
<br>
<button (click)="showHello()" class="btn">Hello</button>
</div>
</div>
`
})
export class HelloComponent {
name;
sheetList: SheetListComponent;
constructor(
private sheetListService: SheetListService
) {
this.sheetList = this.sheetListService.getComponent();
}
showHello() {
const inputParams = {
name: 'angular again',
};
this.sheetList.addSheet(HelloComponent, 'HelloComponent', inputParams);
}
}