Skip to content

Commit

Permalink
feat(core): support Angular RC5
Browse files Browse the repository at this point in the history
feat(bootstrap): support Angular RC5
misc: disable plugins that does not support RC5
  • Loading branch information
Shlomi Assaf (shlassaf) committed Aug 10, 2016
1 parent 2bb0835 commit e4bbcc4
Show file tree
Hide file tree
Showing 21 changed files with 317 additions and 253 deletions.
8 changes: 6 additions & 2 deletions package.json
Expand Up @@ -27,15 +27,19 @@
"server": "npm run server:dev",
"server:dev": "webpack-dev-server --config webpack.config.js --hot --inline --progress --profile --colors --watch --display-error-details --display-cached --content-base src/",
"build": "exec ./scripts/build_release.sh",
"preinstall": "node install_angular.js --preinstall",
"postinstall": "node install_angular.js --postinstall",
"start": "npm run server:dev"
},
"peerDependencies": {
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12"
},
"devDependencies": {
"@angular/core": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/common": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",
"angular-cli": "0.0.31",
"async": "^1.5.2",
"bootstrap": "^3.3.6",
Expand Down
22 changes: 6 additions & 16 deletions src/bootstrap.ts
@@ -1,28 +1,18 @@
import { ComponentRef, PLATFORM_DIRECTIVES } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { NgModuleRef } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { MODAL_BROWSER_PROVIDERS } from './components/angular2-modal/platform-browser';
// The app module
import { AppModule } from './demo/app/app.module';

// Register providers for browser, this is mandatory.

import { App } from './demo/app/app';
import { APP_ROUTER_PROVIDERS } from './demo/app/app.routes';

let _bootstrapped = false;

export function main(): Promise<ComponentRef<App>> {
export function main(): Promise<NgModuleRef<AppModule>> {
if (_bootstrapped) {
return <any>Promise.reject(null);
} else {
_bootstrapped = true;
return bootstrap(App, [
...MODAL_BROWSER_PROVIDERS,
{provide: PLATFORM_DIRECTIVES, multi: true, useValue: ROUTER_DIRECTIVES},
APP_ROUTER_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy},
])
return platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/components/angular2-modal/angular2-modal.module.ts
@@ -0,0 +1,20 @@
import { NgModule, ModuleWithProviders } from '@angular/core';

import { EVENT_MANAGER_PLUGINS } from '@angular/platform-browser';
import { DOMOutsideEventPlugin } from './providers/outside-event-plugin';
import { ModalRenderer, DOMModalRenderer } from '../angular2-modal';

@NgModule({

})
export class ModalModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: ModalModule,
providers: [
{ provide: ModalRenderer, useClass: DOMModalRenderer },
{ provide: EVENT_MANAGER_PLUGINS, useClass: DOMOutsideEventPlugin, multi: true },
]
};
}
}
7 changes: 2 additions & 5 deletions src/components/angular2-modal/angular2-modal.ts
Expand Up @@ -24,8 +24,5 @@ export {

export { ModalOpenContext, ModalOpenContextBuilder } from './models/modal-open-context';

/**
* Deprecated, use platform based providers.
* @type {Array}
*/
export const MODAL_PROVIDERS: any[] = [];

export { ModalModule } from './angular2-modal.module';
2 changes: 1 addition & 1 deletion src/components/angular2-modal/models/tokens.ts
Expand Up @@ -39,7 +39,7 @@ export abstract class ModalRenderer {
viewContainer: ViewContainerRef,
bindings: ResolvedReflectiveProvider[],
dialog: DialogRef<any>
): Promise<DialogRef<any>>;
): DialogRef<any>;
}

export abstract class ModalBackdropComponent extends Type {}
Expand Down
12 changes: 0 additions & 12 deletions src/components/angular2-modal/platform-browser/index.ts

This file was deleted.

@@ -0,0 +1,44 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';

import { Modal } from './modal';
import { BSModalBackdrop } from './modal-backdrop';
import { BSMessageModal } from './message-modal';
import { BSModalContainer } from './modal-container';
import { BSModalFooter } from './modal-footer';


import { OneButtonPresetBuilder } from './presets/one-button-preset';
import { TwoButtonPresetBuilder } from './presets/two-button-preset';

import {
Modal as BaseModal,
ModalBackdropComponent,
ModalDropInFactory
} from '../../angular2-modal';

@NgModule({
imports: [ CommonModule ],
declarations: [
BSModalBackdrop,
BSMessageModal,
BSModalContainer,
BSModalFooter
],
providers: [
{ provide: BaseModal, useClass: Modal },
{ provide: Modal, useClass: Modal },
{ provide: ModalBackdropComponent, useValue: BSModalBackdrop },
{ provide: ModalDropInFactory, useValue: {
alert: modal => new OneButtonPresetBuilder(modal, <any>{isBlocking: false}),
prompt: modal => new OneButtonPresetBuilder(modal, <any>{isBlocking: true, keyboard: null}),
confirm: modal => new TwoButtonPresetBuilder(modal, <any>{isBlocking: true, keyboard: null})
}}
],
entryComponents: [
BSModalBackdrop,
BSMessageModal
]
})
export class BootstrapModalModule {}

