Commit fb1e923a176adbb9d007beba3747eef35e892d2a
Exists in
master
and in
7 other branches
Merge branch 'events-hub' into 'master'
Events hub Added a service called EventsHubService to serve as central point for events propagated through the Noosfero Angular Application. See merge request !53
Showing
6 changed files
with
194 additions
and
54 deletions
Show diff stats
src/app/index.ts
1 | -import {bootstrap} from "ng-forward"; | 1 | +import {bootstrap, provide} from "ng-forward"; |
2 | import {noosferoModuleConfig} from "./index.config"; | 2 | import {noosferoModuleConfig} from "./index.config"; |
3 | import {noosferoAngularRunBlock} from "./index.run"; | 3 | import {noosferoAngularRunBlock} from "./index.run"; |
4 | import {MainComponent} from "./main/main.component"; | 4 | import {MainComponent} from "./main/main.component"; |
@@ -22,4 +22,13 @@ angular.module('noosfero.init', ['noosfero.templates.app', 'noosfero.templates.p | @@ -22,4 +22,13 @@ angular.module('noosfero.init', ['noosfero.templates.app', 'noosfero.templates.p | ||
22 | run(noosferoAngularRunBlock). | 22 | run(noosferoAngularRunBlock). |
23 | constant("moment", moment). | 23 | constant("moment", moment). |
24 | constant("AuthEvents", AuthEvents); | 24 | constant("AuthEvents", AuthEvents); |
25 | -bootstrap(MainComponent); | 25 | + |
26 | + | ||
27 | +import { EVENTS_HUB_KNOW_EVENT_NAMES } from './shared/services/events-hub.service'; | ||
28 | +import { NoosferoKnownEvents } from './known-events'; | ||
29 | + | ||
30 | +bootstrap(MainComponent, | ||
31 | + [ | ||
32 | + provide(EVENTS_HUB_KNOW_EVENT_NAMES, { useClass: NoosferoKnownEvents }) | ||
33 | + ] | ||
34 | +); |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +import { EventsHubKnownEventNames } from './shared/services/events-hub.service'; | ||
2 | + | ||
3 | +export class NoosferoKnownEvents implements EventsHubKnownEventNames { | ||
4 | + IMAGE_PROFILE_UPDATED: string = 'IMAGE_PROFILE_UPDATED'; | ||
5 | + PROFILE_INFO_UPDATED: string = 'PROFILE_INFO_UPDATED'; | ||
6 | + ARTICLE_UPDATED: string = 'ARTICLE_UPDATED'; | ||
7 | + | ||
8 | + constructor() { | ||
9 | + } | ||
10 | + | ||
11 | + getNames() { | ||
12 | + return Object.getOwnPropertyNames(this); | ||
13 | + } | ||
14 | +} | ||
0 | \ No newline at end of file | 15 | \ No newline at end of file |
src/app/main/main.component.spec.ts
@@ -4,8 +4,9 @@ import {TestComponentBuilder, ComponentFixture} from "ng-forward/cjs/testing/tes | @@ -4,8 +4,9 @@ import {TestComponentBuilder, ComponentFixture} from "ng-forward/cjs/testing/tes | ||
4 | 4 | ||
5 | import {quickCreateComponent} from "../../spec/helpers"; | 5 | import {quickCreateComponent} from "../../spec/helpers"; |
6 | import {getAngularServiceFactory} from "../../spec/helpers"; | 6 | import {getAngularServiceFactory} from "../../spec/helpers"; |
7 | +import { EVENTS_HUB_KNOW_EVENT_NAMES } from "../shared/services/events-hub.service"; | ||
7 | 8 | ||
8 | -describe("MainComponent", function() { | 9 | +describe("MainComponent", function () { |
9 | 10 | ||
10 | let localFixture: ComponentFixture; | 11 | let localFixture: ComponentFixture; |
11 | let $state: angular.ui.IStateService; | 12 | let $state: angular.ui.IStateService; |
@@ -34,6 +35,14 @@ describe("MainComponent", function() { | @@ -34,6 +35,14 @@ describe("MainComponent", function() { | ||
34 | { | 35 | { |
35 | useValue: environmentService | 36 | useValue: environmentService |
36 | }), | 37 | }), |
38 | + provide(EVENTS_HUB_KNOW_EVENT_NAMES, | ||
39 | + { | ||
40 | + useValue: [ | ||
41 | + 'IMAGE_PROFILE_UPDATED', | ||
42 | + 'PROFILE_INFO_UPDATED', | ||
43 | + 'ARTICLE_UPDATED' | ||
44 | + ] | ||
45 | + }), | ||
37 | ] | 46 | ] |
38 | }) | 47 | }) |
39 | class MainComponentParent { | 48 | class MainComponentParent { |
@@ -57,7 +66,7 @@ describe("MainComponent", function() { | @@ -57,7 +66,7 @@ describe("MainComponent", function() { | ||
57 | // navigates to the environment home | 66 | // navigates to the environment home |
58 | $state.go("main.environment.home"); | 67 | $state.go("main.environment.home"); |
59 | localFixture.detectChanges(); | 68 | localFixture.detectChanges(); |
60 | - // after changes were detected it checks the current $state route | 69 | + // after changes were detected it checks the current $state route |
61 | expect($state.current.name).toEqual("main.environment.home"); | 70 | expect($state.current.name).toEqual("main.environment.home"); |
62 | done(); | 71 | done(); |
63 | }); | 72 | }); |
src/app/main/main.component.ts
1 | import * as plugins from "../../plugins"; | 1 | import * as plugins from "../../plugins"; |
2 | -import {bundle, Component, StateConfig, Inject} from "ng-forward"; | ||
3 | -import {ArticleBlogComponent} from "./../article/types/blog/blog.component"; | ||
4 | - | ||
5 | -import {ArticleViewComponent} from "./../article/article-default-view.component"; | ||
6 | - | ||
7 | -import {ProfileComponent} from "../profile/profile.component"; | ||
8 | -import {BoxesComponent} from "../layout/boxes/boxes.component"; | ||
9 | -import {BlockContentComponent} from "../layout/blocks/block-content.component"; | ||
10 | -import {BlockComponent} from "../layout/blocks/block.component"; | ||
11 | -import {EnvironmentComponent} from "../environment/environment.component"; | ||
12 | -import {EnvironmentHomeComponent} from "../environment/environment-home.component"; | ||
13 | -import {PeopleBlockComponent} from "../layout/blocks/people/people-block.component"; | ||
14 | -import {DisplayContentBlockComponent} from "../layout/blocks/display-content/display-content-block.component"; | ||
15 | -import {LinkListBlockComponent} from "../layout/blocks/link-list/link-list-block.component"; | ||
16 | -import {RecentDocumentsBlockComponent} from "../layout/blocks/recent-documents/recent-documents-block.component"; | ||
17 | -import {ProfileImageBlockComponent} from "../layout/blocks/profile-image/profile-image-block.component"; | ||
18 | -import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html-block.component"; | ||
19 | -import {StatisticsBlockComponent} from "../layout/blocks/statistics/statistics-block.component"; | ||
20 | -import {PersonTagsPluginInterestsBlockComponent} from "../layout/blocks/person-tags-plugin-interests/person-tags-plugin-interests-block.component"; | ||
21 | -import {TagsBlockComponent} from "../layout/blocks/tags/tags-block.component"; | ||
22 | -import {CustomContentComponent} from "../profile/custom-content/custom-content.component"; | ||
23 | -import {RecentActivitiesPluginActivitiesBlockComponent} from "../layout/blocks/recent-activities-plugin-activities/recent-activities-plugin-activities-block.component"; | ||
24 | - | ||
25 | -import {MembersBlockComponent} from "../layout/blocks/members/members-block.component"; | ||
26 | -import {CommunitiesBlockComponent} from "../layout/blocks/communities/communities-block.component"; | ||
27 | - | ||
28 | -import {LoginBlockComponent} from "../layout/blocks/login-block/login-block.component"; | ||
29 | - | ||
30 | -import {NoosferoTemplate} from "../shared/pipes/noosfero-template.filter"; | ||
31 | -import {DateFormat} from "../shared/pipes/date-format.filter"; | ||
32 | - | ||
33 | -import {AuthService} from "../login/auth.service"; | ||
34 | -import {SessionService} from "../login/session.service"; | ||
35 | -import {EnvironmentService} from "./../../lib/ng-noosfero-api/http/environment.service"; | ||
36 | -import {NotificationService} from "../shared/services/notification.service"; | ||
37 | - | ||
38 | -import {BodyStateClassesService} from "./../layout/services/body-state-classes.service"; | ||
39 | - | ||
40 | -import {Navbar} from "../layout/navbar/navbar"; | ||
41 | - | ||
42 | -import {SidebarComponent} from "../layout/sidebar/sidebar.component"; | ||
43 | - | ||
44 | -import {MainBlockComponent} from "../layout/blocks/main/main-block.component"; | ||
45 | -import {HtmlEditorComponent} from "../shared/components/html-editor/html-editor.component"; | ||
46 | -import {PermissionDirective} from "../shared/components/permission/permission.directive"; | ||
47 | -import {SearchComponent} from "../search/search.component"; | ||
48 | -import {SearchFormComponent} from "../search/search-form/search-form.component"; | ||
49 | - | 2 | +import { bundle, Component, StateConfig, Inject } from "ng-forward"; |
3 | +import { ArticleBlogComponent } from "./../article/types/blog/blog.component"; | ||
4 | + | ||
5 | +import { ArticleViewComponent } from "./../article/article-default-view.component"; | ||
6 | + | ||
7 | +import { ProfileComponent } from "../profile/profile.component"; | ||
8 | +import { BoxesComponent } from "../layout/boxes/boxes.component"; | ||
9 | +import { BlockContentComponent } from "../layout/blocks/block-content.component"; | ||
10 | +import { BlockComponent } from "../layout/blocks/block.component"; | ||
11 | +import { EnvironmentComponent } from "../environment/environment.component"; | ||
12 | +import { EnvironmentHomeComponent } from "../environment/environment-home.component"; | ||
13 | +import { PeopleBlockComponent } from "../layout/blocks/people/people-block.component"; | ||
14 | +import { DisplayContentBlockComponent } from "../layout/blocks/display-content/display-content-block.component"; | ||
15 | +import { LinkListBlockComponent } from "../layout/blocks/link-list/link-list-block.component"; | ||
16 | +import { RecentDocumentsBlockComponent } from "../layout/blocks/recent-documents/recent-documents-block.component"; | ||
17 | +import { ProfileImageBlockComponent } from "../layout/blocks/profile-image/profile-image-block.component"; | ||
18 | +import { RawHTMLBlockComponent } from "../layout/blocks/raw-html/raw-html-block.component"; | ||
19 | +import { StatisticsBlockComponent } from "../layout/blocks/statistics/statistics-block.component"; | ||
20 | +import { PersonTagsPluginInterestsBlockComponent } from "../layout/blocks/person-tags-plugin-interests/person-tags-plugin-interests-block.component"; | ||
21 | +import { TagsBlockComponent } from "../layout/blocks/tags/tags-block.component"; | ||
22 | +import { CustomContentComponent } from "../profile/custom-content/custom-content.component"; | ||
23 | +import { RecentActivitiesPluginActivitiesBlockComponent } from "../layout/blocks/recent-activities-plugin-activities/recent-activities-plugin-activities-block.component"; | ||
24 | + | ||
25 | +import { MembersBlockComponent } from "../layout/blocks/members/members-block.component"; | ||
26 | +import { CommunitiesBlockComponent } from "../layout/blocks/communities/communities-block.component"; | ||
27 | + | ||
28 | +import { LoginBlockComponent } from "../layout/blocks/login-block/login-block.component"; | ||
29 | + | ||
30 | +import { NoosferoTemplate } from "../shared/pipes/noosfero-template.filter"; | ||
31 | +import { DateFormat } from "../shared/pipes/date-format.filter"; | ||
32 | + | ||
33 | +import { AuthService } from "../login/auth.service"; | ||
34 | +import { SessionService } from "../login/session.service"; | ||
35 | +import { EnvironmentService } from "./../../lib/ng-noosfero-api/http/environment.service"; | ||
36 | +import { NotificationService } from "../shared/services/notification.service"; | ||
37 | + | ||
38 | +import { BodyStateClassesService } from "./../layout/services/body-state-classes.service"; | ||
39 | + | ||
40 | +import { Navbar } from "../layout/navbar/navbar"; | ||
41 | + | ||
42 | +import { SidebarComponent } from "../layout/sidebar/sidebar.component"; | ||
43 | + | ||
44 | +import { MainBlockComponent } from "../layout/blocks/main/main-block.component"; | ||
45 | +import { HtmlEditorComponent } from "../shared/components/html-editor/html-editor.component"; | ||
46 | +import { PermissionDirective } from "../shared/components/permission/permission.directive"; | ||
47 | +import { SearchComponent } from "../search/search.component"; | ||
48 | +import { SearchFormComponent } from "../search/search-form/search-form.component"; | ||
49 | + | ||
50 | +import { EVENTS_HUB_KNOW_EVENT_NAMES, EventsHubService } from "../shared/services/events-hub.service"; | ||
51 | +import { NoosferoKnownEvents } from "../known-events"; | ||
50 | /** | 52 | /** |
51 | * @ngdoc controller | 53 | * @ngdoc controller |
52 | * @name main.MainContentComponent | 54 | * @name main.MainContentComponent |
@@ -62,12 +64,16 @@ import {SearchFormComponent} from "../search/search-form/search-form.component"; | @@ -62,12 +64,16 @@ import {SearchFormComponent} from "../search/search-form/search-form.component"; | ||
62 | templateUrl: "app/main/main.html", | 64 | templateUrl: "app/main/main.html", |
63 | providers: [AuthService, SessionService] | 65 | providers: [AuthService, SessionService] |
64 | }) | 66 | }) |
65 | -@Inject(BodyStateClassesService) | 67 | +@Inject(BodyStateClassesService, EVENTS_HUB_KNOW_EVENT_NAMES) |
66 | export class MainContentComponent { | 68 | export class MainContentComponent { |
67 | 69 | ||
68 | public themeSkin: string = 'skin-whbl'; | 70 | public themeSkin: string = 'skin-whbl'; |
69 | 71 | ||
70 | - constructor(private bodyStateClassesService: BodyStateClassesService) { | 72 | + constructor( |
73 | + private bodyStateClassesService: BodyStateClassesService, | ||
74 | + eventsNames: NoosferoKnownEvents, | ||
75 | + eventsHubService: EventsHubService | ||
76 | + ) { | ||
71 | bodyStateClassesService.start({ | 77 | bodyStateClassesService.start({ |
72 | skin: this.themeSkin | 78 | skin: this.themeSkin |
73 | }); | 79 | }); |
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +import { OpaqueToken } from 'ng-forward'; | ||
2 | +import { EventsHubService, EventsHubKnownEventNames } from './events-hub.service'; | ||
3 | + | ||
4 | + | ||
5 | +describe("EventsHubService", () => { | ||
6 | + let eventsHubService: EventsHubService; | ||
7 | + let event1 = 'Event 1'; | ||
8 | + let eventsHubKnownEventNames = <EventsHubKnownEventNames>{ getNames: () => { return [ event1]; }}; | ||
9 | + it("emits events for the known events", (done) => { | ||
10 | + | ||
11 | + let eventListener = () => { | ||
12 | + }; | ||
13 | + // creates the events hub service which known the event "Event1" | ||
14 | + eventsHubService = new EventsHubService(eventsHubKnownEventNames); | ||
15 | + // subscribe to the event passing the done Function as the eventListener | ||
16 | + // if the event emits works the done function is called and the | ||
17 | + // test will pass | ||
18 | + eventsHubService.subscribeToEvent<any>(event1, done); | ||
19 | + // emits the event | ||
20 | + eventsHubService.emitEvent(event1, null); | ||
21 | + }); | ||
22 | + | ||
23 | + it("throws error when trying to emit an unknow event", () => { | ||
24 | + let eventListener = () => { | ||
25 | + }; | ||
26 | + // creates the events hub service which known the event "Event1" | ||
27 | + eventsHubService = new EventsHubService(eventsHubKnownEventNames); | ||
28 | + | ||
29 | + // emits the event | ||
30 | + expect( | ||
31 | + () => { eventsHubService.emitEvent('NotKnownEvent', null); } | ||
32 | + ).toThrowError('Unknown event named NotKnownEvent'); | ||
33 | + }); | ||
34 | + | ||
35 | + it("throws error when trying to subscribe to an unknow event", () => { | ||
36 | + let eventListener = () => { | ||
37 | + }; | ||
38 | + // creates the events hub service which known the event "Event1" | ||
39 | + eventsHubService = new EventsHubService(eventsHubKnownEventNames); | ||
40 | + | ||
41 | + // emits the event | ||
42 | + expect( | ||
43 | + () => { eventsHubService.subscribeToEvent<void>('NotKnownEvent', () => {}); } | ||
44 | + ).toThrowError('Unknown event named NotKnownEvent'); | ||
45 | + }); | ||
46 | +}); | ||
0 | \ No newline at end of file | 47 | \ No newline at end of file |
@@ -0,0 +1,56 @@ | @@ -0,0 +1,56 @@ | ||
1 | +import { Injectable, Inject, OpaqueToken, EventEmitter } from 'ng-forward'; | ||
2 | + | ||
3 | +export const EVENTS_HUB_KNOW_EVENT_NAMES = new OpaqueToken('EVENTS_HUB_KNOW_EVENT_NAMES'); | ||
4 | + | ||
5 | +export interface EventsHubKnownEventNames { | ||
6 | + getNames(): string[]; | ||
7 | +} | ||
8 | + | ||
9 | +function isEventsHubKnownEventNames(object: any): object is EventsHubKnownEventNames { | ||
10 | + return 'getNames' in object; | ||
11 | +} | ||
12 | + | ||
13 | +@Injectable() | ||
14 | +@Inject(EVENTS_HUB_KNOW_EVENT_NAMES) | ||
15 | +export class EventsHubService { | ||
16 | + | ||
17 | + private emitters: Map<string, EventEmitter<any>>; | ||
18 | + private knownEvents: string[] = []; | ||
19 | + | ||
20 | + constructor(private eventsHubKnownEventNames: EventsHubKnownEventNames | string[]) { | ||
21 | + if (isEventsHubKnownEventNames(eventsHubKnownEventNames)) { | ||
22 | + this.knownEvents = eventsHubKnownEventNames.getNames(); | ||
23 | + } else if (Array.isArray(eventsHubKnownEventNames)) { | ||
24 | + this.knownEvents = eventsHubKnownEventNames; | ||
25 | + } | ||
26 | + | ||
27 | + this.emitters = new Map<string, EventEmitter<any>>(); | ||
28 | + this.setupEmitters(); | ||
29 | + } | ||
30 | + | ||
31 | + emitEvent(eventType: string, payload?: any) { | ||
32 | + this.checkKnownEvent(eventType); | ||
33 | + let event = this.emitters.get(eventType); | ||
34 | + if ( event ) this.emitters.get(eventType).next(payload); | ||
35 | + } | ||
36 | + | ||
37 | + subscribeToEvent<T>(eventType: string, generatorOrNext?: ((p?: T) => void), error?: any, complete?: any) { | ||
38 | + this.checkKnownEvent(eventType); | ||
39 | + let event = this.emitters.get(eventType); | ||
40 | + if (event) event.subscribe(generatorOrNext, error, complete); | ||
41 | + } | ||
42 | + | ||
43 | + private setupEmitters() { | ||
44 | + for (let i: number = 0; i < this.knownEvents.length; i++) { | ||
45 | + this.emitters.set(this.knownEvents[i], new EventEmitter<any>()); | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | + private checkKnownEvent(eventType: string) { | ||
50 | + if (!this.emitters.has(eventType)) { | ||
51 | + throw new Error('Unknown event named ' + eventType.toString()); | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + | ||
56 | +} | ||
0 | \ No newline at end of file | 57 | \ No newline at end of file |