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 | 2 | import {noosferoModuleConfig} from "./index.config"; |
3 | 3 | import {noosferoAngularRunBlock} from "./index.run"; |
4 | 4 | import {MainComponent} from "./main/main.component"; |
... | ... | @@ -22,4 +22,13 @@ angular.module('noosfero.init', ['noosfero.templates.app', 'noosfero.templates.p |
22 | 22 | run(noosferoAngularRunBlock). |
23 | 23 | constant("moment", moment). |
24 | 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 @@ |
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 | 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 | 4 | |
5 | 5 | import {quickCreateComponent} from "../../spec/helpers"; |
6 | 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 | 11 | let localFixture: ComponentFixture; |
11 | 12 | let $state: angular.ui.IStateService; |
... | ... | @@ -34,6 +35,14 @@ describe("MainComponent", function() { |
34 | 35 | { |
35 | 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 | 48 | class MainComponentParent { |
... | ... | @@ -57,7 +66,7 @@ describe("MainComponent", function() { |
57 | 66 | // navigates to the environment home |
58 | 67 | $state.go("main.environment.home"); |
59 | 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 | 70 | expect($state.current.name).toEqual("main.environment.home"); |
62 | 71 | done(); |
63 | 72 | }); | ... | ... |
src/app/main/main.component.ts
1 | 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 | 53 | * @ngdoc controller |
52 | 54 | * @name main.MainContentComponent |
... | ... | @@ -62,12 +64,16 @@ import {SearchFormComponent} from "../search/search-form/search-form.component"; |
62 | 64 | templateUrl: "app/main/main.html", |
63 | 65 | providers: [AuthService, SessionService] |
64 | 66 | }) |
65 | -@Inject(BodyStateClassesService) | |
67 | +@Inject(BodyStateClassesService, EVENTS_HUB_KNOW_EVENT_NAMES) | |
66 | 68 | export class MainContentComponent { |
67 | 69 | |
68 | 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 | 77 | bodyStateClassesService.start({ |
72 | 78 | skin: this.themeSkin |
73 | 79 | }); | ... | ... |
... | ... | @@ -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 | 47 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 57 | \ No newline at end of file | ... | ... |