26 changes: 1 addition & 25 deletions src/components/angular2-modal/plugins/bootstrap/index.ts
@@ -1,17 +1,3 @@
import { Provider } from '@angular/core';

import { Modal } from './modal';
import { BSModalBackdrop } from './modal-backdrop';
import { OneButtonPresetBuilder } from './presets/one-button-preset';
import { TwoButtonPresetBuilder } from './presets/two-button-preset';

import {
Modal as BaseModal,
ModalBackdropComponent,
ModalDropInFactory,
MODAL_PROVIDERS
} from '../../angular2-modal';

export { BootstrapModalSize, BSModalContext, BSModalContextBuilder } from './modal-context';
export { BSModalBackdrop } from './modal-backdrop';
export { BSModalContainer } from './modal-container';
Expand All @@ -28,14 +14,4 @@ export { OneButtonPreset, OneButtonPresetBuilder } from './presets/one-button-pr
export { TwoButtonPreset, TwoButtonPresetBuilder } from './presets/two-button-preset';
export { BSModal, Modal } from './modal';

export const BS_MODAL_PROVIDERS: any[] = [
...MODAL_PROVIDERS,
new Provider(BaseModal, { useClass: Modal }),
new Provider(Modal, { useClass: Modal }),
new Provider(ModalBackdropComponent, { useValue: BSModalBackdrop }),
new Provider(ModalDropInFactory, { useValue: {
alert: modal => new OneButtonPresetBuilder(modal, <any>{isBlocking: false}),
prompt: modal => new OneButtonPresetBuilder(modal, <any>{isBlocking: true, keyboard: null}),
confirm: modal => new TwoButtonPresetBuilder(modal, <any>{isBlocking: true, keyboard: null})
}})
];
export { BootstrapModalModule } from './bootstrap.module';
Expand Up @@ -37,7 +37,6 @@ export interface BSMessageModalButtonConfig {
*/
@Component({
selector: 'modal-content',
directives: [BSModalFooter],
encapsulation: ViewEncapsulation.None,
template:
`<div [ngClass]="context.headerClass" [ngSwitch]="titleHtml">
Expand Down
Expand Up @@ -11,8 +11,6 @@ import {
} from '@angular/core';

import { DialogRef } from '../../angular2-modal';

import { BSModalContainer } from './modal-container';
import { BSModalContext } from './modal-context';

let dialogRefCount = 0;
Expand All @@ -31,7 +29,6 @@ let dialogRefCount = 0;
'[style.right]': 'hs.pt',
'[style.bottom]': 'hs.pt'
},
directives: [BSModalContainer],
animations: [
trigger('fade', [
transition('void => in', [
Expand All @@ -54,7 +51,7 @@ let dialogRefCount = 0;
])
],
encapsulation: ViewEncapsulation.None,
template: `<div [style.position]="hs.ps" class="modal-backdrop in" @fade="fadeState"></div>
template: `<div [style.position]="hs.ps" class="modal-backdrop in" [@fade]="fadeState"></div>
<modal-container></modal-container>`
})
export class BSModalBackdrop implements OnDestroy {
Expand Down
35 changes: 20 additions & 15 deletions src/components/angular2-modal/plugins/bootstrap/modal-container.ts
@@ -1,6 +1,6 @@
import {
Component,
ComponentResolver,
ComponentFactoryResolver,
ViewContainerRef,
ReflectiveInjector,
ViewChild,
Expand Down Expand Up @@ -61,7 +61,7 @@ import { BSModalContext } from './modal-context';
template: `<div [ngClass]="dialog.context.dialogClass"
[class.modal-lg]="dialog.context.size == \'lg\'"
[class.modal-sm]="dialog.context.size == \'sm\'"
@fade="fadeState">
[@fade]="fadeState">
<div class="modal-content"
style="display:block"
role="document"
Expand All @@ -82,7 +82,7 @@ export class BSModalContainer implements AfterViewInit {
private el: ElementRef,
private _compileConfig: ModalCompileConfig,
private _modal: Modal,
private _cr: ComponentResolver) {
private _cr: ComponentFactoryResolver) {
if (!dialog.inElement) {
this.position = null;
} else {
Expand All @@ -92,21 +92,26 @@ export class BSModalContainer implements AfterViewInit {
}

ngAfterViewInit() {
this._cr.resolveComponent(this._compileConfig.component)
.then(cmpFactory => {
const vcr = this._viewContainer,
const cmpFactory = this._cr.resolveComponentFactory(this._compileConfig.component as any),
vcr = this._viewContainer,
bindings = this._compileConfig.bindings,
ctxInjector = vcr.parentInjector;
ctxInjector = vcr.parentInjector,
childInjector = Array.isArray(bindings) && bindings.length > 0 ?
ReflectiveInjector.fromResolvedProviders(bindings, ctxInjector) : ctxInjector;

const childInjector = Array.isArray(bindings) && bindings.length > 0 ?
ReflectiveInjector.fromResolvedProviders(bindings, ctxInjector) : ctxInjector;

if (this.el.nativeElement) {
this.el.nativeElement.focus();
}
if (this.el.nativeElement) {
this.el.nativeElement.focus();
}

this.dialog.contentRef = vcr.createComponent(cmpFactory, vcr.length, childInjector);
});
/* TODO:
In RC5 dynamic component creation is no longer async.
Somewhere down the pipe of the created component a value change happens that fires
a CD exception. setTimeout is a workaround that mimics the async behavior.
Find out the error and remove setTimeout.
*/
setTimeout(
() => this.dialog.contentRef = vcr.createComponent(cmpFactory, vcr.length, childInjector)
);
}

onClickOutside() {
Expand Down
69 changes: 40 additions & 29 deletions src/components/angular2-modal/providers/dom-modal-renderer.ts
@@ -1,6 +1,6 @@
import {
ViewContainerRef,
ComponentResolver,
ComponentFactoryResolver,
ComponentRef,
ResolvedReflectiveProvider,
ReflectiveInjector,
Expand All @@ -14,38 +14,49 @@ import { ModalRenderer } from '../models/tokens';

@Injectable()
export class DOMModalRenderer implements ModalRenderer {
constructor(private _cr: ComponentResolver) {
constructor(private _cr: ComponentFactoryResolver) {
}

render(type: Type,
render(type: any,
viewContainer: ViewContainerRef,
bindings: ResolvedReflectiveProvider[],
dialog: DialogRef<any>): Promise<DialogRef<any>> {

return this._cr.resolveComponent(type)
.then(cmpFactory => {
const ctxInjector = viewContainer.parentInjector;
const childInjector = Array.isArray(bindings) && bindings.length > 0 ?
ReflectiveInjector.fromResolvedProviders(bindings, ctxInjector) : ctxInjector;
return viewContainer.createComponent(cmpFactory, viewContainer.length, childInjector);
})
.then((cmpRef: ComponentRef<any>) => {
if (dialog.inElement) {
viewContainer.element.nativeElement.appendChild(cmpRef.location.nativeElement);
} else {
document.body.appendChild(cmpRef.location.nativeElement);
}

dialog.onDestroy.subscribe( () => {
if (typeof cmpRef.instance.canDestroy === 'function') {
cmpRef.instance.canDestroy().then ( () => cmpRef.destroy() );
} else {
cmpRef.destroy();
}
});

return dialog;
});
dialog: DialogRef<any>): DialogRef<any> {


const cmpRef = this.createComponent(type, viewContainer, bindings);

if (dialog.inElement) {
viewContainer.element.nativeElement.appendChild(cmpRef.location.nativeElement);
} else {
document.body.appendChild(cmpRef.location.nativeElement);
}

dialog.onDestroy.subscribe( () => {
if (typeof cmpRef.instance.canDestroy === 'function') {
cmpRef.instance.canDestroy().then ( () => cmpRef.destroy() );
} else {
cmpRef.destroy();
}
});

return dialog;
}

private createComponent(type: any,
viewContainer: ViewContainerRef,
bindings: ResolvedReflectiveProvider[]): ComponentRef<any> {
return viewContainer.createComponent(
this._cr.resolveComponentFactory(type),
viewContainer.length,
this.getInjector(viewContainer, bindings)
);
}

private getInjector(viewContainer: ViewContainerRef, bindings: ResolvedReflectiveProvider[]) {
const ctxInjector = viewContainer.parentInjector;
return Array.isArray(bindings) && bindings.length > 0 ?
ReflectiveInjector.fromResolvedProviders(bindings, ctxInjector) : ctxInjector;

}
}

11 changes: 5 additions & 6 deletions src/components/angular2-modal/providers/modal.ts
Expand Up @@ -113,12 +113,11 @@ export class Modal {
{provide: ModalCompileConfig, useValue: compileConfig}
]);

return this._modalRenderer.render(this._backdrop, viewContainer, b, dialog)
.then(dialog => {
_stack.pushManaged(dialog);
dialog.onDestroy.subscribe( () => _stack.remove(dialog) );
return dialog;
});
this._modalRenderer.render(this._backdrop, viewContainer, b, dialog);
_stack.pushManaged(dialog);
dialog.onDestroy.subscribe( () => _stack.remove(dialog) );

return Promise.resolve(dialog);
}

/**
Expand Down

0 comments on commit e4bbcc4

Please sign in to comment.