From 9b902dc4e3c04424b5a6da3fa06534af7fa0cc1e Mon Sep 17 00:00:00 2001 From: Edward Carroll Date: Thu, 8 Jun 2017 04:18:33 +0100 Subject: [PATCH 01/24] feat(message): Added very early implementation of message container --- components/message/active-message.ts | 14 ++++++++ components/message/live-message.ts | 25 ++++++++++++++ components/message/message-config.ts | 45 +++++++++++++++++++++++++ components/message/message-container.ts | 41 ++++++++++++++++++++++ components/message/message.module.ts | 10 ++++-- components/util/types.ts | 30 +++++++++++++++++ demo/src/app/pages/test/test.page.html | 26 +------------- demo/src/app/pages/test/test.page.ts | 28 +++++---------- 8 files changed, 172 insertions(+), 47 deletions(-) create mode 100644 components/message/active-message.ts create mode 100644 components/message/live-message.ts create mode 100644 components/message/message-config.ts create mode 100644 components/message/message-container.ts create mode 100644 components/util/types.ts diff --git a/components/message/active-message.ts b/components/message/active-message.ts new file mode 100644 index 000000000..9c7aed25c --- /dev/null +++ b/components/message/active-message.ts @@ -0,0 +1,14 @@ +import {MessageConfig} from './message-config'; + +export class ActiveMessage { + private _config:MessageConfig; + + constructor(config:MessageConfig) { + this._config = config; + } + + public onClick(callback:() => void) { + this._config.onClick.subscribe(() => callback()); + return this; + } +} \ No newline at end of file diff --git a/components/message/live-message.ts b/components/message/live-message.ts new file mode 100644 index 000000000..d8c7e05cb --- /dev/null +++ b/components/message/live-message.ts @@ -0,0 +1,25 @@ +import {MessageConfig} from './message-config'; + +export class LiveMessage { + public config:MessageConfig; + + private _displayTimeout:number; + + constructor(config:MessageConfig) { + this.config = config; + + this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.timeout); + } + + public onMouseEnter() { + clearTimeout(this._displayTimeout); + } + + public onMouseLeave() { + this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.extendedTimeout); + } + + public onTimedOut() { + console.log("bye"); + } +} \ No newline at end of file diff --git a/components/message/message-config.ts b/components/message/message-config.ts new file mode 100644 index 000000000..b2b1a6ad0 --- /dev/null +++ b/components/message/message-config.ts @@ -0,0 +1,45 @@ +import {EventEmitter} from '@angular/core'; + +export type MessageState = "" | "info" | "success" | "warning" | "error"; + +export const MessageState = { + Default: "" as MessageState, + Info: "info" as MessageState, + Success: "success" as MessageState, + Warning: "warning" as MessageState, + Error: "error" as MessageState +} + +export class MessageConfig { + public text:string; + public header:string; + public state:MessageState; + + public timeout:number; + public extendedTimeout:number; + + public closeButton:boolean; + + public transition:string; + public transitionInDuration:number; + public transitionOutDuration:number; + + public onClick:EventEmitter; + + constructor(text:string, state?:MessageState, header?:string) { + this.text = text; + this.state = state; + this.header = header; + + this.timeout = 5000; + this.extendedTimeout = 1000; + + this.closeButton = true; + + this.transition = "scale"; + this.transitionInDuration = 200; + this.transitionOutDuration = 1000; + + this.onClick = new EventEmitter(); + } +} \ No newline at end of file diff --git a/components/message/message-container.ts b/components/message/message-container.ts new file mode 100644 index 000000000..91eb285dc --- /dev/null +++ b/components/message/message-container.ts @@ -0,0 +1,41 @@ +import {Component, EventEmitter, Input} from '@angular/core'; +import {MessageConfig} from './message-config'; +import {LiveMessage} from './live-message'; +import {ActiveMessage} from './active-message'; + +@Component({ + selector: 'sui-message-container', + template: ` + +
{{ message.config.header }}
+

{{ message.config.text }}

+
+` +}) +export class SuiMessageContainer { + private _messages:LiveMessage[]; + private _queue:MessageConfig[]; + + @Input() + public maxShown:number; + + constructor() { + this._messages = []; + this._queue = []; + + this.maxShown = 10; + } + + public show(message:MessageConfig) { + if (this._messages.length == this.maxShown) { + this._queue.push(message); + } + else { + const live = new LiveMessage(message); + + this._messages.push(live); + } + + return new ActiveMessage(message); + } +} \ No newline at end of file diff --git a/components/message/message.module.ts b/components/message/message.module.ts index f9c3eb42f..ca17ed3e3 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -2,6 +2,7 @@ import {NgModule} from '@angular/core'; import {CommonModule} from "@angular/common"; import {SuiMessage, IMessage} from './message'; import {SuiTransitionModule} from "../transition/transition.module"; +import {SuiMessageContainer} from './message-container'; @NgModule({ imports: [ @@ -9,10 +10,15 @@ import {SuiTransitionModule} from "../transition/transition.module"; SuiTransitionModule ], declarations: [ - SuiMessage + SuiMessage, + SuiMessageContainer ], exports: [ - SuiMessage + SuiMessage, + SuiMessageContainer + ], + entryComponents: [ + SuiMessageContainer ] }) export class SuiMessageModule {} diff --git a/components/util/types.ts b/components/util/types.ts new file mode 100644 index 000000000..02848253b --- /dev/null +++ b/components/util/types.ts @@ -0,0 +1,30 @@ +export type SuiColor = "" | "red" | "orange" | "yellow" | "olive" | "green" | "teal" | "blue" | "violet" | "purple" | "pink" | "brown" | "black"; + +export const SuiColor = { + Default: "" as SuiColor, + Red: "red" as SuiColor, + Orange: "orange" as SuiColor, + Yellow: "yellow" as SuiColor, + Olive: "olive" as SuiColor, + Green: "green" as SuiColor, + Teal: "teal" as SuiColor, + Blue: "blue" as SuiColor, + Violet: "violet" as SuiColor, + Purple: "purple" as SuiColor, + Pink: "pink" as SuiColor, + Brown: "brown" as SuiColor, + Black: "black" as SuiColor +} + +export type SuiSize = "mini" | "tiny" | "small" | "" | "large" | "big" | "huge" | "massive"; + +export const SuiSize = { + Mini: "mini" as SuiSize, + Tiny: "tiny" as SuiSize, + Small: "small" as SuiSize, + Default: "" as SuiSize, + Large: "large" as SuiSize, + Big: "big" as SuiSize, + Huge: "huge" as SuiSize, + Massive: "massive" as SuiSize +} \ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index 54e13002c..70755f694 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -7,30 +7,6 @@

Examples

- -
Example
-
-

Hey there!

-








-

Hellloooo

-
-
- - -
-
- - +
\ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index 32c2bc374..7235d9e8f 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -1,8 +1,7 @@ import {Component, AfterViewInit, ViewChild, TemplateRef} from '@angular/core'; import {SuiModalService} from '../../../../../components/modal/modal.service'; -import {ModalConfig, ComponentModalConfig, TemplateModalConfig, ModalSize} from '../../../../../components/modal/modal-config'; -import {Modal} from '../../../../../components/modal/modal-controls'; -import {ModalTemplate} from '../../../../../components/modal/modal-template'; +import {SuiMessageContainer} from '../../../../../components/message/message-container'; +import {MessageConfig, MessageState} from '../../../../../components/message/message-config'; @Component({ selector: 'demo-page-test', @@ -10,26 +9,15 @@ import {ModalTemplate} from '../../../../../components/modal/modal-template'; }) export class TestPage implements AfterViewInit { - @ViewChild('modalTemplate') - public modalTemplate:ModalTemplate + @ViewChild('messages') + public messages:SuiMessageContainer - constructor(public modalService:SuiModalService) {} + constructor() {} public ngAfterViewInit() { - // const modal = new TemplateModalInstance(this.modalTemplate, null, true); - // const modal = new AcceptRejectModal("Are you sure?", "Are you sure you want to do this?"); + const message = new MessageConfig(null, MessageState.Default, "Hello, world!"); - // modal.closeResult = "default!"; - - // let activeModal = this.modalService - // .open(modal) - // .onApprove(str => alert(str)) - // .onDeny(str => alert(str)); - - // setTimeout(() => activeModal.destroy(), 2000); - } - - public alert(str:string) { - alert(str); + this.messages.show(message); + this.messages.show(message); } } From 2899a87d037ec0539fc54c9e80960d3a22d08b94 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 03:58:03 +0100 Subject: [PATCH 02/24] style: Fixed tslint errors --- components/message/active-message.ts | 6 +++--- components/message/live-message.ts | 10 +++++----- components/message/message-config.ts | 6 +++--- components/message/message-container.ts | 19 +++++++++---------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/components/message/active-message.ts b/components/message/active-message.ts index 9c7aed25c..c31afd6d1 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -1,4 +1,4 @@ -import {MessageConfig} from './message-config'; +import { MessageConfig } from "./message-config"; export class ActiveMessage { private _config:MessageConfig; @@ -7,8 +7,8 @@ export class ActiveMessage { this._config = config; } - public onClick(callback:() => void) { + public onClick(callback:() => void):ActiveMessage { this._config.onClick.subscribe(() => callback()); return this; } -} \ No newline at end of file +} diff --git a/components/message/live-message.ts b/components/message/live-message.ts index d8c7e05cb..576c9f4b5 100644 --- a/components/message/live-message.ts +++ b/components/message/live-message.ts @@ -1,4 +1,4 @@ -import {MessageConfig} from './message-config'; +import { MessageConfig } from "./message-config"; export class LiveMessage { public config:MessageConfig; @@ -11,15 +11,15 @@ export class LiveMessage { this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.timeout); } - public onMouseEnter() { + public onMouseEnter():void { clearTimeout(this._displayTimeout); } - public onMouseLeave() { + public onMouseLeave():void { this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.extendedTimeout); } - public onTimedOut() { + public onTimedOut():void { console.log("bye"); } -} \ No newline at end of file +} diff --git a/components/message/message-config.ts b/components/message/message-config.ts index b2b1a6ad0..5ff580d88 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from '@angular/core'; +import { EventEmitter } from "@angular/core"; export type MessageState = "" | "info" | "success" | "warning" | "error"; @@ -8,7 +8,7 @@ export const MessageState = { Success: "success" as MessageState, Warning: "warning" as MessageState, Error: "error" as MessageState -} +}; export class MessageConfig { public text:string; @@ -42,4 +42,4 @@ export class MessageConfig { this.onClick = new EventEmitter(); } -} \ No newline at end of file +} diff --git a/components/message/message-container.ts b/components/message/message-container.ts index 91eb285dc..69ed753d3 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,10 +1,10 @@ -import {Component, EventEmitter, Input} from '@angular/core'; -import {MessageConfig} from './message-config'; -import {LiveMessage} from './live-message'; -import {ActiveMessage} from './active-message'; +import { Component, EventEmitter, Input } from "@angular/core"; +import { MessageConfig } from "./message-config"; +import { LiveMessage } from "./live-message"; +import { ActiveMessage } from "./active-message"; @Component({ - selector: 'sui-message-container', + selector: "sui-message-container", template: `
{{ message.config.header }}
@@ -26,11 +26,10 @@ export class SuiMessageContainer { this.maxShown = 10; } - public show(message:MessageConfig) { - if (this._messages.length == this.maxShown) { + public show(message:MessageConfig):ActiveMessage { + if (this._messages.length === this.maxShown) { this._queue.push(message); - } - else { + } else { const live = new LiveMessage(message); this._messages.push(live); @@ -38,4 +37,4 @@ export class SuiMessageContainer { return new ActiveMessage(message); } -} \ No newline at end of file +} From d5c0b77e5b9e69276fbd029abf52990604248706 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 05:25:58 +0100 Subject: [PATCH 03/24] feat(message): Migrated to generated components, similar to popup Messages are now completely controlled within the component, rather than trying to tack on functionality to the existing messages --- components/message/active-message.ts | 12 +- components/message/live-message.ts | 25 --- components/message/message-config.ts | 4 +- components/message/message-container.ts | 36 ++-- components/message/message-test.ts | 166 ++++++++++++++++++ components/message/message.module.ts | 4 + components/message/message.ts | 2 +- .../transition/transition-controller.ts | 47 +++-- demo/src/app/pages/test/test.page.html | 1 + demo/src/app/pages/test/test.page.ts | 7 +- package.json | 2 +- 11 files changed, 245 insertions(+), 61 deletions(-) delete mode 100644 components/message/live-message.ts create mode 100644 components/message/message-test.ts diff --git a/components/message/active-message.ts b/components/message/active-message.ts index c31afd6d1..03eb0da13 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -1,10 +1,20 @@ import { MessageConfig } from "./message-config"; +import { ComponentRef } from "@angular/core"; +import { SuiMessageTest } from "./message-test"; export class ActiveMessage { private _config:MessageConfig; + private _componentRef:ComponentRef; - constructor(config:MessageConfig) { + public get component():SuiMessageTest { + return this._componentRef.instance; + } + + constructor(config:MessageConfig, componentRef:ComponentRef) { this._config = config; + this._componentRef = componentRef; + + this.component.onDismiss.subscribe(() => this._componentRef.destroy()); } public onClick(callback:() => void):ActiveMessage { diff --git a/components/message/live-message.ts b/components/message/live-message.ts deleted file mode 100644 index 576c9f4b5..000000000 --- a/components/message/live-message.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MessageConfig } from "./message-config"; - -export class LiveMessage { - public config:MessageConfig; - - private _displayTimeout:number; - - constructor(config:MessageConfig) { - this.config = config; - - this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.timeout); - } - - public onMouseEnter():void { - clearTimeout(this._displayTimeout); - } - - public onMouseLeave():void { - this._displayTimeout = window.setTimeout(() => this.onTimedOut(), this.config.extendedTimeout); - } - - public onTimedOut():void { - console.log("bye"); - } -} diff --git a/components/message/message-config.ts b/components/message/message-config.ts index 5ff580d88..2822148b6 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -25,6 +25,7 @@ export class MessageConfig { public transitionOutDuration:number; public onClick:EventEmitter; + public onDismiss:EventEmitter; constructor(text:string, state?:MessageState, header?:string) { this.text = text; @@ -36,10 +37,11 @@ export class MessageConfig { this.closeButton = true; - this.transition = "scale"; + this.transition = "fade"; this.transitionInDuration = 200; this.transitionOutDuration = 1000; this.onClick = new EventEmitter(); + this.onDismiss = new EventEmitter(); } } diff --git a/components/message/message-container.ts b/components/message/message-container.ts index 69ed753d3..1743ee23b 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,40 +1,44 @@ -import { Component, EventEmitter, Input } from "@angular/core"; +import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef } from "@angular/core"; import { MessageConfig } from "./message-config"; -import { LiveMessage } from "./live-message"; import { ActiveMessage } from "./active-message"; +import { SuiMessageTest } from "./message-test"; @Component({ selector: "sui-message-container", template: ` - -
{{ message.config.header }}
-

{{ message.config.text }}

-
` }) export class SuiMessageContainer { - private _messages:LiveMessage[]; + private _messages:ActiveMessage[]; private _queue:MessageConfig[]; @Input() public maxShown:number; - constructor() { + constructor(private _viewContainerRef:ViewContainerRef, + private _componentFactoryResolver:ComponentFactoryResolver) { + this._messages = []; this._queue = []; this.maxShown = 10; } - public show(message:MessageConfig):ActiveMessage { - if (this._messages.length === this.maxShown) { - this._queue.push(message); - } else { - const live = new LiveMessage(message); + public show(config:MessageConfig):ActiveMessage { + // Resolve component factory for the `SuiPopup` component. + const factory = this._componentFactoryResolver.resolveComponentFactory(SuiMessageTest); + + // Generate a component using the view container reference and the previously resolved factory. + const componentRef = this._viewContainerRef.createComponent(factory); + + const message = componentRef.instance; + message.loadConfig(config); + message.show(); + + const active = new ActiveMessage(config, componentRef); - this._messages.push(live); - } + this._messages.push(active); - return new ActiveMessage(message); + return active; } } diff --git a/components/message/message-test.ts b/components/message/message-test.ts new file mode 100644 index 000000000..7799c54ef --- /dev/null +++ b/components/message/message-test.ts @@ -0,0 +1,166 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { TransitionController } from "../transition/transition-controller"; +import { MessageState, MessageConfig } from "./message-config"; +import { Transition, TransitionDirection } from "../transition/transition"; +import { HandledEvent } from "../util/util"; + +export interface IClasses { + [name:string]:true; +} + +@Component({ + selector: "sui-message", + template: ` +
+ + + + +
{{ header }}
+

{{ text }}

+
+
+` +}) +export class SuiMessageTest { + public isDynamic:boolean; + public isClosing:boolean; + + public text:string; + public header:string; + public state:MessageState; + + public timeout:number; + public extendedTimeout:number; + + @Input("isDismissable") + public closeButton:boolean; + + public transitionController:TransitionController; + + @Input() + public transition:string; + public transitionInDuration:number; + + @Input("transitionDuration") + public transitionOutDuration:number; + + private _displayTimeout:number; + + @Output("click") + public onClick:EventEmitter; + + @Output("dismiss") + public onDismiss:EventEmitter; + + @Input() + public class:string; + + public get classes():IClasses { + const classes:IClasses = {}; + classes[this.state] = true; + this.class.split(" ").forEach(c => classes[c] = true); + return classes; + } + + constructor() { + const config = new MessageConfig(""); + this.loadConfig(config); + + this.isDynamic = false; + this.class = ""; + this.transitionController = new TransitionController(false); + + this.show(); + } + + public loadConfig(config:MessageConfig):void { + this.isDynamic = true; + + this.text = config.text; + this.header = config.header; + this.state = config.state; + + this.timeout = config.timeout; + this.extendedTimeout = config.extendedTimeout; + + this.closeButton = config.closeButton; + + this.transition = config.transition; + this.transitionInDuration = config.transitionInDuration; + this.transitionOutDuration = config.transitionOutDuration; + + this.onClick = config.onClick; + this.onDismiss = config.onDismiss; + } + + public show():void { + this.transitionController.stopAll(); + this.transitionController.animate( + new Transition( + this.transition, + this.isDynamic ? 4000 : 0, + TransitionDirection.In, + () => { + if (this.isDynamic) { + this.beginTimer(this.timeout); + } + })); + } + + public dismiss(e?:HandledEvent):void { + if (e) { + e.eventHandled = true; + } + this.hide(); + } + + public hide():void { + this.isClosing = true; + + this.transitionController.stopAll(); + this.transitionController.animate( + new Transition( + this.transition, + this.transitionOutDuration, + TransitionDirection.Out, + () => { + this.isClosing = false; + this.onDismiss.emit(); + })); + } + + public beginTimer(timeout:number):void { + if (this.isDynamic) { + this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); + } + } + + public cancelTimer():void { + if (this.isDynamic) { + clearTimeout(this._displayTimeout); + + if (this.isClosing) { + this.isClosing = false; + + this.transitionController.cancel(); + } + } + } + + public onClicked(e:HandledEvent):void { + if (!e.eventHandled) { + this.cancelTimer(); + this.onClick.emit(); + } + } + + private onTimedOut():void { + this.hide(); + } +} diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 1bada230b..9ac1560dd 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -3,6 +3,7 @@ import { CommonModule } from "@angular/common"; import { SuiMessage, IMessage } from "./message"; import { SuiTransitionModule } from "../transition/transition.module"; import { SuiMessageContainer } from "./message-container"; +import { SuiMessageTest } from "./message-test"; @NgModule({ imports: [ @@ -11,13 +12,16 @@ import { SuiMessageContainer } from "./message-container"; ], declarations: [ SuiMessage, + SuiMessageTest, SuiMessageContainer ], exports: [ SuiMessage, + SuiMessageTest, SuiMessageContainer ], entryComponents: [ + SuiMessageTest, SuiMessageContainer ] }) diff --git a/components/message/message.ts b/components/message/message.ts index 737ca6937..b99abd573 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -7,7 +7,7 @@ export interface IMessage { } @Component({ - selector: "sui-message", + selector: "sui-test-message", template: `
diff --git a/components/transition/transition-controller.ts b/components/transition/transition-controller.ts index 7e014d509..85b8c0583 100644 --- a/components/transition/transition-controller.ts +++ b/components/transition/transition-controller.ts @@ -131,12 +131,10 @@ export class TransitionController { } // Wait the length of the animation before calling the complete callback. - this._animationTimeout = window.setTimeout(() => this.finishTransition(transition), transition.duration); + this._animationTimeout = window.setTimeout(() => this.finalizeTransition(transition), transition.duration); } - // Called when a transition has completed. - private finishTransition(transition:Transition):void { - // Unset the Semantic UI classes & styles for transitioning. + private completeTransition(transition:Transition):void { transition.classes.forEach(c => this._renderer.removeClass(this._element, c)); this._renderer.removeClass(this._element, `animating`); this._renderer.removeClass(this._element, transition.directionClass); @@ -144,6 +142,19 @@ export class TransitionController { this._renderer.removeStyle(this._element, `animationDuration`); this._renderer.removeStyle(this._element, `display`); + // Delete the transition from the queue. + this._queue.shift(); + this._isAnimating = false; + + this._changeDetector.markForCheck(); + + clearTimeout(this._animationTimeout); + } + + // Called when a transition has completed. + private finalizeTransition(transition:Transition):void { + this.completeTransition(transition); + if (transition.direction === TransitionDirection.In) { // If we have just animated in, we are now visible. this._isVisible = true; @@ -158,12 +169,6 @@ export class TransitionController { transition.onComplete(); } - // Delete the transition from the queue. - this._queue.shift(); - this._isAnimating = false; - - this._changeDetector.markForCheck(); - // Immediately attempt to perform another transition. this.performTransition(); } @@ -174,8 +179,21 @@ export class TransitionController { return; } - clearTimeout(this._animationTimeout); - this.finishTransition(transition); + this.finalizeTransition(transition); + } + + // Cancels the current transition, leaves the rest of the queue intact. + public cancel(transition:Transition = this._queueFirst):void { + if (!transition || !this._isAnimating) { + return; + } + + this.completeTransition(transition); + + if (transition.direction === TransitionDirection.In) { + // Return hidden class if we were originally transitioning in. + this._isHidden = true; + } } // Stops the current transition, and empties the queue. @@ -184,6 +202,11 @@ export class TransitionController { this.stop(); } + public cancelAll():void { + this.clearQueue(); + this.cancel(); + } + // Empties the transition queue but carries on with the current transition. public clearQueue():void { if (this.isAnimating) { diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index 70755f694..caf6629e1 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -7,6 +7,7 @@

Examples

+
\ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index 2883b8730..c21a4d46e 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -6,17 +6,16 @@ import { MessageConfig, MessageState } from "../../../../../components/message/m selector: "demo-page-test", templateUrl: "./test.page.html" }) -export class TestPage implements AfterViewInit { +export class TestPage { @ViewChild("messages") public messages:SuiMessageContainer; constructor() {} - public ngAfterViewInit():void { + public open():void { const message = new MessageConfig(null, MessageState.Default, "Hello, world!"); - - this.messages.show(message); + message.state = MessageState.Success; this.messages.show(message); } } diff --git a/package.json b/package.json index 170e670a8..bf0d3625e 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "lint": "npm run lint:lib & npm run lint:demo", "compile:lib": "ngc", "compile:lib:w": "ngc -w", - "compile:demo": "ng build --prod --aot=false --base-href=/ng2-semantic-ui/", + "compile:demo": "ng build --prod --aot=false --progress=false --base-href=/ng2-semantic-ui/", "compile": "npm run compile:lib && npm run compile:demo", "package:lib": "rollup -c", "build:lib": "npm run lint:lib && npm run compile:lib && npm run package:lib", From 9a614069c755469473d949c7c952a95dc23c6b6e Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 05:35:05 +0100 Subject: [PATCH 04/24] refactor: Removed old message and replaced with new one --- components/message/active-message.ts | 8 +- components/message/message-container.ts | 4 +- components/message/message-test.ts | 166 ------------------------ components/message/message.module.ts | 7 +- components/message/message.ts | 160 +++++++++++++++++++---- components/util/interfaces.ts | 3 + components/util/types.ts | 9 +- 7 files changed, 152 insertions(+), 205 deletions(-) delete mode 100644 components/message/message-test.ts create mode 100644 components/util/interfaces.ts diff --git a/components/message/active-message.ts b/components/message/active-message.ts index 03eb0da13..948ed510a 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -1,16 +1,16 @@ import { MessageConfig } from "./message-config"; import { ComponentRef } from "@angular/core"; -import { SuiMessageTest } from "./message-test"; +import { SuiMessage } from "./message"; export class ActiveMessage { private _config:MessageConfig; - private _componentRef:ComponentRef; + private _componentRef:ComponentRef; - public get component():SuiMessageTest { + public get component():SuiMessage { return this._componentRef.instance; } - constructor(config:MessageConfig, componentRef:ComponentRef) { + constructor(config:MessageConfig, componentRef:ComponentRef) { this._config = config; this._componentRef = componentRef; diff --git a/components/message/message-container.ts b/components/message/message-container.ts index 1743ee23b..2c9cc3c66 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef } from "@angular/core"; import { MessageConfig } from "./message-config"; import { ActiveMessage } from "./active-message"; -import { SuiMessageTest } from "./message-test"; +import { SuiMessage } from "./message"; @Component({ selector: "sui-message-container", @@ -26,7 +26,7 @@ export class SuiMessageContainer { public show(config:MessageConfig):ActiveMessage { // Resolve component factory for the `SuiPopup` component. - const factory = this._componentFactoryResolver.resolveComponentFactory(SuiMessageTest); + const factory = this._componentFactoryResolver.resolveComponentFactory(SuiMessage); // Generate a component using the view container reference and the previously resolved factory. const componentRef = this._viewContainerRef.createComponent(factory); diff --git a/components/message/message-test.ts b/components/message/message-test.ts deleted file mode 100644 index 7799c54ef..000000000 --- a/components/message/message-test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { TransitionController } from "../transition/transition-controller"; -import { MessageState, MessageConfig } from "./message-config"; -import { Transition, TransitionDirection } from "../transition/transition"; -import { HandledEvent } from "../util/util"; - -export interface IClasses { - [name:string]:true; -} - -@Component({ - selector: "sui-message", - template: ` -
- - - - -
{{ header }}
-

{{ text }}

-
-
-` -}) -export class SuiMessageTest { - public isDynamic:boolean; - public isClosing:boolean; - - public text:string; - public header:string; - public state:MessageState; - - public timeout:number; - public extendedTimeout:number; - - @Input("isDismissable") - public closeButton:boolean; - - public transitionController:TransitionController; - - @Input() - public transition:string; - public transitionInDuration:number; - - @Input("transitionDuration") - public transitionOutDuration:number; - - private _displayTimeout:number; - - @Output("click") - public onClick:EventEmitter; - - @Output("dismiss") - public onDismiss:EventEmitter; - - @Input() - public class:string; - - public get classes():IClasses { - const classes:IClasses = {}; - classes[this.state] = true; - this.class.split(" ").forEach(c => classes[c] = true); - return classes; - } - - constructor() { - const config = new MessageConfig(""); - this.loadConfig(config); - - this.isDynamic = false; - this.class = ""; - this.transitionController = new TransitionController(false); - - this.show(); - } - - public loadConfig(config:MessageConfig):void { - this.isDynamic = true; - - this.text = config.text; - this.header = config.header; - this.state = config.state; - - this.timeout = config.timeout; - this.extendedTimeout = config.extendedTimeout; - - this.closeButton = config.closeButton; - - this.transition = config.transition; - this.transitionInDuration = config.transitionInDuration; - this.transitionOutDuration = config.transitionOutDuration; - - this.onClick = config.onClick; - this.onDismiss = config.onDismiss; - } - - public show():void { - this.transitionController.stopAll(); - this.transitionController.animate( - new Transition( - this.transition, - this.isDynamic ? 4000 : 0, - TransitionDirection.In, - () => { - if (this.isDynamic) { - this.beginTimer(this.timeout); - } - })); - } - - public dismiss(e?:HandledEvent):void { - if (e) { - e.eventHandled = true; - } - this.hide(); - } - - public hide():void { - this.isClosing = true; - - this.transitionController.stopAll(); - this.transitionController.animate( - new Transition( - this.transition, - this.transitionOutDuration, - TransitionDirection.Out, - () => { - this.isClosing = false; - this.onDismiss.emit(); - })); - } - - public beginTimer(timeout:number):void { - if (this.isDynamic) { - this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); - } - } - - public cancelTimer():void { - if (this.isDynamic) { - clearTimeout(this._displayTimeout); - - if (this.isClosing) { - this.isClosing = false; - - this.transitionController.cancel(); - } - } - } - - public onClicked(e:HandledEvent):void { - if (!e.eventHandled) { - this.cancelTimer(); - this.onClick.emit(); - } - } - - private onTimedOut():void { - this.hide(); - } -} diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 9ac1560dd..649da62e0 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -1,9 +1,8 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; -import { SuiMessage, IMessage } from "./message"; import { SuiTransitionModule } from "../transition/transition.module"; import { SuiMessageContainer } from "./message-container"; -import { SuiMessageTest } from "./message-test"; +import { SuiMessage, IMessage } from "./message"; @NgModule({ imports: [ @@ -12,16 +11,14 @@ import { SuiMessageTest } from "./message-test"; ], declarations: [ SuiMessage, - SuiMessageTest, SuiMessageContainer ], exports: [ SuiMessage, - SuiMessageTest, SuiMessageContainer ], entryComponents: [ - SuiMessageTest, + SuiMessage, SuiMessageContainer ] }) diff --git a/components/message/message.ts b/components/message/message.ts index b99abd573..8645f4a20 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -1,57 +1,167 @@ -import { Component, Input, Output, EventEmitter, ElementRef, Renderer2, AfterViewInit } from "@angular/core"; -import { SuiTransition, Transition, TransitionDirection } from "../transition/transition"; +import { Component, EventEmitter, Input, Output } from "@angular/core"; import { TransitionController } from "../transition/transition-controller"; +import { MessageState, MessageConfig } from "./message-config"; +import { Transition, TransitionDirection } from "../transition/transition"; +import { HandledEvent } from "../util/util"; +import { IDynamicClasslist } from "../util/interfaces"; export interface IMessage { dismiss():void; } @Component({ - selector: "sui-test-message", + selector: "sui-message", template: ` -
- +
+ + + +
{{ header }}
+

{{ text }}

+
` }) export class SuiMessage implements IMessage { - @Input() - public isDismissable:boolean; + public isDynamic:boolean; + public isClosing:boolean; - @Output("dismiss") - public onDismiss:EventEmitter; + public text:string; + public header:string; + public state:MessageState; + + public timeout:number; + public extendedTimeout:number; - public isDismissed:boolean; + @Input("isDismissable") + public closeButton:boolean; public transitionController:TransitionController; @Input() public transition:string; + public transitionInDuration:number; - @Input() - public transitionDuration:number; + @Input("transitionDuration") + public transitionOutDuration:number; + + private _displayTimeout:number; + + @Output("click") + public onClick:EventEmitter; + + @Output("dismiss") + public onDismiss:EventEmitter; @Input("class") - public class:string; + public classes:string; + + public get dynamicClasses():IDynamicClasslist { + const classes:IDynamicClasslist = {}; + classes[this.state] = true; + this.classes.split(" ").forEach(c => classes[c] = true); + return classes; + } constructor() { - this.isDismissable = true; - this.onDismiss = new EventEmitter(); + const config = new MessageConfig(""); + this.loadConfig(config); + + this.isDynamic = false; + this.classes = ""; + this.transitionController = new TransitionController(false); + + this.show(); + } + + public loadConfig(config:MessageConfig):void { + this.isDynamic = true; + + this.text = config.text; + this.header = config.header; + this.state = config.state; - this.isDismissed = false; + this.timeout = config.timeout; + this.extendedTimeout = config.extendedTimeout; - this.transitionController = new TransitionController(); - this.transition = "fade"; - this.transitionDuration = 300; + this.closeButton = config.closeButton; + + this.transition = config.transition; + this.transitionInDuration = config.transitionInDuration; + this.transitionOutDuration = config.transitionOutDuration; + + this.onClick = config.onClick; + this.onDismiss = config.onDismiss; + } + + public show():void { + this.transitionController.stopAll(); + this.transitionController.animate( + new Transition( + this.transition, + this.isDynamic ? this.transitionInDuration : 0, + TransitionDirection.In, + () => { + if (this.isDynamic) { + this.beginTimer(this.timeout); + } + })); + } + + public dismiss(e?:HandledEvent):void { + if (e) { + e.eventHandled = true; + } + this.hide(); + } + + public hide():void { + this.isClosing = true; + + this.transitionController.stopAll(); + this.transitionController.animate( + new Transition( + this.transition, + this.transitionOutDuration, + TransitionDirection.Out, + () => { + this.isClosing = false; + this.onDismiss.emit(); + })); + } + + public beginTimer(timeout:number):void { + if (this.isDynamic) { + this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); + } + } + + public cancelTimer():void { + if (this.isDynamic) { + clearTimeout(this._displayTimeout); + + if (this.isClosing) { + this.isClosing = false; + + this.transitionController.cancel(); + } + } + } - this.class = ""; + public onClicked(e:HandledEvent):void { + if (!e.eventHandled) { + this.cancelTimer(); + this.onClick.emit(); + } } - public dismiss():void { - this.transitionController.animate(new Transition(this.transition, this.transitionDuration, TransitionDirection.Out, () => { - this.isDismissed = true; - this.onDismiss.emit(this); - })); + private onTimedOut():void { + this.hide(); } } diff --git a/components/util/interfaces.ts b/components/util/interfaces.ts new file mode 100644 index 000000000..9ef7521ef --- /dev/null +++ b/components/util/interfaces.ts @@ -0,0 +1,3 @@ +export interface IDynamicClasslist { + [name:string]:true; +} diff --git a/components/util/types.ts b/components/util/types.ts index 02848253b..cb5f39f29 100644 --- a/components/util/types.ts +++ b/components/util/types.ts @@ -1,4 +1,6 @@ -export type SuiColor = "" | "red" | "orange" | "yellow" | "olive" | "green" | "teal" | "blue" | "violet" | "purple" | "pink" | "brown" | "black"; +export type SuiColor = "" | "red" | "orange" | "yellow" | "olive" | + "green" | "teal" | "blue" | "violet" | + "purple" | "pink" | "brown" | "black"; export const SuiColor = { Default: "" as SuiColor, @@ -14,7 +16,7 @@ export const SuiColor = { Pink: "pink" as SuiColor, Brown: "brown" as SuiColor, Black: "black" as SuiColor -} +}; export type SuiSize = "mini" | "tiny" | "small" | "" | "large" | "big" | "huge" | "massive"; @@ -27,4 +29,5 @@ export const SuiSize = { Big: "big" as SuiSize, Huge: "huge" as SuiSize, Massive: "massive" as SuiSize -} \ No newline at end of file +}; + From 0e7dc1236e5a2b2a170a56b1b3e06ad23f402a7a Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 06:20:03 +0100 Subject: [PATCH 05/24] feat: Created internal component factory service --- components/message/message-container.ts | 4 +- components/message/message.module.ts | 4 +- components/modal/modal-config.ts | 6 +-- components/modal/modal.module.ts | 4 +- components/modal/modal.service.ts | 37 +++++-------- components/sui.module.ts | 5 +- components/util/component-factory.service.ts | 55 ++++++++++++++++++++ components/util/{types.ts => enums.ts} | 0 components/util/util.module.ts | 11 ++++ 9 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 components/util/component-factory.service.ts rename components/util/{types.ts => enums.ts} (100%) create mode 100644 components/util/util.module.ts diff --git a/components/message/message-container.ts b/components/message/message-container.ts index 2c9cc3c66..dd2e99332 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainer import { MessageConfig } from "./message-config"; import { ActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; +import { SuiComponentFactory } from "../util/component-factory.service"; @Component({ selector: "sui-message-container", @@ -15,7 +16,8 @@ export class SuiMessageContainer { @Input() public maxShown:number; - constructor(private _viewContainerRef:ViewContainerRef, + constructor(private _componentGenerator:SuiComponentFactory, + private _viewContainerRef:ViewContainerRef, private _componentFactoryResolver:ComponentFactoryResolver) { this._messages = []; diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 649da62e0..30b9baa12 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -3,11 +3,13 @@ import { CommonModule } from "@angular/common"; import { SuiTransitionModule } from "../transition/transition.module"; import { SuiMessageContainer } from "./message-container"; import { SuiMessage, IMessage } from "./message"; +import { SuiUtilityModule } from "../util/util.module"; @NgModule({ imports: [ CommonModule, - SuiTransitionModule + SuiTransitionModule, + SuiUtilityModule ], declarations: [ SuiMessage, diff --git a/components/modal/modal-config.ts b/components/modal/modal-config.ts index ee0ba4c15..90ccd4eb2 100644 --- a/components/modal/modal-config.ts +++ b/components/modal/modal-config.ts @@ -1,4 +1,4 @@ -import { TemplateRef } from "@angular/core"; +import { TemplateRef, Type } from "@angular/core"; import { ModalControls, ModalResult } from "./modal-controls"; import { ModalTemplate } from "./modal-template"; @@ -64,9 +64,9 @@ export class TemplateModalConfig extends ModalConfig extends ModalConfig { - public component:Function; + public component:Type; - constructor(component:Function, context:T = null, isClosable:boolean = true) { + constructor(component:Type, context:T = null, isClosable:boolean = true) { super(context, isClosable); this.component = component; diff --git a/components/modal/modal.module.ts b/components/modal/modal.module.ts index e0f950045..3196f4302 100644 --- a/components/modal/modal.module.ts +++ b/components/modal/modal.module.ts @@ -8,12 +8,14 @@ import { Modal, ModalResult, ModalControls } from "./modal-controls"; import { ActiveModal } from "./active-modal"; import { ModalConfig, TemplateModalConfig, ComponentModalConfig, ModalSize } from "./modal-config"; import { ModalTemplate } from "./modal-template"; +import { SuiUtilityModule } from "../util/util.module"; @NgModule({ imports: [ CommonModule, SuiDimmerModule, - SuiTransitionModule + SuiTransitionModule, + SuiUtilityModule ], declarations: [ SuiModal diff --git a/components/modal/modal.service.ts b/components/modal/modal.service.ts index e10e71713..704bdcd13 100644 --- a/components/modal/modal.service.ts +++ b/components/modal/modal.service.ts @@ -3,50 +3,42 @@ import { ModalConfig, TemplateModalConfig, ComponentModalConfig } from "./modal- import { SuiModal } from "./modal"; import { Modal } from "./modal-controls"; import { ActiveModal } from "./active-modal"; +import { SuiComponentFactory } from "../util/component-factory.service"; @Injectable() export class SuiModalService { - constructor(private _applicationRef:ApplicationRef, - private _componentFactoryResolver:ComponentFactoryResolver, - private _injector:Injector) {} + constructor(private _componentFactory:SuiComponentFactory) {} public open(modal:ModalConfig):ActiveModal { - // Resolve factory for creating `SuiModal` components. - const factory = this._componentFactoryResolver.resolveComponentFactory>(SuiModal); + // Generate the modal component to be shown. + const componentRef = this._componentFactory.createComponent>(SuiModal); - // Generate a component using the injector and the previously resolved factory. - const componentRef = factory.create(this._injector); // Shorthand for the created modal component instance. const modalComponent = componentRef.instance; if (modal instanceof TemplateModalConfig) { // Inject the template into the view. - componentRef.instance.templateSibling.createEmbeddedView(modal.template, { + this._componentFactory.createView(modalComponent.templateSibling, modal.template, { // `let-context` $implicit: modal.context, // `let-modal="modal"` modal: componentRef.instance.controls }); } else if (modal instanceof ComponentModalConfig) { - // Resolve factory for creating a new instance of the provided component. - const contentComponentFactory = this._componentFactoryResolver.resolveComponentFactory(modal.component as Type<{}>); - - // Provide an instance of `Modal` for the injector, to be used in the component constructor. - const modalContentInjector = ReflectiveInjector.resolveAndCreate( + // Generate the component to be used as the modal content, + // injecting an instance of `Modal` to be used in the component constructor. + const contentComponentRef = this._componentFactory.createComponent( + modal.component, [ { provide: Modal, useValue: new Modal(modalComponent.controls, modal.context) } - ], - this._injector + ] ); - // Generate a component using the custom injector and the previously resolved factory. - const contentComponentRef = contentComponentFactory.create(modalContentInjector); - // Insert the new component into the content of the modal. - modalComponent.templateSibling.insert(contentComponentRef.hostView); + this._componentFactory.attachToView(modalComponent.templateSibling, contentComponentRef); // Shorthand for access to the content component's DOM element. const contentElement = contentComponentRef.location.nativeElement as Element; @@ -65,11 +57,8 @@ export class SuiModalService { const templateElement = modalComponent.templateSibling.element.nativeElement as Element; templateElement.remove(); - // Attach the new modal component to the application. - this._applicationRef.attachView(componentRef.hostView); - - // Move the new modal component DOM to the document body. - document.querySelector("body").appendChild(componentRef.location.nativeElement); + this._componentFactory.attachToApplication(componentRef); + this._componentFactory.moveToDocumentBody(componentRef); // Initialise the generated modal with the provided config. modalComponent.loadConfig(modal); diff --git a/components/sui.module.ts b/components/sui.module.ts index ae1cd64f3..b7d8fcbdc 100644 --- a/components/sui.module.ts +++ b/components/sui.module.ts @@ -15,6 +15,7 @@ import { SuiSidebarModule } from "./sidebar/sidebar.module"; import { SuiTabsModule } from "./tabs/tab.module"; import { SuiSelectModule } from "./select/select.module"; import { SuiTransitionModule } from "./transition/transition.module"; +import { SuiUtilityModule } from "./util/util.module"; @NgModule({ exports: [ @@ -32,7 +33,9 @@ import { SuiTransitionModule } from "./transition/transition.module"; SuiSelectModule, SuiSidebarModule, SuiTabsModule, - SuiTransitionModule + SuiTransitionModule, + + SuiUtilityModule ] }) export class SuiModule {} diff --git a/components/util/component-factory.service.ts b/components/util/component-factory.service.ts new file mode 100644 index 000000000..49d7486ab --- /dev/null +++ b/components/util/component-factory.service.ts @@ -0,0 +1,55 @@ +import { + Injectable, ApplicationRef, ComponentFactoryResolver, Injector, ComponentRef, + ReflectiveInjector, Provider, Type, ViewContainerRef, TemplateRef +} from "@angular/core"; + +export interface IImplicitContext { + $implicit?:T; +} + +@Injectable() +export class SuiComponentFactory { + constructor(private _applicationRef:ApplicationRef, + private _componentFactoryResolver:ComponentFactoryResolver, + private _injector:Injector) {} + + public createComponent(type:Type, providers:Provider[] = []):ComponentRef { + // Resolve a factory for creating components of type `type`. + const factory = this._componentFactoryResolver.resolveComponentFactory(type as Type); + + // Resolve and create an injector with the specified providers. + const injector = ReflectiveInjector.resolveAndCreate( + providers, + this._injector + ); + + // Create a component using the previously resolved factory & injector. + const componentRef = factory.create(injector); + + return componentRef; + } + + public createView>(viewContainer:ViewContainerRef, template:TemplateRef, context:U):void { + viewContainer.createEmbeddedView(template, context); + } + + // Inserts the component into the specified view container. + public attachToView(viewContainer:ViewContainerRef, componentRef:ComponentRef):void { + viewContainer.insert(componentRef.hostView); + } + + // Inserts the component in the root application node. + public attachToApplication(componentRef:ComponentRef):void { + this._applicationRef.attachView(componentRef.hostView); + } + + // Moves the component to the specified DOM element. + public moveToElement(element:Element, componentRef:ComponentRef):void { + element.appendChild(componentRef.location.nativeElement); + } + + // Moves the component to the document body. + public moveToDocumentBody(componentRef:ComponentRef):void { + this.moveToElement(document.querySelector("body"), componentRef); + } +} diff --git a/components/util/types.ts b/components/util/enums.ts similarity index 100% rename from components/util/types.ts rename to components/util/enums.ts diff --git a/components/util/util.module.ts b/components/util/util.module.ts new file mode 100644 index 000000000..818a07adc --- /dev/null +++ b/components/util/util.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { SuiComponentFactory } from "./component-factory.service"; + +@NgModule({ + imports: [CommonModule], + providers: [ + SuiComponentFactory + ] +}) +export class SuiUtilityModule {} From 4b27513c2771b1d2e54ce422229bb30ad2798e45 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 06:24:13 +0100 Subject: [PATCH 06/24] refactor(popup): Moved to new component factory service --- components/modal/modal.module.ts | 2 +- components/popup/popup.directive.ts | 16 +++++++--------- components/popup/popup.module.ts | 4 +++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/modal/modal.module.ts b/components/modal/modal.module.ts index 3196f4302..a740e5958 100644 --- a/components/modal/modal.module.ts +++ b/components/modal/modal.module.ts @@ -2,13 +2,13 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { SuiDimmerModule } from "../dimmer/dimmer.module"; import { SuiTransitionModule } from "../transition/transition.module"; +import { SuiUtilityModule } from "../util/util.module"; import { SuiModalService } from "./modal.service"; import { SuiModal } from "./modal"; import { Modal, ModalResult, ModalControls } from "./modal-controls"; import { ActiveModal } from "./active-modal"; import { ModalConfig, TemplateModalConfig, ComponentModalConfig, ModalSize } from "./modal-config"; import { ModalTemplate } from "./modal-template"; -import { SuiUtilityModule } from "../util/util.module"; @NgModule({ imports: [ diff --git a/components/popup/popup.directive.ts b/components/popup/popup.directive.ts index b24ddf567..2427e12ad 100644 --- a/components/popup/popup.directive.ts +++ b/components/popup/popup.directive.ts @@ -7,6 +7,7 @@ import { PositioningPlacement } from "../util/positioning.service"; import { ITemplateRefContext, parseBooleanAttribute } from "../util/util"; import { PopupConfig, IPopupConfig, PopupTrigger } from "./popup-config"; import { SuiPopupConfig } from "./popup.service"; +import { SuiComponentFactory } from "../util/component-factory.service"; export interface IPopup { open():void; @@ -92,8 +93,7 @@ export class SuiPopupDirective implements IPopup { private _openingTimeout:number; constructor(private _element:ElementRef, - private _viewContainerRef:ViewContainerRef, - private _componentFactoryResolver:ComponentFactoryResolver, + private _componentFactory:SuiComponentFactory, popupDefaults:SuiPopupConfig) { this.config = new PopupConfig(popupDefaults); @@ -107,15 +107,13 @@ export class SuiPopupDirective implements IPopup { this._openingTimeout = window.setTimeout( () => { if (!this._componentRef) { - // Resolve component factory for the `SuiPopup` component. - const factory = this._componentFactoryResolver.resolveComponentFactory(SuiPopup); - - // Generate a component using the view container reference and the previously resolved factory. - this._componentRef = this._viewContainerRef.createComponent(factory); + // Generate a new SuiPopup component and attach it to the application view. + this._componentRef = this._componentFactory.createComponent(SuiPopup); + this._componentFactory.attachToApplication(this._componentRef); // If there is a template, inject it into the view. if (this.config.template) { - this._popup.templateSibling.createEmbeddedView(this.config.template, { $implicit: this._popup }); + this._componentFactory.createView(this._popup.templateSibling, this.config.template, { $implicit: this._popup }); } // Configure popup with provided config, and attach a reference to the anchor element. @@ -123,7 +121,7 @@ export class SuiPopupDirective implements IPopup { this._popup.anchor = this._element; // Move the generated element to the body to avoid any positioning issues. - document.querySelector("body").appendChild(this._componentRef.location.nativeElement); + this._componentFactory.moveToDocumentBody(this._componentRef); // When the popup is closed (onClose fires on animation complete), this._popup.onClose.subscribe(() => { diff --git a/components/popup/popup.module.ts b/components/popup/popup.module.ts index c10182079..a8183039e 100644 --- a/components/popup/popup.module.ts +++ b/components/popup/popup.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { SuiTransitionModule } from "../transition/transition.module"; +import { SuiUtilityModule } from "../util/util.module"; import { SuiPopupDirective, IPopup } from "./popup.directive"; import { SuiPopup } from "./popup"; import { SuiPopupArrow } from "./popup-arrow"; @@ -11,7 +12,8 @@ import { SuiPopupConfig } from "./popup.service"; @NgModule({ imports: [ CommonModule, - SuiTransitionModule + SuiTransitionModule, + SuiUtilityModule ], declarations: [ SuiPopupDirective, From 5fdd91aebb614903f78685cc3810d5d8b96afa81 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 06:33:24 +0100 Subject: [PATCH 07/24] refactor(message): Moved message container to component factory service --- components/message/message-container.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/components/message/message-container.ts b/components/message/message-container.ts index dd2e99332..e80d7cec8 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -16,9 +16,8 @@ export class SuiMessageContainer { @Input() public maxShown:number; - constructor(private _componentGenerator:SuiComponentFactory, - private _viewContainerRef:ViewContainerRef, - private _componentFactoryResolver:ComponentFactoryResolver) { + constructor(private _componentFactory:SuiComponentFactory, + private _viewContainerRef:ViewContainerRef) { this._messages = []; this._queue = []; @@ -27,11 +26,8 @@ export class SuiMessageContainer { } public show(config:MessageConfig):ActiveMessage { - // Resolve component factory for the `SuiPopup` component. - const factory = this._componentFactoryResolver.resolveComponentFactory(SuiMessage); - - // Generate a component using the view container reference and the previously resolved factory. - const componentRef = this._viewContainerRef.createComponent(factory); + const componentRef = this._componentFactory.createComponent(SuiMessage); + this._componentFactory.attachToView(this._viewContainerRef, componentRef); const message = componentRef.instance; message.loadConfig(config); From 602d1214f1639ac27d0ec20cc8e7ac643968ffe0 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 06:48:31 +0100 Subject: [PATCH 08/24] feat: Added initial styles to message container --- components/message/message-container.ts | 26 ++++++++++++++++---- components/util/component-factory.service.ts | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/components/message/message-container.ts b/components/message/message-container.ts index e80d7cec8..aef515c16 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef } from "@angular/core"; +import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef, ViewChild } from "@angular/core"; import { MessageConfig } from "./message-config"; import { ActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; @@ -7,7 +7,19 @@ import { SuiComponentFactory } from "../util/component-factory.service"; @Component({ selector: "sui-message-container", template: ` -` +
+
+`, + styles: [` +:host >>> sui-message { + display: block; + margin-bottom: 1rem; +} + +:host >>> sui-message:last-of-type { + margin-bottom: 0; +} +`] }) export class SuiMessageContainer { private _messages:ActiveMessage[]; @@ -16,9 +28,13 @@ export class SuiMessageContainer { @Input() public maxShown:number; - constructor(private _componentFactory:SuiComponentFactory, - private _viewContainerRef:ViewContainerRef) { + @ViewChild("top", { read: ViewContainerRef }) + public topContainer:ViewContainerRef; + + @ViewChild("bottom", { read: ViewContainerRef }) + public bottomContainer:ViewContainerRef; + constructor(private _componentFactory:SuiComponentFactory) { this._messages = []; this._queue = []; @@ -27,7 +43,7 @@ export class SuiMessageContainer { public show(config:MessageConfig):ActiveMessage { const componentRef = this._componentFactory.createComponent(SuiMessage); - this._componentFactory.attachToView(this._viewContainerRef, componentRef); + this._componentFactory.attachToView(this.topContainer, componentRef); const message = componentRef.instance; message.loadConfig(config); diff --git a/components/util/component-factory.service.ts b/components/util/component-factory.service.ts index 49d7486ab..d26c9db46 100644 --- a/components/util/component-factory.service.ts +++ b/components/util/component-factory.service.ts @@ -35,7 +35,7 @@ export class SuiComponentFactory { // Inserts the component into the specified view container. public attachToView(viewContainer:ViewContainerRef, componentRef:ComponentRef):void { - viewContainer.insert(componentRef.hostView); + viewContainer.insert(componentRef.hostView, 0); } // Inserts the component in the root application node. From 5a2ca1351a8142419af36aa5d437a6528fed3447 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 07:11:16 +0100 Subject: [PATCH 09/24] feat(message): Added queue functionality --- components/message/active-message.ts | 20 +++++++++---- components/message/message-container.ts | 40 ++++++++++++++++++++----- demo/src/app/pages/test/test.page.ts | 2 +- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/components/message/active-message.ts b/components/message/active-message.ts index 948ed510a..9fa5ffea0 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -2,23 +2,33 @@ import { MessageConfig } from "./message-config"; import { ComponentRef } from "@angular/core"; import { SuiMessage } from "./message"; -export class ActiveMessage { +export abstract class SuiActiveMessage { + public abstract onClick(callback:() => void):SuiActiveMessage; + public abstract onDismiss(callback:() => void):SuiActiveMessage; +} + +export class ActiveMessage implements SuiActiveMessage { private _config:MessageConfig; - private _componentRef:ComponentRef; + public componentRef:ComponentRef; public get component():SuiMessage { - return this._componentRef.instance; + return this.componentRef.instance; } constructor(config:MessageConfig, componentRef:ComponentRef) { this._config = config; - this._componentRef = componentRef; + this.componentRef = componentRef; - this.component.onDismiss.subscribe(() => this._componentRef.destroy()); + this.component.onDismiss.subscribe(() => this.componentRef.destroy()); } public onClick(callback:() => void):ActiveMessage { this._config.onClick.subscribe(() => callback()); return this; } + + public onDismiss(callback:() => void):ActiveMessage { + this._config.onDismiss.subscribe(() => callback()); + return this; + } } diff --git a/components/message/message-container.ts b/components/message/message-container.ts index aef515c16..bfccafb88 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef, ViewChild } from "@angular/core"; import { MessageConfig } from "./message-config"; -import { ActiveMessage } from "./active-message"; +import { ActiveMessage, SuiActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; import { SuiComponentFactory } from "../util/component-factory.service"; @@ -11,6 +11,10 @@ import { SuiComponentFactory } from "../util/component-factory.service";
`, styles: [` +:host { + display: block; +} + :host >>> sui-message { display: block; margin-bottom: 1rem; @@ -23,7 +27,7 @@ import { SuiComponentFactory } from "../util/component-factory.service"; }) export class SuiMessageContainer { private _messages:ActiveMessage[]; - private _queue:MessageConfig[]; + private _queue:ActiveMessage[]; @Input() public maxShown:number; @@ -38,21 +42,41 @@ export class SuiMessageContainer { this._messages = []; this._queue = []; - this.maxShown = 10; + this.maxShown = 7; } - public show(config:MessageConfig):ActiveMessage { + public show(config:MessageConfig):SuiActiveMessage { const componentRef = this._componentFactory.createComponent(SuiMessage); - this._componentFactory.attachToView(this.topContainer, componentRef); const message = componentRef.instance; message.loadConfig(config); - message.show(); - const active = new ActiveMessage(config, componentRef); + const active = new ActiveMessage(config, componentRef) + .onDismiss(() => this.onMessageClose(active)); - this._messages.push(active); + if (this._messages.length < this.maxShown) { + this.open(active); + } else { + this._queue.push(active); + } return active; } + + private open(message:ActiveMessage):void { + this._messages.push(message); + + this._componentFactory.attachToView(this.topContainer, message.componentRef); + message.component.show(); + } + + private onMessageClose(message:ActiveMessage):void { + this._messages = this._messages.filter(m => m !== message); + + if (this._queue.length > 0) { + const queued = this._queue.shift(); + + this.open(queued); + } + } } diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index c21a4d46e..fbcfad938 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -14,7 +14,7 @@ export class TestPage { constructor() {} public open():void { - const message = new MessageConfig(null, MessageState.Default, "Hello, world!"); + const message = new MessageConfig(null, MessageState.Default, Date.now().toString()); message.state = MessageState.Success; this.messages.show(message); } From 020f74e4b1325916f265953b9fe993432f9bc382 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 07:27:25 +0100 Subject: [PATCH 10/24] feat(message): Removed reliance on `@ViewChild` --- components/message/message-config.ts | 2 +- components/message/message-container.ts | 16 ++++++++++++---- components/message/message-controller.ts | 20 ++++++++++++++++++++ demo/src/app/pages/test/test.page.html | 2 +- demo/src/app/pages/test/test.page.ts | 12 +++++++----- 5 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 components/message/message-controller.ts diff --git a/components/message/message-config.ts b/components/message/message-config.ts index 2822148b6..c066280e8 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -38,7 +38,7 @@ export class MessageConfig { this.closeButton = true; this.transition = "fade"; - this.transitionInDuration = 200; + this.transitionInDuration = 400; this.transitionOutDuration = 1000; this.onClick = new EventEmitter(); diff --git a/components/message/message-container.ts b/components/message/message-container.ts index bfccafb88..f52626ecc 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -3,6 +3,7 @@ import { MessageConfig } from "./message-config"; import { ActiveMessage, SuiActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; import { SuiComponentFactory } from "../util/component-factory.service"; +import { MessageController } from "./message-controller"; @Component({ selector: "sui-message-container", @@ -32,6 +33,11 @@ export class SuiMessageContainer { @Input() public maxShown:number; + @Input() + public set controller(controller:MessageController) { + controller.registerContainer(this); + } + @ViewChild("top", { read: ViewContainerRef }) public topContainer:ViewContainerRef; @@ -47,9 +53,7 @@ export class SuiMessageContainer { public show(config:MessageConfig):SuiActiveMessage { const componentRef = this._componentFactory.createComponent(SuiMessage); - - const message = componentRef.instance; - message.loadConfig(config); + componentRef.instance.loadConfig(config); const active = new ActiveMessage(config, componentRef) .onDismiss(() => this.onMessageClose(active)); @@ -57,7 +61,7 @@ export class SuiMessageContainer { if (this._messages.length < this.maxShown) { this.open(active); } else { - this._queue.push(active); + this.queue(active); } return active; @@ -70,6 +74,10 @@ export class SuiMessageContainer { message.component.show(); } + private queue(message:ActiveMessage):void { + this._queue.push(message); + } + private onMessageClose(message:ActiveMessage):void { this._messages = this._messages.filter(m => m !== message); diff --git a/components/message/message-controller.ts b/components/message/message-controller.ts new file mode 100644 index 000000000..6abf39427 --- /dev/null +++ b/components/message/message-controller.ts @@ -0,0 +1,20 @@ +import { MessageConfig } from "./message-config"; +import { SuiActiveMessage } from "./active-message"; +import { SuiMessageContainer } from "./message-container"; + + +export class MessageController { + private _container:SuiMessageContainer; + + public registerContainer(container:SuiMessageContainer):void { + this._container = container; + } + + public show(config:MessageConfig):SuiActiveMessage { + if (!this._container) { + throw new Error("You must pass this controller to a message container."); + } + + return this._container.show(config); + } +} diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index caf6629e1..ed646a8b1 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -8,6 +8,6 @@

Examples

- +
\ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index fbcfad938..a663167f7 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -1,21 +1,23 @@ import { Component, AfterViewInit, ViewChild, TemplateRef } from "@angular/core"; import { SuiMessageContainer } from "../../../../../components/message/message-container"; import { MessageConfig, MessageState } from "../../../../../components/message/message-config"; +import { MessageController } from "../../../../../components/message/message-controller"; @Component({ selector: "demo-page-test", templateUrl: "./test.page.html" }) export class TestPage { + public controller:MessageController; - @ViewChild("messages") - public messages:SuiMessageContainer; - - constructor() {} + constructor() { + this.controller = new MessageController(); + } public open():void { const message = new MessageConfig(null, MessageState.Default, Date.now().toString()); message.state = MessageState.Success; - this.messages.show(message); + + this.controller.show(message); } } From 9c150fc217c0e52ade8630aad843be3188c57449 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 07:31:11 +0100 Subject: [PATCH 11/24] feat(modal): Internal ActiveModal functionality now hidden from consumer --- components/modal/active-modal.ts | 12 +++++++++++- components/modal/modal.module.ts | 4 ++-- components/modal/modal.service.ts | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/components/modal/active-modal.ts b/components/modal/active-modal.ts index 822187996..cf41a0ce7 100644 --- a/components/modal/active-modal.ts +++ b/components/modal/active-modal.ts @@ -2,8 +2,18 @@ import { ModalConfig } from "./modal-config"; import { SuiModal } from "./modal"; import { ComponentRef } from "@angular/core"; +export abstract class SuiActiveModal { + public abstract onApprove(callback:(result:U) => void):SuiActiveModal; + public abstract onDeny(callback:(result:V) => void):SuiActiveModal; + + public abstract approve(result:U):void; + public abstract deny(result:V):void; + + public abstract destroy():void; +} + // Helper class to support method chaining when calling `SuiModalService.open(...)`. -export class ActiveModal { +export class ActiveModal implements SuiActiveModal { private _config:ModalConfig; private _componentRef:ComponentRef>; diff --git a/components/modal/modal.module.ts b/components/modal/modal.module.ts index a740e5958..6bf85aea8 100644 --- a/components/modal/modal.module.ts +++ b/components/modal/modal.module.ts @@ -6,7 +6,7 @@ import { SuiUtilityModule } from "../util/util.module"; import { SuiModalService } from "./modal.service"; import { SuiModal } from "./modal"; import { Modal, ModalResult, ModalControls } from "./modal-controls"; -import { ActiveModal } from "./active-modal"; +import { ActiveModal, SuiActiveModal } from "./active-modal"; import { ModalConfig, TemplateModalConfig, ComponentModalConfig, ModalSize } from "./modal-config"; import { ModalTemplate } from "./modal-template"; @@ -37,7 +37,7 @@ export { Modal as SuiModal, ModalResult, ModalControls, - ActiveModal as SuiActiveModal, + SuiActiveModal, ModalConfig, TemplateModalConfig, ComponentModalConfig, diff --git a/components/modal/modal.service.ts b/components/modal/modal.service.ts index 704bdcd13..300161eb3 100644 --- a/components/modal/modal.service.ts +++ b/components/modal/modal.service.ts @@ -2,14 +2,14 @@ import { Injectable, ApplicationRef, ComponentFactoryResolver, Injector, Type, R import { ModalConfig, TemplateModalConfig, ComponentModalConfig } from "./modal-config"; import { SuiModal } from "./modal"; import { Modal } from "./modal-controls"; -import { ActiveModal } from "./active-modal"; +import { ActiveModal, SuiActiveModal } from "./active-modal"; import { SuiComponentFactory } from "../util/component-factory.service"; @Injectable() export class SuiModalService { constructor(private _componentFactory:SuiComponentFactory) {} - public open(modal:ModalConfig):ActiveModal { + public open(modal:ModalConfig):SuiActiveModal { // Generate the modal component to be shown. const componentRef = this._componentFactory.createComponent>(SuiModal); From 772cf680fb47703b4eb1b37cd79e31b1a68fb14c Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 07:35:13 +0100 Subject: [PATCH 12/24] feat(message): Renamed isDismissable to hasDismissButton BREAKING CHANGE --- components/message/message-config.ts | 4 ++-- components/message/message.module.ts | 12 +++++++++++- components/message/message.ts | 6 +++--- demo/src/app/pages/accordion/accordion.page.html | 2 +- demo/src/app/pages/collapse/collapse.page.html | 2 +- demo/src/app/pages/message/message.page.ts | 4 ++-- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/components/message/message-config.ts b/components/message/message-config.ts index c066280e8..7c23e23fa 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -18,7 +18,7 @@ export class MessageConfig { public timeout:number; public extendedTimeout:number; - public closeButton:boolean; + public hasDismissButton:boolean; public transition:string; public transitionInDuration:number; @@ -35,7 +35,7 @@ export class MessageConfig { this.timeout = 5000; this.extendedTimeout = 1000; - this.closeButton = true; + this.hasDismissButton = true; this.transition = "fade"; this.transitionInDuration = 400; diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 30b9baa12..538507cc5 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -4,6 +4,9 @@ import { SuiTransitionModule } from "../transition/transition.module"; import { SuiMessageContainer } from "./message-container"; import { SuiMessage, IMessage } from "./message"; import { SuiUtilityModule } from "../util/util.module"; +import { MessageController } from "./message-controller"; +import { MessageConfig, MessageState } from "./message-config"; +import { SuiActiveMessage } from "./active-message"; @NgModule({ imports: [ @@ -26,4 +29,11 @@ import { SuiUtilityModule } from "../util/util.module"; }) export class SuiMessageModule {} -export {IMessage}; +export { + IMessage, + SuiMessageContainer, + MessageController, + MessageConfig, + SuiActiveMessage, + MessageState +}; diff --git a/components/message/message.ts b/components/message/message.ts index 8645f4a20..3c46f4018 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -39,8 +39,8 @@ export class SuiMessage implements IMessage { public timeout:number; public extendedTimeout:number; - @Input("isDismissable") - public closeButton:boolean; + @Input() + public hasDismissButton:boolean; public transitionController:TransitionController; @@ -90,7 +90,7 @@ export class SuiMessage implements IMessage { this.timeout = config.timeout; this.extendedTimeout = config.extendedTimeout; - this.closeButton = config.closeButton; + this.hasDismissButton = config.hasDismissButton; this.transition = config.transition; this.transitionInDuration = config.transitionInDuration; diff --git a/demo/src/app/pages/accordion/accordion.page.html b/demo/src/app/pages/accordion/accordion.page.html index 7c745e855..9f2dc395b 100644 --- a/demo/src/app/pages/accordion/accordion.page.html +++ b/demo/src/app/pages/accordion/accordion.page.html @@ -7,7 +7,7 @@

Examples

- +
Important Note

The accordion depends on the Web Animations API, which requires a polyfill for full browser diff --git a/demo/src/app/pages/collapse/collapse.page.html b/demo/src/app/pages/collapse/collapse.page.html index 6fcff0905..55209d5b6 100644 --- a/demo/src/app/pages/collapse/collapse.page.html +++ b/demo/src/app/pages/collapse/collapse.page.html @@ -14,7 +14,7 @@

Collapse

- +
Important Note

The collapse component uses the Web Animations API.

diff --git a/demo/src/app/pages/message/message.page.ts b/demo/src/app/pages/message/message.page.ts index a861e1106..80caedd6c 100644 --- a/demo/src/app/pages/message/message.page.ts +++ b/demo/src/app/pages/message/message.page.ts @@ -11,7 +11,7 @@ const exampleStandardTemplate = ` `; const exampleNoDismissTemplate = ` - +

Attached message!
@@ -32,7 +32,7 @@ export class MessagePage { selector: "", properties: [ { - name: "isDismissable", + name: "hasDismissButton", type: "boolean", description: "Sets whether or not the message has a dismiss button.", defaultValue: "true" From 6627a224fc007278e6adb81076f918aa2b4c676f Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 07:54:12 +0100 Subject: [PATCH 13/24] feat(message): Added showNewestFirst property --- components/message/message-config.ts | 2 +- components/message/message-container.ts | 23 +++++++++++--------- components/message/message.ts | 2 +- components/modal/modal.service.ts | 2 +- components/util/component-factory.service.ts | 6 ++--- demo/src/app/pages/test/test.page.html | 2 +- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/components/message/message-config.ts b/components/message/message-config.ts index 7c23e23fa..d6e753f0a 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -27,7 +27,7 @@ export class MessageConfig { public onClick:EventEmitter; public onDismiss:EventEmitter; - constructor(text:string, state?:MessageState, header?:string) { + constructor(text:string, state:MessageState = MessageState.Default, header?:string) { this.text = text; this.state = state; this.header = header; diff --git a/components/message/message-container.ts b/components/message/message-container.ts index f52626ecc..c82fadc8f 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef, ViewChild } from "@angular/core"; +import { Component, EventEmitter, Input, ComponentFactoryResolver, ViewContainerRef, ViewChild, ElementRef } from "@angular/core"; import { MessageConfig } from "./message-config"; import { ActiveMessage, SuiActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; @@ -8,8 +8,7 @@ import { MessageController } from "./message-controller"; @Component({ selector: "sui-message-container", template: ` -
-
+
`, styles: [` :host { @@ -33,22 +32,23 @@ export class SuiMessageContainer { @Input() public maxShown:number; + @Input() + public showNewestFirst:boolean; + @Input() public set controller(controller:MessageController) { controller.registerContainer(this); } - @ViewChild("top", { read: ViewContainerRef }) - public topContainer:ViewContainerRef; + @ViewChild("containerSibling", { read: ViewContainerRef }) + public containerSibling:ViewContainerRef; - @ViewChild("bottom", { read: ViewContainerRef }) - public bottomContainer:ViewContainerRef; - - constructor(private _componentFactory:SuiComponentFactory) { + constructor(private _componentFactory:SuiComponentFactory, private _element:ElementRef) { this._messages = []; this._queue = []; this.maxShown = 7; + this.showNewestFirst = true; } public show(config:MessageConfig):SuiActiveMessage { @@ -70,7 +70,10 @@ export class SuiMessageContainer { private open(message:ActiveMessage):void { this._messages.push(message); - this._componentFactory.attachToView(this.topContainer, message.componentRef); + this._componentFactory.attachToView(message.componentRef, this.containerSibling); + if (!this.showNewestFirst) { + this._componentFactory.moveToElement(message.componentRef, this._element.nativeElement); + } message.component.show(); } diff --git a/components/message/message.ts b/components/message/message.ts index 3c46f4018..4e934bc2c 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -19,7 +19,7 @@ export interface IMessage { (mouseleave)="beginTimer(extendedTimeout)" (click)="onClicked($event)"> - +
{{ header }}
diff --git a/components/modal/modal.service.ts b/components/modal/modal.service.ts index 300161eb3..269c638e9 100644 --- a/components/modal/modal.service.ts +++ b/components/modal/modal.service.ts @@ -38,7 +38,7 @@ export class SuiModalService { ); // Insert the new component into the content of the modal. - this._componentFactory.attachToView(modalComponent.templateSibling, contentComponentRef); + this._componentFactory.attachToView(contentComponentRef, modalComponent.templateSibling); // Shorthand for access to the content component's DOM element. const contentElement = contentComponentRef.location.nativeElement as Element; diff --git a/components/util/component-factory.service.ts b/components/util/component-factory.service.ts index d26c9db46..8f74c329b 100644 --- a/components/util/component-factory.service.ts +++ b/components/util/component-factory.service.ts @@ -34,7 +34,7 @@ export class SuiComponentFactory { } // Inserts the component into the specified view container. - public attachToView(viewContainer:ViewContainerRef, componentRef:ComponentRef):void { + public attachToView(componentRef:ComponentRef, viewContainer:ViewContainerRef):void { viewContainer.insert(componentRef.hostView, 0); } @@ -44,12 +44,12 @@ export class SuiComponentFactory { } // Moves the component to the specified DOM element. - public moveToElement(element:Element, componentRef:ComponentRef):void { + public moveToElement(componentRef:ComponentRef, element:Element):void { element.appendChild(componentRef.location.nativeElement); } // Moves the component to the document body. public moveToDocumentBody(componentRef:ComponentRef):void { - this.moveToElement(document.querySelector("body"), componentRef); + this.moveToElement(componentRef, document.querySelector("body")); } } diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index ed646a8b1..d2a03892d 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -8,6 +8,6 @@

Examples

- +
\ No newline at end of file From c55b03cc3850f41442e6d28016948f209703a1c6 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 08:15:44 +0100 Subject: [PATCH 14/24] feat(message): Added manual dismiss method --- components/message/active-message.ts | 6 +++++ components/message/message-container.ts | 4 ++++ components/message/message.ts | 30 ++++++++++++++++--------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/message/active-message.ts b/components/message/active-message.ts index 9fa5ffea0..b277c659e 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -5,6 +5,8 @@ import { SuiMessage } from "./message"; export abstract class SuiActiveMessage { public abstract onClick(callback:() => void):SuiActiveMessage; public abstract onDismiss(callback:() => void):SuiActiveMessage; + + public abstract dismiss():void; } export class ActiveMessage implements SuiActiveMessage { @@ -31,4 +33,8 @@ export class ActiveMessage implements SuiActiveMessage { this._config.onDismiss.subscribe(() => callback()); return this; } + + public dismiss():void { + this.component.dismiss(); + } } diff --git a/components/message/message-container.ts b/components/message/message-container.ts index c82fadc8f..3057cd62f 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -23,6 +23,10 @@ import { MessageController } from "./message-controller"; :host >>> sui-message:last-of-type { margin-bottom: 0; } + +:host >>> sui-message { + cursor: pointer; +} `] }) export class SuiMessageContainer { diff --git a/components/message/message.ts b/components/message/message.ts index 4e934bc2c..cd772ba52 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Component, EventEmitter, Input, Output, HostBinding } from "@angular/core"; import { TransitionController } from "../transition/transition-controller"; import { MessageState, MessageConfig } from "./message-config"; import { Transition, TransitionDirection } from "../transition/transition"; @@ -19,7 +19,7 @@ export interface IMessage { (mouseleave)="beginTimer(extendedTimeout)" (click)="onClicked($event)"> - +
{{ header }}
@@ -31,6 +31,7 @@ export interface IMessage { export class SuiMessage implements IMessage { public isDynamic:boolean; public isClosing:boolean; + public isDismissing:boolean; public text:string; public header:string; @@ -65,7 +66,11 @@ export class SuiMessage implements IMessage { public get dynamicClasses():IDynamicClasslist { const classes:IDynamicClasslist = {}; classes[this.state] = true; - this.classes.split(" ").forEach(c => classes[c] = true); + + (this.classes || "") + .split(" ") + .forEach(c => classes[c] = true); + return classes; } @@ -74,7 +79,8 @@ export class SuiMessage implements IMessage { this.loadConfig(config); this.isDynamic = false; - this.classes = ""; + this.transitionOutDuration = 300; + this.transitionController = new TransitionController(false); this.show(); @@ -114,10 +120,9 @@ export class SuiMessage implements IMessage { })); } - public dismiss(e?:HandledEvent):void { - if (e) { - e.eventHandled = true; - } + public dismiss():void { + this.isDismissing = true; + this.transitionOutDuration = this.transitionInDuration; this.hide(); } @@ -137,13 +142,13 @@ export class SuiMessage implements IMessage { } public beginTimer(timeout:number):void { - if (this.isDynamic) { + if (this.isDynamic && !this.isDismissing) { this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); } } public cancelTimer():void { - if (this.isDynamic) { + if (this.isDynamic && !this.isDismissing) { clearTimeout(this._displayTimeout); if (this.isClosing) { @@ -161,6 +166,11 @@ export class SuiMessage implements IMessage { } } + public onDismissClicked(e:HandledEvent):void { + e.eventHandled = true; + this.dismiss(); + } + private onTimedOut():void { this.hide(); } From e85b5194a4766e7dcc3f73e8b89debb58d279f46 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 08:28:52 +0100 Subject: [PATCH 15/24] feat(message): Added rough progress bar --- components/message/message-config.ts | 2 ++ components/message/message.module.ts | 2 ++ components/message/message.ts | 42 +++++++++++++++++++--------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/components/message/message-config.ts b/components/message/message-config.ts index d6e753f0a..917d22ec6 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -19,6 +19,7 @@ export class MessageConfig { public extendedTimeout:number; public hasDismissButton:boolean; + public hasProgress:boolean; public transition:string; public transitionInDuration:number; @@ -36,6 +37,7 @@ export class MessageConfig { this.extendedTimeout = 1000; this.hasDismissButton = true; + this.hasProgress = true; this.transition = "fade"; this.transitionInDuration = 400; diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 538507cc5..329199314 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { SuiTransitionModule } from "../transition/transition.module"; +import { SuiProgressModule } from "../progress/progress.module"; import { SuiMessageContainer } from "./message-container"; import { SuiMessage, IMessage } from "./message"; import { SuiUtilityModule } from "../util/util.module"; @@ -12,6 +13,7 @@ import { SuiActiveMessage } from "./active-message"; imports: [ CommonModule, SuiTransitionModule, + SuiProgressModule, SuiUtilityModule ], declarations: [ diff --git a/components/message/message.ts b/components/message/message.ts index cd772ba52..0c993ba60 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -12,19 +12,23 @@ export interface IMessage { @Component({ selector: "sui-message", template: ` -
- - - - -
{{ header }}
-

{{ text }}

-
+
+
+ + + + +
{{ header }}
+

{{ text }}

+
+
+
` }) @@ -43,6 +47,10 @@ export class SuiMessage implements IMessage { @Input() public hasDismissButton:boolean; + public hasProgress:boolean; + + public timeoutProgress:number; + public transitionController:TransitionController; @Input() @@ -67,6 +75,10 @@ export class SuiMessage implements IMessage { const classes:IDynamicClasslist = {}; classes[this.state] = true; + if (this.isDynamic && this.hasProgress) { + classes["attached"] = true; + } + (this.classes || "") .split(" ") .forEach(c => classes[c] = true); @@ -80,6 +92,7 @@ export class SuiMessage implements IMessage { this.isDynamic = false; this.transitionOutDuration = 300; + this.timeoutProgress = 100; this.transitionController = new TransitionController(false); @@ -97,6 +110,7 @@ export class SuiMessage implements IMessage { this.extendedTimeout = config.extendedTimeout; this.hasDismissButton = config.hasDismissButton; + this.hasProgress = config.hasProgress; this.transition = config.transition; this.transitionInDuration = config.transitionInDuration; @@ -143,12 +157,14 @@ export class SuiMessage implements IMessage { public beginTimer(timeout:number):void { if (this.isDynamic && !this.isDismissing) { + this.timeoutProgress = 0; this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); } } public cancelTimer():void { if (this.isDynamic && !this.isDismissing) { + this.timeoutProgress = 100; clearTimeout(this._displayTimeout); if (this.isClosing) { From e0eb5e1f22f86a82dc7f6027a0ab1a8de055c8a5 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 08:48:52 +0100 Subject: [PATCH 16/24] feat(progress): Added transition options and ability to completely empty bar Added `transition` Added `transitionDuration` Added `canCompletelyEmpty` --- components/message/message.ts | 8 +++++++- components/progress/progress.ts | 20 ++++++++++++++++++-- demo/src/app/pages/progress/progress.page.ts | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/components/message/message.ts b/components/message/message.ts index 0c993ba60..c6b5cf112 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -28,7 +28,10 @@ export interface IMessage {
+ [value]="timeoutProgress" + transition="linear" + [transitionDuration]="currentTimeout" + [canCompletelyEmpty]="true">
` }) @@ -43,6 +46,7 @@ export class SuiMessage implements IMessage { public timeout:number; public extendedTimeout:number; + public currentTimeout:number; @Input() public hasDismissButton:boolean; @@ -158,6 +162,7 @@ export class SuiMessage implements IMessage { public beginTimer(timeout:number):void { if (this.isDynamic && !this.isDismissing) { this.timeoutProgress = 0; + this.currentTimeout = timeout; this._displayTimeout = window.setTimeout(() => this.onTimedOut(), timeout); } } @@ -165,6 +170,7 @@ export class SuiMessage implements IMessage { public cancelTimer():void { if (this.isDynamic && !this.isDismissing) { this.timeoutProgress = 100; + this.currentTimeout = 0; clearTimeout(this._displayTimeout); if (this.isClosing) { diff --git a/components/progress/progress.ts b/components/progress/progress.ts index 4ca7685ae..3cd74aa2a 100644 --- a/components/progress/progress.ts +++ b/components/progress/progress.ts @@ -3,7 +3,11 @@ import { Component, Input, HostBinding } from "@angular/core"; @Component({ selector: "sui-progress", template: ` -
+
{{ percentage }}%
@@ -12,7 +16,6 @@ import { Component, Input, HostBinding } from "@angular/core"; `, styles: [` .bar { - transition-duration: 300ms !important; z-index: 1; } `] @@ -96,6 +99,15 @@ export class SuiProgress { return percentage.toFixed(this.precision); } + @Input() + public transition:string; + + @Input() + public transitionDuration:number; + + @Input() + public canCompletelyEmpty:boolean; + @Input("class") public set classValue(classes:string) { if (classes.includes("attached") || classes.includes("tiny")) { @@ -115,6 +127,10 @@ export class SuiProgress { this.autoSuccess = true; this.showProgress = true; + this.transition = "ease"; + this.transitionDuration = 350; + this.canCompletelyEmpty = false; + this._popupClasses = true; } } diff --git a/demo/src/app/pages/progress/progress.page.ts b/demo/src/app/pages/progress/progress.page.ts index 9160890bf..54a94946b 100644 --- a/demo/src/app/pages/progress/progress.page.ts +++ b/demo/src/app/pages/progress/progress.page.ts @@ -91,6 +91,24 @@ export class ProgressPage { type: "boolean", description: "Sets whether or not the progress bar automatically turns green when value == maximum.", defaultValue: "true" + }, + { + name: "transition", + type: "number", + description: "Sets the transition function used when transitioning between values.", + defaultValue: "350" + }, + { + name: "transitionDuration", + type: "number", + description: "Sets the transition duration of the bar between values.", + defaultValue: "350" + }, + { + name: "canCompletelyEmpty", + type: "boolean", + description: "Sets whether the progress bar can empty completely.", + defaultValue: "false" } ] } From 2162a1b89c6bfc929818856a3dfbcb6c4a97067b Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 09:05:10 +0100 Subject: [PATCH 17/24] style: Fixed tslint rule for public property names --- components/message/message-config.ts | 2 +- components/message/message.ts | 2 ++ demo/src/app/pages/test/test.page.ts | 2 +- tslint.json | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/message/message-config.ts b/components/message/message-config.ts index 917d22ec6..ef2888eaf 100644 --- a/components/message/message-config.ts +++ b/components/message/message-config.ts @@ -37,7 +37,7 @@ export class MessageConfig { this.extendedTimeout = 1000; this.hasDismissButton = true; - this.hasProgress = true; + this.hasProgress = false; this.transition = "fade"; this.transitionInDuration = 400; diff --git a/components/message/message.ts b/components/message/message.ts index c6b5cf112..62ade01a0 100644 --- a/components/message/message.ts +++ b/components/message/message.ts @@ -29,6 +29,7 @@ export interface IMessage { @@ -141,6 +142,7 @@ export class SuiMessage implements IMessage { public dismiss():void { this.isDismissing = true; this.transitionOutDuration = this.transitionInDuration; + this.hide(); } diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index a663167f7..d31c16980 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -16,7 +16,7 @@ export class TestPage { public open():void { const message = new MessageConfig(null, MessageState.Default, Date.now().toString()); - message.state = MessageState.Success; + message.state = MessageState.Default; this.controller.show(message); } diff --git a/tslint.json b/tslint.json index 7cf902d7f..fdc426534 100644 --- a/tslint.json +++ b/tslint.json @@ -38,9 +38,9 @@ ["class", "pascal"], ["interface", "pascal", { "regex": "^I.*$" }], ["parameter", "camel"], - ["property", "static", "camel"], ["property", "private", "camel", "require-leading-underscore"], ["property", "protected", "camel", "require-leading-underscore"], + ["property", "camel"], ["method", "camel"], ["function", "camel"] ], From dd4878e7911aa3a04cf68fe89dd12cb9b1ff4441 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 09:06:40 +0100 Subject: [PATCH 18/24] feat: Made internal properties of ActiveModal & ActiveMessage public Since they're both behind public filtered interfaces there isn't any need to keep them private --- components/message/active-message.ts | 8 ++++---- components/modal/active-modal.ts | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/message/active-message.ts b/components/message/active-message.ts index b277c659e..b661f0289 100644 --- a/components/message/active-message.ts +++ b/components/message/active-message.ts @@ -10,7 +10,7 @@ export abstract class SuiActiveMessage { } export class ActiveMessage implements SuiActiveMessage { - private _config:MessageConfig; + public config:MessageConfig; public componentRef:ComponentRef; public get component():SuiMessage { @@ -18,19 +18,19 @@ export class ActiveMessage implements SuiActiveMessage { } constructor(config:MessageConfig, componentRef:ComponentRef) { - this._config = config; + this.config = config; this.componentRef = componentRef; this.component.onDismiss.subscribe(() => this.componentRef.destroy()); } public onClick(callback:() => void):ActiveMessage { - this._config.onClick.subscribe(() => callback()); + this.config.onClick.subscribe(() => callback()); return this; } public onDismiss(callback:() => void):ActiveMessage { - this._config.onDismiss.subscribe(() => callback()); + this.config.onDismiss.subscribe(() => callback()); return this; } diff --git a/components/modal/active-modal.ts b/components/modal/active-modal.ts index cf41a0ce7..0f4151c2d 100644 --- a/components/modal/active-modal.ts +++ b/components/modal/active-modal.ts @@ -14,20 +14,20 @@ export abstract class SuiActiveModal { // Helper class to support method chaining when calling `SuiModalService.open(...)`. export class ActiveModal implements SuiActiveModal { - private _config:ModalConfig; - private _componentRef:ComponentRef>; + public config:ModalConfig; + public componentRef:ComponentRef>; // Shorthand for direct access to the `SuiModal` instance. public get component():SuiModal { - return this._componentRef.instance; + return this.componentRef.instance; } constructor(instance:ModalConfig, componentRef:ComponentRef>) { - this._config = instance; - this._componentRef = componentRef; + this.config = instance; + this.componentRef = componentRef; // Automatically destroy the modal component when it has been dismissed. - this.component.onDismiss.subscribe(() => this._componentRef.destroy()); + this.component.onDismiss.subscribe(() => this.componentRef.destroy()); } // Registers a callback for when `onApprove` is fired. @@ -54,6 +54,6 @@ export class ActiveModal implements SuiActiveModal { // Removes the modal component instantly, without transitions or firing any events. public destroy():void { - this._componentRef.destroy(); + this.componentRef.destroy(); } } From 9cb441220f17a24eed524c174dea13ab0c6cae7c Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Fri, 16 Jun 2017 09:20:17 +0100 Subject: [PATCH 19/24] feat(message): Added dismissAll method to controller --- components/message/message-container.ts | 5 +++++ components/message/message-controller.ts | 14 ++++++++++++-- demo/src/app/pages/test/test.page.html | 2 ++ demo/src/app/pages/test/test.page.ts | 3 ++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/components/message/message-container.ts b/components/message/message-container.ts index 3057cd62f..c996bcfa9 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -85,6 +85,11 @@ export class SuiMessageContainer { this._queue.push(message); } + public dismissAll():void { + this._queue = []; + this._messages.forEach(m => m.dismiss()); + } + private onMessageClose(message:ActiveMessage):void { this._messages = this._messages.filter(m => m !== message); diff --git a/components/message/message-controller.ts b/components/message/message-controller.ts index 6abf39427..22ed5aa0f 100644 --- a/components/message/message-controller.ts +++ b/components/message/message-controller.ts @@ -11,10 +11,20 @@ export class MessageController { } public show(config:MessageConfig):SuiActiveMessage { + this.throwContainerError(); + + return this._container.show(config); + } + + public dismissAll():void { + this.throwContainerError(); + + return this._container.dismissAll(); + } + + private throwContainerError() { if (!this._container) { throw new Error("You must pass this controller to a message container."); } - - return this._container.show(config); } } diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index d2a03892d..eb0f41697 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -8,6 +8,8 @@

Examples

+ +
\ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index d31c16980..87f7ab5e9 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -15,8 +15,9 @@ export class TestPage { } public open():void { - const message = new MessageConfig(null, MessageState.Default, Date.now().toString()); + const message = new MessageConfig("hello, world!", MessageState.Default, "Header"); message.state = MessageState.Default; + message.hasProgress = true; this.controller.show(message); } From 84b1a4a15594eb51dda7e35cba3af8f405e9d046 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Sun, 18 Jun 2017 19:01:44 +0100 Subject: [PATCH 20/24] feat(message): Added global message service --- components/message/message-container.ts | 1 + components/message/message-controller.ts | 3 +-- .../message/message-global-container.ts | 12 ++++++++++ components/message/message-service.ts | 24 +++++++++++++++++++ components/message/message.module.ts | 13 +++++++--- demo/src/app/pages/test/test.page.ts | 3 ++- 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 components/message/message-global-container.ts create mode 100644 components/message/message-service.ts diff --git a/components/message/message-container.ts b/components/message/message-container.ts index c996bcfa9..b3f00b995 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -78,6 +78,7 @@ export class SuiMessageContainer { if (!this.showNewestFirst) { this._componentFactory.moveToElement(message.componentRef, this._element.nativeElement); } + message.component.show(); } diff --git a/components/message/message-controller.ts b/components/message/message-controller.ts index 22ed5aa0f..78f105069 100644 --- a/components/message/message-controller.ts +++ b/components/message/message-controller.ts @@ -2,7 +2,6 @@ import { MessageConfig } from "./message-config"; import { SuiActiveMessage } from "./active-message"; import { SuiMessageContainer } from "./message-container"; - export class MessageController { private _container:SuiMessageContainer; @@ -22,7 +21,7 @@ export class MessageController { return this._container.dismissAll(); } - private throwContainerError() { + private throwContainerError():void { if (!this._container) { throw new Error("You must pass this controller to a message container."); } diff --git a/components/message/message-global-container.ts b/components/message/message-global-container.ts new file mode 100644 index 000000000..148bdae18 --- /dev/null +++ b/components/message/message-global-container.ts @@ -0,0 +1,12 @@ + +import { Component } from "@angular/core"; +import { MessageController } from "./message-controller"; +import { SuiMessageService } from "./message-service"; + +@Component({ + selector: "sui-message-global-container", + template: `` +}) +export class SuiMessageGlobalContainer { + public controller:MessageController; +} diff --git a/components/message/message-service.ts b/components/message/message-service.ts new file mode 100644 index 000000000..6f649429a --- /dev/null +++ b/components/message/message-service.ts @@ -0,0 +1,24 @@ +import { Injectable, ComponentRef } from "@angular/core"; +import { SuiComponentFactory } from "../util/component-factory.service"; +import { SuiMessageGlobalContainer } from "./message-global-container"; +import { MessageController } from "./message-controller"; + +@Injectable() +export class SuiMessageService { + private _controller:MessageController; + private _containerRef:ComponentRef; + + private get _container():SuiMessageGlobalContainer { + return this._containerRef.instance; + } + + constructor(private _componentFactory:SuiComponentFactory) { + this._controller = new MessageController(); + + this._containerRef = this._componentFactory.createComponent(SuiMessageGlobalContainer); + this._container.controller = this._controller; + + this._componentFactory.attachToApplication(this._containerRef); + this._componentFactory.moveToDocumentBody(this._containerRef); + } +} diff --git a/components/message/message.module.ts b/components/message/message.module.ts index 329199314..1b9f2d0c2 100644 --- a/components/message/message.module.ts +++ b/components/message/message.module.ts @@ -8,6 +8,8 @@ import { SuiUtilityModule } from "../util/util.module"; import { MessageController } from "./message-controller"; import { MessageConfig, MessageState } from "./message-config"; import { SuiActiveMessage } from "./active-message"; +import { SuiMessageGlobalContainer } from "./message-global-container"; +import { SuiMessageService } from "./message-service"; @NgModule({ imports: [ @@ -18,15 +20,20 @@ import { SuiActiveMessage } from "./active-message"; ], declarations: [ SuiMessage, - SuiMessageContainer + SuiMessageContainer, + SuiMessageGlobalContainer ], exports: [ SuiMessage, - SuiMessageContainer + SuiMessageContainer, + SuiMessageGlobalContainer + ], + providers: [ + SuiMessageService ], entryComponents: [ SuiMessage, - SuiMessageContainer + SuiMessageGlobalContainer ] }) export class SuiMessageModule {} diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index 87f7ab5e9..a365e61e4 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -2,6 +2,7 @@ import { Component, AfterViewInit, ViewChild, TemplateRef } from "@angular/core" import { SuiMessageContainer } from "../../../../../components/message/message-container"; import { MessageConfig, MessageState } from "../../../../../components/message/message-config"; import { MessageController } from "../../../../../components/message/message-controller"; +import { SuiMessageService } from "../../../../../components/message/message-service"; @Component({ selector: "demo-page-test", @@ -10,7 +11,7 @@ import { MessageController } from "../../../../../components/message/message-con export class TestPage { public controller:MessageController; - constructor() { + constructor(private _messageService:SuiMessageService) { this.controller = new MessageController(); } From e7eaf131263032981f11fcb871df5d80c85d8aed Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Sun, 18 Jun 2017 19:14:21 +0100 Subject: [PATCH 21/24] feat(message): Added display functionality to global service --- components/message/message-controller.ts | 7 ++++++- components/message/message-global-container.ts | 2 ++ components/message/message-service.ts | 14 ++++++++++++-- demo/src/app/pages/test/test.page.ts | 5 ++--- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/components/message/message-controller.ts b/components/message/message-controller.ts index 78f105069..e868f369c 100644 --- a/components/message/message-controller.ts +++ b/components/message/message-controller.ts @@ -2,7 +2,12 @@ import { MessageConfig } from "./message-config"; import { SuiActiveMessage } from "./active-message"; import { SuiMessageContainer } from "./message-container"; -export class MessageController { +export interface IMessageController { + show(config:MessageConfig):SuiActiveMessage; + dismissAll():void; +} + +export class MessageController implements IMessageController { private _container:SuiMessageContainer; public registerContainer(container:SuiMessageContainer):void { diff --git a/components/message/message-global-container.ts b/components/message/message-global-container.ts index 148bdae18..e5213373a 100644 --- a/components/message/message-global-container.ts +++ b/components/message/message-global-container.ts @@ -9,4 +9,6 @@ import { SuiMessageService } from "./message-service"; }) export class SuiMessageGlobalContainer { public controller:MessageController; + + } diff --git a/components/message/message-service.ts b/components/message/message-service.ts index 6f649429a..ce9fb94d8 100644 --- a/components/message/message-service.ts +++ b/components/message/message-service.ts @@ -1,10 +1,12 @@ import { Injectable, ComponentRef } from "@angular/core"; import { SuiComponentFactory } from "../util/component-factory.service"; import { SuiMessageGlobalContainer } from "./message-global-container"; -import { MessageController } from "./message-controller"; +import { MessageController, IMessageController } from "./message-controller"; +import { MessageConfig } from "./message-config"; +import { SuiActiveMessage } from "./active-message"; @Injectable() -export class SuiMessageService { +export class SuiMessageService implements IMessageController { private _controller:MessageController; private _containerRef:ComponentRef; @@ -21,4 +23,12 @@ export class SuiMessageService { this._componentFactory.attachToApplication(this._containerRef); this._componentFactory.moveToDocumentBody(this._containerRef); } + + public show(config:MessageConfig):SuiActiveMessage { + return this._controller.show(config); + } + + public dismissAll():void { + return this._controller.dismissAll(); + } } diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index a365e61e4..70316bf14 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -17,9 +17,8 @@ export class TestPage { public open():void { const message = new MessageConfig("hello, world!", MessageState.Default, "Header"); - message.state = MessageState.Default; - message.hasProgress = true; - this.controller.show(message); + // this.controller.show(message); + this._messageService.show(message); } } From 1b70a7c2ace40005bd365a7057c0565dec4a6328 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Sun, 18 Jun 2017 19:58:02 +0100 Subject: [PATCH 22/24] feat(message): Added global positioning support --- .../message/message-global-container.ts | 84 ++++++++++++++++++- components/modal/modal.ts | 5 +- components/util/util.ts | 6 ++ .../page-content/page-content.component.css | 2 +- .../page-title/page-title.component.css | 2 +- 5 files changed, 91 insertions(+), 8 deletions(-) diff --git a/components/message/message-global-container.ts b/components/message/message-global-container.ts index e5213373a..5b6d6945f 100644 --- a/components/message/message-global-container.ts +++ b/components/message/message-global-container.ts @@ -1,14 +1,92 @@ -import { Component } from "@angular/core"; +import { Component, HostListener } from "@angular/core"; import { MessageController } from "./message-controller"; import { SuiMessageService } from "./message-service"; +import { IDynamicClasslist } from "../util/interfaces"; +import { getDocumentFontSize } from "../util/util"; + +export type MessagePosition = "top" | "top-left" | "top-right" | + "bottom" | "bottom-left" | "bottom-right"; + +export const MessagePosition = { + Top: "top" as MessagePosition, + TopLeft: "top-left" as MessagePosition, + TopRight: "top-right" as MessagePosition, + Bottom: "bottom" as MessagePosition, + BottomLeft: "bottom-left" as MessagePosition, + BottomRight: "bottom-right" as MessagePosition +}; @Component({ selector: "sui-message-global-container", - template: `` + template: ` +
+ +
+`, + styles: [` +.global.container { + display: block; + position: fixed; +} + +.global.container.top { + top: 1rem; +} + +.global.container.bottom { + bottom: 1rem; +} + +.global.container.left { + left: 1rem; +} + +.global.container.right { + right: 1rem; +} + +.global.container:not(.left):not(.right) { + left: 1rem; +} +`] }) export class SuiMessageGlobalContainer { public controller:MessageController; - + public position:MessagePosition; + + public width:number; + + public get dynamicClasses():IDynamicClasslist { + const classes:IDynamicClasslist = {}; + + this.position + .split("-") + .forEach(p => classes[p] = true); + + return classes; + } + + public get dynamicWidth():number { + const margin = getDocumentFontSize(); + let width = this.width; + + if (this.position === MessagePosition.Top || + this.position === MessagePosition.Bottom || + window.innerWidth < width + margin * 2) { + + width = window.innerWidth - margin * 2; + } + + return width; + } + + constructor() { + this.position = MessagePosition.Top; + this.width = 480; + } + + @HostListener("window:resize") + public onDocumentResize():void {} } diff --git a/components/modal/modal.ts b/components/modal/modal.ts index 554b728d4..1435cfa8c 100644 --- a/components/modal/modal.ts +++ b/components/modal/modal.ts @@ -4,7 +4,7 @@ import { } from "@angular/core"; import { TransitionController } from "../transition/transition-controller"; import { Transition, TransitionDirection } from "../transition/transition"; -import { KeyCode, parseBooleanAttribute } from "../util/util"; +import { KeyCode, parseBooleanAttribute, getDocumentFontSize } from "../util/util"; import { ModalControls, ModalResult } from "./modal-controls"; import { ModalConfig, ModalSize } from "./modal-config"; @@ -219,8 +219,7 @@ export class SuiModal implements OnInit, AfterViewInit { // Decides whether the modal needs to reposition to allow scrolling. private updateScroll():void { // Semantic UI modal margin is 3.5rem, which is relative to the global font size, so for compatibility: - const fontSize = parseFloat(window.getComputedStyle(document.documentElement, null).getPropertyValue("font-size")); - const margin = fontSize * 3.5; + const margin = getDocumentFontSize() * 3.5; // _mustAlwaysScroll works by stopping _mustScroll from being automatically updated, so it stays `true`. if (!this._mustAlwaysScroll && this._modalElement) { diff --git a/components/util/util.ts b/components/util/util.ts index 44733bc11..302e7e303 100644 --- a/components/util/util.ts +++ b/components/util/util.ts @@ -56,3 +56,9 @@ export function parseBooleanAttribute(attributeValue:boolean):boolean { return value; } + +export function getDocumentFontSize():number { + return parseFloat(window + .getComputedStyle(document.documentElement, null) + .getPropertyValue("font-size")); +} diff --git a/demo/src/app/components/page-content/page-content.component.css b/demo/src/app/components/page-content/page-content.component.css index 87ba68ea3..bd3b20502 100644 --- a/demo/src/app/components/page-content/page-content.component.css +++ b/demo/src/app/components/page-content/page-content.component.css @@ -23,7 +23,7 @@ } } -@media only screen and (max-width: 425px) { +@media only screen and (max-width: 480px) { :host.ui.main.container { margin-left: 1em !important; margin-right: 1em !important; diff --git a/demo/src/app/components/page-title/page-title.component.css b/demo/src/app/components/page-title/page-title.component.css index 27e0f3100..6a8814696 100644 --- a/demo/src/app/components/page-title/page-title.component.css +++ b/demo/src/app/components/page-title/page-title.component.css @@ -26,7 +26,7 @@ } } -@media only screen and (max-width: 425px) { +@media only screen and (max-width: 480px) { :host.ui.masthead.segment { margin-bottom: 1em; padding: 1em; From ae87f3357f0e9404f8bf48b94b80c7e45af48c7b Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Sun, 18 Jun 2017 20:23:02 +0100 Subject: [PATCH 23/24] feat(message): Added global service accessors --- components/message/message-container.ts | 27 +++++--------- components/message/message-controller.ts | 12 +++++- .../message/message-global-container.ts | 6 --- components/message/message-service.ts | 37 ++++++++++++++++++- demo/src/app/pages/test/test.page.html | 2 +- demo/src/app/pages/test/test.page.ts | 5 ++- 6 files changed, 61 insertions(+), 28 deletions(-) diff --git a/components/message/message-container.ts b/components/message/message-container.ts index b3f00b995..620349eb3 100644 --- a/components/message/message-container.ts +++ b/components/message/message-container.ts @@ -3,7 +3,7 @@ import { MessageConfig } from "./message-config"; import { ActiveMessage, SuiActiveMessage } from "./active-message"; import { SuiMessage } from "./message"; import { SuiComponentFactory } from "../util/component-factory.service"; -import { MessageController } from "./message-controller"; +import { MessageController, IMessageController } from "./message-controller"; @Component({ selector: "sui-message-container", @@ -33,12 +33,6 @@ export class SuiMessageContainer { private _messages:ActiveMessage[]; private _queue:ActiveMessage[]; - @Input() - public maxShown:number; - - @Input() - public showNewestFirst:boolean; - @Input() public set controller(controller:MessageController) { controller.registerContainer(this); @@ -50,20 +44,17 @@ export class SuiMessageContainer { constructor(private _componentFactory:SuiComponentFactory, private _element:ElementRef) { this._messages = []; this._queue = []; - - this.maxShown = 7; - this.showNewestFirst = true; } - public show(config:MessageConfig):SuiActiveMessage { + public show(config:MessageConfig, maxShown:number, showNewestFirst:boolean):SuiActiveMessage { const componentRef = this._componentFactory.createComponent(SuiMessage); componentRef.instance.loadConfig(config); const active = new ActiveMessage(config, componentRef) - .onDismiss(() => this.onMessageClose(active)); + .onDismiss(() => this.onMessageClose(active, showNewestFirst)); - if (this._messages.length < this.maxShown) { - this.open(active); + if (this._messages.length < maxShown) { + this.open(active, showNewestFirst); } else { this.queue(active); } @@ -71,11 +62,11 @@ export class SuiMessageContainer { return active; } - private open(message:ActiveMessage):void { + private open(message:ActiveMessage, showNewestFirst:boolean):void { this._messages.push(message); this._componentFactory.attachToView(message.componentRef, this.containerSibling); - if (!this.showNewestFirst) { + if (!showNewestFirst) { this._componentFactory.moveToElement(message.componentRef, this._element.nativeElement); } @@ -91,13 +82,13 @@ export class SuiMessageContainer { this._messages.forEach(m => m.dismiss()); } - private onMessageClose(message:ActiveMessage):void { + private onMessageClose(message:ActiveMessage, showNewestFirst:boolean):void { this._messages = this._messages.filter(m => m !== message); if (this._queue.length > 0) { const queued = this._queue.shift(); - this.open(queued); + this.open(queued, showNewestFirst); } } } diff --git a/components/message/message-controller.ts b/components/message/message-controller.ts index e868f369c..e2e161697 100644 --- a/components/message/message-controller.ts +++ b/components/message/message-controller.ts @@ -3,6 +3,8 @@ import { SuiActiveMessage } from "./active-message"; import { SuiMessageContainer } from "./message-container"; export interface IMessageController { + maxShown:number; + isNewestOnTop:boolean; show(config:MessageConfig):SuiActiveMessage; dismissAll():void; } @@ -10,6 +12,14 @@ export interface IMessageController { export class MessageController implements IMessageController { private _container:SuiMessageContainer; + public maxShown:number; + public isNewestOnTop:boolean; + + constructor() { + this.maxShown = 7; + this.isNewestOnTop = true; + } + public registerContainer(container:SuiMessageContainer):void { this._container = container; } @@ -17,7 +27,7 @@ export class MessageController implements IMessageController { public show(config:MessageConfig):SuiActiveMessage { this.throwContainerError(); - return this._container.show(config); + return this._container.show(config, this.maxShown, this.isNewestOnTop); } public dismissAll():void { diff --git a/components/message/message-global-container.ts b/components/message/message-global-container.ts index 5b6d6945f..90d3c0c19 100644 --- a/components/message/message-global-container.ts +++ b/components/message/message-global-container.ts @@ -55,7 +55,6 @@ export class SuiMessageGlobalContainer { public controller:MessageController; public position:MessagePosition; - public width:number; public get dynamicClasses():IDynamicClasslist { @@ -82,11 +81,6 @@ export class SuiMessageGlobalContainer { return width; } - constructor() { - this.position = MessagePosition.Top; - this.width = 480; - } - @HostListener("window:resize") public onDocumentResize():void {} } diff --git a/components/message/message-service.ts b/components/message/message-service.ts index ce9fb94d8..415cdce75 100644 --- a/components/message/message-service.ts +++ b/components/message/message-service.ts @@ -1,6 +1,6 @@ import { Injectable, ComponentRef } from "@angular/core"; import { SuiComponentFactory } from "../util/component-factory.service"; -import { SuiMessageGlobalContainer } from "./message-global-container"; +import { SuiMessageGlobalContainer, MessagePosition } from "./message-global-container"; import { MessageController, IMessageController } from "./message-controller"; import { MessageConfig } from "./message-config"; import { SuiActiveMessage } from "./active-message"; @@ -14,6 +14,38 @@ export class SuiMessageService implements IMessageController { return this._containerRef.instance; } + public get position():MessagePosition { + return this._container.position; + } + + public set position(position:MessagePosition) { + this._container.position = position; + } + + public get width():number { + return this._container.width; + } + + public set width(width:number) { + this._container.width = width; + } + + public get maxShown():number { + return this._controller.maxShown; + } + + public set maxShown(max:number) { + this._controller.maxShown = max; + } + + public get isNewestOnTop():boolean { + return this._controller.isNewestOnTop; + } + + public set isNewestOnTop(value:boolean) { + this._controller.isNewestOnTop = value; + } + constructor(private _componentFactory:SuiComponentFactory) { this._controller = new MessageController(); @@ -22,6 +54,9 @@ export class SuiMessageService implements IMessageController { this._componentFactory.attachToApplication(this._containerRef); this._componentFactory.moveToDocumentBody(this._containerRef); + + this.position = MessagePosition.TopRight; + this.width = 480; } public show(config:MessageConfig):SuiActiveMessage { diff --git a/demo/src/app/pages/test/test.page.html b/demo/src/app/pages/test/test.page.html index eb0f41697..8465bd8c3 100644 --- a/demo/src/app/pages/test/test.page.html +++ b/demo/src/app/pages/test/test.page.html @@ -10,6 +10,6 @@

Examples


- +
\ No newline at end of file diff --git a/demo/src/app/pages/test/test.page.ts b/demo/src/app/pages/test/test.page.ts index 70316bf14..9128cd217 100644 --- a/demo/src/app/pages/test/test.page.ts +++ b/demo/src/app/pages/test/test.page.ts @@ -3,6 +3,7 @@ import { SuiMessageContainer } from "../../../../../components/message/message-c import { MessageConfig, MessageState } from "../../../../../components/message/message-config"; import { MessageController } from "../../../../../components/message/message-controller"; import { SuiMessageService } from "../../../../../components/message/message-service"; +import { MessagePosition } from "../../../../../components/message/message-global-container"; @Component({ selector: "demo-page-test", @@ -13,10 +14,12 @@ export class TestPage { constructor(private _messageService:SuiMessageService) { this.controller = new MessageController(); + this._messageService.position = MessagePosition.BottomRight; + this._messageService.isNewestOnTop = true; } public open():void { - const message = new MessageConfig("hello, world!", MessageState.Default, "Header"); + const message = new MessageConfig(Date.now().toString(), MessageState.Default, "Header"); // this.controller.show(message); this._messageService.show(message); From 4491f15a8c703670cc925899ae79fde838c7467d Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Sun, 18 Jun 2017 23:59:20 +0100 Subject: [PATCH 24/24] docs: Minor modal & message updates --- components/modal/active-modal.ts | 4 ++-- components/modal/modal.module.ts | 3 ++- components/modal/modal.ts | 7 ++++++- demo/src/app/pages/message/message.page.ts | 5 +++++ demo/src/app/pages/popup/popup.page.ts | 4 ++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/components/modal/active-modal.ts b/components/modal/active-modal.ts index 0f4151c2d..f35d8b9d4 100644 --- a/components/modal/active-modal.ts +++ b/components/modal/active-modal.ts @@ -22,8 +22,8 @@ export class ActiveModal implements SuiActiveModal { return this.componentRef.instance; } - constructor(instance:ModalConfig, componentRef:ComponentRef>) { - this.config = instance; + constructor(config:ModalConfig, componentRef:ComponentRef>) { + this.config = config; this.componentRef = componentRef; // Automatically destroy the modal component when it has been dismissed. diff --git a/components/modal/modal.module.ts b/components/modal/modal.module.ts index 6bf85aea8..2d1bf0e95 100644 --- a/components/modal/modal.module.ts +++ b/components/modal/modal.module.ts @@ -4,7 +4,7 @@ import { SuiDimmerModule } from "../dimmer/dimmer.module"; import { SuiTransitionModule } from "../transition/transition.module"; import { SuiUtilityModule } from "../util/util.module"; import { SuiModalService } from "./modal.service"; -import { SuiModal } from "./modal"; +import { SuiModal, IModal } from "./modal"; import { Modal, ModalResult, ModalControls } from "./modal-controls"; import { ActiveModal, SuiActiveModal } from "./active-modal"; import { ModalConfig, TemplateModalConfig, ComponentModalConfig, ModalSize } from "./modal-config"; @@ -35,6 +35,7 @@ export class SuiModalModule {} export { SuiModalService, Modal as SuiModal, + IModal, ModalResult, ModalControls, SuiActiveModal, diff --git a/components/modal/modal.ts b/components/modal/modal.ts index 1435cfa8c..479c27317 100644 --- a/components/modal/modal.ts +++ b/components/modal/modal.ts @@ -8,6 +8,11 @@ import { KeyCode, parseBooleanAttribute, getDocumentFontSize } from "../util/uti import { ModalControls, ModalResult } from "./modal-controls"; import { ModalConfig, ModalSize } from "./modal-config"; +export interface IModal { + approve(result:T):void; + deny(result:U):void; +} + @Component({ selector: "sui-modal", template: ` @@ -44,7 +49,7 @@ import { ModalConfig, ModalSize } from "./modal-config"; } `] }) -export class SuiModal implements OnInit, AfterViewInit { +export class SuiModal implements IModal, OnInit, AfterViewInit { @Input() // Determines whether the modal can be closed with a close button, clicking outside, or the escape key. public isClosable:boolean; diff --git a/demo/src/app/pages/message/message.page.ts b/demo/src/app/pages/message/message.page.ts index 80caedd6c..70407db23 100644 --- a/demo/src/app/pages/message/message.page.ts +++ b/demo/src/app/pages/message/message.page.ts @@ -55,6 +55,11 @@ export class MessagePage { name: "dismiss", type: "void", description: "Fires when the message is dismissed by the user." + }, + { + name: "click", + type: "void", + description: "Fires when the message is clicked by the user." } ] } diff --git a/demo/src/app/pages/popup/popup.page.ts b/demo/src/app/pages/popup/popup.page.ts index 6f9a2d1ac..0dcad529c 100644 --- a/demo/src/app/pages/popup/popup.page.ts +++ b/demo/src/app/pages/popup/popup.page.ts @@ -127,7 +127,7 @@ export class PopupPage { "right bottom" ]; - public position:string = "right bottom"; + public position:string = "top right"; public manualPopupMarkup:string = `
@@ -198,7 +198,7 @@ export class PopupExampleTemplate {} }) export class PopupExamplePlacement { @Input() - public position:string = "right bottom"; + public position:string = "top right"; } export const PopupPageComponents = [PopupPage, PopupExampleStandard, PopupExampleTemplate, PopupExamplePlacement];