Merge Request #4
... | ... | @@ -27,7 +27,8 @@ describe("Components", () => { |
27 | 27 | providers: [ |
28 | 28 | helpers.createProviderToValue('CommentService', helpers.mocks.commentService), |
29 | 29 | helpers.provideFilters("translateFilter"), |
30 | - helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService) | |
30 | + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService), | |
31 | + helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})) | |
31 | 32 | ] |
32 | 33 | }) |
33 | 34 | class ArticleContainerComponent { |
... | ... | @@ -64,7 +65,8 @@ describe("Components", () => { |
64 | 65 | providers: [ |
65 | 66 | helpers.createProviderToValue('CommentService', helpers.mocks.commentService), |
66 | 67 | helpers.provideFilters("translateFilter"), |
67 | - helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService) | |
68 | + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService), | |
69 | + helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})) | |
68 | 70 | ] |
69 | 71 | }) |
70 | 72 | class ArticleContainerComponent { | ... | ... |
... | ... | @@ -2,6 +2,7 @@ import {Provider, provide, Component} from 'ng-forward'; |
2 | 2 | import * as helpers from "../../../spec/helpers"; |
3 | 3 | |
4 | 4 | import {CommentComponent} from './comment.component'; |
5 | +import {PostCommentComponent} from './post-comment/post-comment.component'; | |
5 | 6 | |
6 | 7 | const htmlTemplate: string = '<noosfero-comment [article]="ctrl.article" [comment]="ctrl.comment"></noosfero-comment>'; |
7 | 8 | |
... | ... | @@ -10,35 +11,56 @@ describe("Components", () => { |
10 | 11 | |
11 | 12 | beforeEach(angular.mock.module("templates")); |
12 | 13 | |
13 | - @Component({ selector: 'test-container-component', directives: [CommentComponent], template: htmlTemplate, providers: helpers.provideFilters("translateFilter") }) | |
14 | - class ContainerComponent { | |
15 | - article = { id: 1 }; | |
16 | - comment = { title: "title", body: "body" }; | |
14 | + let postCommentEventService = jasmine.createSpyObj("postCommentEventService", ["subscribe"]); | |
15 | + | |
16 | + function createComponent() { | |
17 | + let providers = [ | |
18 | + new Provider('PostCommentEventService', { useValue: postCommentEventService }) | |
19 | + ].concat(helpers.provideFilters("translateFilter")); | |
20 | + | |
21 | + @Component({ selector: 'test-container-component', directives: [CommentComponent], template: htmlTemplate, providers: providers }) | |
22 | + class ContainerComponent { | |
23 | + article = { id: 1 }; | |
24 | + comment = { title: "title", body: "body" }; | |
25 | + } | |
26 | + return helpers.createComponentFromClass(ContainerComponent); | |
17 | 27 | } |
18 | 28 | |
19 | 29 | it("render a comment", done => { |
20 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
30 | + createComponent().then(fixture => { | |
21 | 31 | expect(fixture.debugElement.queryAll(".comment").length).toEqual(1); |
22 | 32 | done(); |
23 | 33 | }); |
24 | 34 | }); |
25 | 35 | |
26 | 36 | it("not render a post comment tag in the beginning", done => { |
27 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
37 | + createComponent().then(fixture => { | |
28 | 38 | expect(fixture.debugElement.queryAll("noosfero-post-comment").length).toEqual(0); |
29 | 39 | done(); |
30 | 40 | }); |
31 | 41 | }); |
32 | 42 | |
33 | - it("render a post comment tag when click in reply", done => { | |
34 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
43 | + it("set show reply to true when click reply", done => { | |
44 | + createComponent().then(fixture => { | |
35 | 45 | let component: CommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance; |
36 | 46 | component.reply(); |
37 | - fixture.debugElement.getLocal("$rootScope").$apply(); | |
38 | - expect(fixture.debugElement.queryAll("noosfero-post-comment").length).toEqual(1); | |
47 | + expect(component.showReply).toBeTruthy(1); | |
39 | 48 | done(); |
40 | 49 | }); |
41 | 50 | }); |
42 | 51 | |
52 | + it("close form when receive a reply", done => { | |
53 | + let func: Function; | |
54 | + postCommentEventService.subscribe = (fn: Function) => { | |
55 | + func = fn; | |
56 | + }; | |
57 | + createComponent().then(fixture => { | |
58 | + let component = fixture.debugElement.componentViewChildren[0]; | |
59 | + component.componentInstance.showReply = true; | |
60 | + func(<noosfero.Comment>{}); | |
61 | + expect(component.componentInstance.showReply).toEqual(false); | |
62 | + done(); | |
63 | + }); | |
64 | + }); | |
43 | 65 | }); |
44 | 66 | }); | ... | ... |
1 | -import { Input, Component } from 'ng-forward'; | |
1 | +import { Inject, Input, Component } from 'ng-forward'; | |
2 | +import { PostCommentComponent } from "./post-comment/post-comment.component"; | |
3 | +import { PostCommentEventService } from "./post-comment/post-comment-event.service"; | |
2 | 4 | |
3 | 5 | @Component({ |
4 | 6 | selector: 'noosfero-comment', |
5 | 7 | templateUrl: 'app/article/comment/comment.html' |
6 | 8 | }) |
9 | +@Inject(PostCommentEventService, "$scope") | |
7 | 10 | export class CommentComponent { |
8 | 11 | |
9 | 12 | @Input() comment: noosfero.Comment; |
... | ... | @@ -11,7 +14,14 @@ export class CommentComponent { |
11 | 14 | |
12 | 15 | showReply: boolean = false; |
13 | 16 | |
17 | + constructor(postCommentEventService: PostCommentEventService, private $scope: ng.IScope) { | |
18 | + postCommentEventService.subscribe((comment: noosfero.Comment) => { | |
19 | + this.showReply = false; | |
20 | + this.$scope.$apply(); | |
21 | + }); | |
22 | + } | |
23 | + | |
14 | 24 | reply() { |
15 | - this.showReply = true; | |
25 | + this.showReply = !this.showReply; | |
16 | 26 | } |
17 | 27 | } | ... | ... |
... | ... | @@ -10,16 +10,12 @@ |
10 | 10 | <h4 class="media-heading">{{ctrl.comment.author.name}}</h4> |
11 | 11 | </a> |
12 | 12 | <span class="date" am-time-ago="ctrl.comment.created_at | dateFormat"></span> |
13 | - <a href="#" (click)="ctrl.reply()"> | |
14 | - <span class="pull-right small text-muted"> | |
15 | - {{"comment.reply" | translate}} | |
16 | - </span> | |
17 | - </a> | |
18 | 13 | </div> |
19 | 14 | <div class="title">{{ctrl.comment.title}}</div> |
20 | 15 | <div class="body">{{ctrl.comment.body}}</div> |
16 | + <a href="#" (click)="ctrl.reply()" class="small text-muted"> | |
17 | + {{"comment.reply" | translate}} | |
18 | + </a> | |
21 | 19 | </div> |
22 | - | |
23 | - <noosfero-post-comment ng-if="ctrl.showReply" [article]="ctrl.article" [reply-of]="ctrl.comment"></noosfero-post-comment> | |
24 | - | |
20 | + <noosfero-comments [show-form]="ctrl.showReply" [article]="ctrl.article" [parent]="ctrl.comment"></noosfero-comments> | |
25 | 21 | </div> | ... | ... |
... | ... | @@ -13,8 +13,7 @@ |
13 | 13 | min-width: 40px; |
14 | 14 | } |
15 | 15 | .media-body { |
16 | - background-color: #F9F9F9; | |
17 | - padding: 10px; | |
16 | + padding: 0 10px 10px 10px; | |
18 | 17 | } |
19 | 18 | noosfero-profile-image { |
20 | 19 | img { |
... | ... | @@ -28,5 +27,8 @@ |
28 | 27 | font-size: 1.7em; |
29 | 28 | } |
30 | 29 | } |
30 | + .comments { | |
31 | + margin-left: 30px; | |
32 | + } | |
31 | 33 | } |
32 | 34 | } | ... | ... |
... | ... | @@ -17,38 +17,78 @@ describe("Components", () => { |
17 | 17 | commentService.getByArticle = jasmine.createSpy("getByArticle") |
18 | 18 | .and.returnValue(helpers.mocks.promiseResultTemplate({ data: comments })); |
19 | 19 | |
20 | - let providers = [ | |
21 | - new Provider('CommentService', { useValue: commentService }), | |
22 | - new Provider('NotificationService', { useValue: helpers.mocks.notificationService }) | |
23 | - ].concat(helpers.provideFilters("translateFilter")); | |
24 | - | |
25 | - @Component({ selector: 'test-container-component', directives: [CommentsComponent], template: htmlTemplate, providers: providers }) | |
26 | - class ContainerComponent { | |
27 | - article = { id: 1 }; | |
20 | + let emitEvent: Function; | |
21 | + let postCommentEventService = { | |
22 | + subscribe: (fn: Function) => { | |
23 | + emitEvent = fn; | |
24 | + } | |
25 | + }; | |
26 | + | |
27 | + let properties = { article: { id: 1 }, parent: <any>null }; | |
28 | + function createComponent() { | |
29 | + // postCommentEventService = jasmine.createSpyObj("postCommentEventService", ["subscribe"]); | |
30 | + let providers = [ | |
31 | + helpers.createProviderToValue('CommentService', commentService), | |
32 | + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService), | |
33 | + helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})), | |
34 | + new Provider('PostCommentEventService', { useValue: postCommentEventService }) | |
35 | + ].concat(helpers.provideFilters("translateFilter")); | |
36 | + | |
37 | + return helpers.quickCreateComponent({ | |
38 | + providers: providers, | |
39 | + directives: [CommentsComponent], | |
40 | + template: htmlTemplate, | |
41 | + properties: properties | |
42 | + }); | |
28 | 43 | } |
29 | 44 | |
45 | + | |
30 | 46 | it("render comments associated to an article", done => { |
31 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
47 | + createComponent().then(fixture => { | |
32 | 48 | expect(fixture.debugElement.queryAll("noosfero-comment").length).toEqual(2); |
33 | 49 | done(); |
34 | 50 | }); |
35 | 51 | }); |
36 | 52 | |
37 | 53 | it("render a post comment tag", done => { |
38 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
54 | + createComponent().then(fixture => { | |
39 | 55 | expect(fixture.debugElement.queryAll("noosfero-post-comment").length).toEqual(1); |
40 | 56 | done(); |
41 | 57 | }); |
42 | 58 | }); |
43 | 59 | |
44 | - it("update comments list when receive an event", done => { | |
45 | - helpers.createComponentFromClass(ContainerComponent).then(fixture => { | |
46 | - fixture.debugElement.getLocal("$rootScope").$emit(PostCommentComponent.EVENT_COMMENT_RECEIVED, { id: 1 }); | |
47 | - fixture.debugElement.getLocal("$rootScope").$apply(); | |
60 | + it("update comments list when receive an reply", done => { | |
61 | + properties.parent = { id: 3 }; | |
62 | + createComponent().then(fixture => { | |
63 | + emitEvent(<noosfero.Comment>{ id: 1, reply_of: { id: 3 } }); | |
48 | 64 | expect(fixture.debugElement.queryAll("noosfero-comment").length).toEqual(3); |
49 | 65 | done(); |
50 | 66 | }); |
51 | 67 | }); |
52 | 68 | |
69 | + it("load comments for next page", done => { | |
70 | + createComponent().then(fixture => { | |
71 | + let headers = jasmine.createSpy("headers").and.returnValue(3); | |
72 | + commentService.getByArticle = jasmine.createSpy("getByArticle") | |
73 | + .and.returnValue(helpers.mocks.promiseResultTemplate({ data: { id: 4 }, headers: headers })); | |
74 | + let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance; | |
75 | + component.loadNextPage(); | |
76 | + expect(component['page']).toEqual(3); | |
77 | + expect(component.comments.length).toEqual(3); | |
78 | + expect(component['total']).toEqual(3); | |
79 | + done(); | |
80 | + }); | |
81 | + }); | |
82 | + | |
83 | + it("not display more when there is no more comments to load", done => { | |
84 | + createComponent().then(fixture => { | |
85 | + let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance; | |
86 | + component['total'] = 0; | |
87 | + component.parent = null; | |
88 | + expect(component.displayMore()).toBeFalsy(); | |
89 | + done(); | |
90 | + }); | |
91 | + }); | |
92 | + | |
53 | 93 | }); |
54 | 94 | }); | ... | ... |
... | ... | @@ -2,27 +2,55 @@ import { Inject, Input, Component, provide } from 'ng-forward'; |
2 | 2 | import { PostCommentComponent } from "./post-comment/post-comment.component"; |
3 | 3 | import { CommentService } from "../../../lib/ng-noosfero-api/http/comment.service"; |
4 | 4 | import { CommentComponent } from "./comment.component"; |
5 | +import { PostCommentEventService } from "./post-comment/post-comment-event.service"; | |
5 | 6 | |
6 | 7 | @Component({ |
7 | 8 | selector: 'noosfero-comments', |
8 | 9 | templateUrl: 'app/article/comment/comments.html', |
9 | 10 | directives: [PostCommentComponent, CommentComponent] |
10 | 11 | }) |
11 | -@Inject(CommentService, "$rootScope") | |
12 | +@Inject(CommentService, PostCommentEventService, "$scope") | |
12 | 13 | export class CommentsComponent { |
13 | 14 | |
14 | 15 | comments: noosfero.Comment[] = []; |
16 | + @Input() showForm = true; | |
15 | 17 | @Input() article: noosfero.Article; |
18 | + @Input() parent: noosfero.Comment; | |
19 | + protected page = 1; | |
20 | + protected perPage = 5; | |
21 | + protected total = 0; | |
16 | 22 | |
17 | - constructor(private commentService: CommentService, private $rootScope: ng.IScope) { | |
18 | - $rootScope.$on(PostCommentComponent.EVENT_COMMENT_RECEIVED, (event: ng.IAngularEvent, comment: noosfero.Comment) => { | |
19 | - this.comments.push(comment); | |
23 | + constructor(protected commentService: CommentService, private postCommentEventService: PostCommentEventService, private $scope: ng.IScope) { } | |
24 | + | |
25 | + ngOnInit() { | |
26 | + if (this.parent) { | |
27 | + this.comments = this.parent.replies; | |
28 | + } else { | |
29 | + this.loadNextPage(); | |
30 | + } | |
31 | + this.postCommentEventService.subscribe((comment: noosfero.Comment) => { | |
32 | + if ((!this.parent && !comment.reply_of) || (comment.reply_of && this.parent && comment.reply_of.id === this.parent.id)) { | |
33 | + if (!this.comments) this.comments = []; | |
34 | + this.comments.push(comment); | |
35 | + this.$scope.$apply(); | |
36 | + } | |
20 | 37 | }); |
21 | 38 | } |
22 | 39 | |
23 | - ngOnInit() { | |
24 | - this.commentService.getByArticle(this.article).then((result: noosfero.RestResult<noosfero.Comment[]>) => { | |
25 | - this.comments = result.data; | |
40 | + loadComments() { | |
41 | + return this.commentService.getByArticle(this.article, { page: this.page, per_page: this.perPage }); | |
42 | + } | |
43 | + | |
44 | + loadNextPage() { | |
45 | + this.loadComments().then((result: noosfero.RestResult<noosfero.Comment[]>) => { | |
46 | + this.comments = this.comments.concat(result.data); | |
47 | + this.total = result.headers ? result.headers("total") : this.comments.length; | |
48 | + this.page++; | |
26 | 49 | }); |
27 | 50 | } |
51 | + | |
52 | + displayMore() { | |
53 | + let pages = Math.ceil(this.total / this.perPage); | |
54 | + return !this.parent && pages >= this.page; | |
55 | + } | |
28 | 56 | } | ... | ... |
1 | 1 | <div class="comments"> |
2 | - <noosfero-post-comment [article]="ctrl.article"></noosfero-post-comment> | |
2 | + <noosfero-post-comment ng-if="ctrl.showForm" [article]="ctrl.article" [parent]="ctrl.parent"></noosfero-post-comment> | |
3 | 3 | |
4 | 4 | <div class="comments-list"> |
5 | - <noosfero-comment ng-repeat="comment in ctrl.comments" [comment]="comment" [article]="ctrl.article"></noosfero-comment> | |
5 | + <noosfero-comment ng-repeat="comment in ctrl.comments | orderBy: 'created_at':true" [comment]="comment" [article]="ctrl.article"></noosfero-comment> | |
6 | 6 | </div> |
7 | + <button type="button" ng-if="ctrl.displayMore()" class="more-comments btn btn-default btn-block" ng-click="ctrl.loadNextPage()">{{"comment.pagination.more" | translate}}</button> | |
2 |
|
|
7 | 8 | </div> | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +import {PostCommentEventService} from "./post-comment-event.service"; | |
2 | +import {ComponentTestHelper, createClass} from '../../../../spec/component-test-helper'; | |
3 | +import * as helpers from "../../../../spec/helpers"; | |
4 | +import {Provider} from 'ng-forward'; | |
5 | +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | |
6 | + | |
7 | +describe("Services", () => { | |
8 | + describe("Comment Paragraph Event Service", () => { | |
9 | + let eventService: PostCommentEventService; | |
10 | + | |
11 | + beforeEach(() => { | |
12 | + eventService = new PostCommentEventService(); | |
13 | + eventService['eventEmitter'] = jasmine.createSpyObj("eventEmitter", ["next", "subscribe"]); | |
14 | + }); | |
15 | + | |
16 | + it('subscribe to post comment event', () => { | |
17 | + eventService.subscribe(() => { }); | |
18 | + expect(eventService['eventEmitter'].subscribe).toHaveBeenCalled(); | |
19 | + }); | |
20 | + | |
21 | + it('emit event when post comment', () => { | |
22 | + eventService.emit(<noosfero.Comment>{}); | |
23 | + expect(eventService['eventEmitter'].next).toHaveBeenCalled(); | |
24 | + }); | |
25 | + }); | |
26 | +}); | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +import {Injectable, EventEmitter} from "ng-forward"; | |
2 | + | |
3 | +@Injectable() | |
4 | +export class PostCommentEventService { | |
5 | + | |
6 | + private eventEmitter: EventEmitter<noosfero.Comment>; | |
7 | + | |
8 | + constructor() { | |
9 | + this.eventEmitter = new EventEmitter(); | |
10 | + } | |
11 | + | |
12 | + emit(comment: noosfero.Comment) { | |
13 | + this.eventEmitter.next(comment); | |
14 | + } | |
15 | + | |
16 | + subscribe(fn: (comment: noosfero.Comment) => void) { | |
17 | + this.eventEmitter.subscribe(fn); | |
18 | + } | |
19 | +} | ... | ... |
... | ... | @@ -11,9 +11,13 @@ describe("Components", () => { |
11 | 11 | beforeEach(angular.mock.module("templates")); |
12 | 12 | |
13 | 13 | let commentService = jasmine.createSpyObj("commentService", ["createInArticle"]); |
14 | + let postCommentEventService = jasmine.createSpyObj("postCommentEventService", ["emit"]); | |
15 | + let user = {}; | |
14 | 16 | let providers = [ |
15 | 17 | new Provider('CommentService', { useValue: commentService }), |
16 | - new Provider('NotificationService', { useValue: helpers.mocks.notificationService }) | |
18 | + new Provider('NotificationService', { useValue: helpers.mocks.notificationService }), | |
19 | + new Provider('SessionService', { useValue: helpers.mocks.sessionWithCurrentUser(user) }), | |
20 | + new Provider('PostCommentEventService', { useValue: postCommentEventService }) | |
17 | 21 | ].concat(helpers.provideFilters("translateFilter")); |
18 | 22 | |
19 | 23 | @Component({ selector: 'test-container-component', directives: [PostCommentComponent], template: htmlTemplate, providers: providers }) |
... | ... | @@ -33,9 +37,8 @@ describe("Components", () => { |
33 | 37 | helpers.createComponentFromClass(ContainerComponent).then(fixture => { |
34 | 38 | let component: PostCommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance; |
35 | 39 | commentService.createInArticle = jasmine.createSpy("createInArticle").and.returnValue(helpers.mocks.promiseResultTemplate({ data: {} })); |
36 | - component["$rootScope"].$emit = jasmine.createSpy("$emit"); | |
37 | 40 | component.save(); |
38 | - expect(component["$rootScope"].$emit).toHaveBeenCalledWith(PostCommentComponent.EVENT_COMMENT_RECEIVED, jasmine.any(Object)); | |
41 | + expect(postCommentEventService.emit).toHaveBeenCalled(); | |
39 | 42 | done(); |
40 | 43 | }); |
41 | 44 | }); |
... | ... | @@ -55,9 +58,9 @@ describe("Components", () => { |
55 | 58 | helpers.createComponentFromClass(ContainerComponent).then(fixture => { |
56 | 59 | let component: PostCommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance; |
57 | 60 | component.comment = <any>{ reply_of_id: null }; |
58 | - component.replyOf = <any>{ id: 10 }; | |
61 | + component.parent = <any>{ id: 10 }; | |
59 | 62 | component.save(); |
60 | - expect(component.comment.reply_of_id).toEqual(component.replyOf.id); | |
63 | + expect(component.comment.reply_of_id).toEqual(component.parent.id); | |
61 | 64 | done(); |
62 | 65 | }); |
63 | 66 | }); | ... | ... |
1 | 1 | import { Inject, Input, Component } from 'ng-forward'; |
2 | 2 | import { CommentService } from "../../../../lib/ng-noosfero-api/http/comment.service"; |
3 | 3 | import { NotificationService } from "../../../shared/services/notification.service"; |
4 | +import { SessionService } from "../../../login"; | |
5 | +import { PostCommentEventService } from "./post-comment-event.service"; | |
4 | 6 | |
5 | 7 | @Component({ |
6 | 8 | selector: 'noosfero-post-comment', |
7 | 9 | templateUrl: 'app/article/comment/post-comment/post-comment.html' |
8 | 10 | }) |
9 | -@Inject(CommentService, NotificationService, "$rootScope") | |
11 | +@Inject(CommentService, NotificationService, SessionService, PostCommentEventService) | |
10 | 12 | export class PostCommentComponent { |
11 | 13 | |
12 | 14 | public static EVENT_COMMENT_RECEIVED = "comment.received"; |
13 | 15 | |
14 | 16 | @Input() article: noosfero.Article; |
15 | - @Input() replyOf: noosfero.Comment; | |
17 | + @Input() parent: noosfero.Comment; | |
16 | 18 | |
17 | - comment: noosfero.Comment; | |
19 | + comment = <noosfero.Comment>{}; | |
20 | + private currentUser: noosfero.User; | |
18 | 21 | |
19 | - constructor(private commentService: CommentService, private notificationService: NotificationService, private $rootScope: ng.IScope) { } | |
22 | + constructor(private commentService: CommentService, | |
23 | + private notificationService: NotificationService, | |
24 | + private session: SessionService, | |
25 | + private postCommentEventService: PostCommentEventService) { | |
26 | + this.currentUser = this.session.currentUser(); | |
27 | + } | |
20 | 28 | |
21 | 29 | save() { |
22 | - if (this.replyOf && this.comment) { | |
23 | - this.comment.reply_of_id = this.replyOf.id; | |
30 | + if (this.parent && this.comment) { | |
31 | + this.comment.reply_of_id = this.parent.id; | |
24 | 32 | } |
25 | 33 | this.commentService.createInArticle(this.article, this.comment).then((result: noosfero.RestResult<noosfero.Comment>) => { |
26 | - this.$rootScope.$emit(PostCommentComponent.EVENT_COMMENT_RECEIVED, result.data); | |
27 | - this.notificationService.success({ title: "Good job!", message: "Comment saved!" }); | |
34 | + this.postCommentEventService.emit(result.data); | |
35 | + this.comment.body = ""; | |
36 | + this.notificationService.success({ title: "comment.post.success.title", message: "comment.post.success.message" }); | |
28 | 37 | }); |
29 | 38 | } |
30 | 39 | } | ... | ... |
1 | -<form> | |
1 | +<form class="clearfix post-comment"> | |
2 | 2 | <div class="form-group"> |
3 | - <textarea class="form-control custom-control" rows="3" ng-model="ctrl.comment.body"></textarea> | |
3 | + <div class="comment media"> | |
4 | + <div class="media-left"> | |
5 | + <a ui-sref="main.profile.home({profile: ctrl.currentUser.person.identifier})"> | |
6 | + <noosfero-profile-image [profile]="ctrl.currentUser.person"></noosfero-profile-image> | |
7 | + </a> | |
8 | + </div> | |
9 | + <div class="media-body"> | |
10 | + <textarea class="form-control custom-control" rows="1" ng-model="ctrl.comment.body" placeholder="{{'comment.post.placeholder' | translate}}"></textarea> | |
11 | + <button ng-show="ctrl.comment.body" type="submit" class="btn btn-default pull-right ng-hide" ng-click="ctrl.save()">{{"comment.post" | translate}}</button> | |
12 | + </div> | |
13 | + </div> | |
4 | 14 | </div> |
5 | - <button type="submit" class="btn btn-default" ng-click="ctrl.save()">{{"comment.post" | translate}}</button> | |
6 | 15 | </form> | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +.comments { | |
2 | + .post-comment { | |
3 | + .media { | |
4 | + border-top: 2px solid #F3F3F3; | |
5 | + padding-top: 10px; | |
6 | + .media-left { | |
7 | + padding: 10px 0; | |
8 | + } | |
9 | + button { | |
1 |
|
|
10 | + margin-top: 10px; | |
11 | + &.ng-hide-add { | |
12 | + animation: 0.5s lightSpeedOut ease; | |
13 | + } | |
14 | + &.ng-hide-remove { | |
15 | + animation: 0.5s lightSpeedIn ease; | |
16 | + } | |
17 | + } | |
18 | + } | |
19 | + } | |
20 | +} | ... | ... |
... | ... | @@ -20,13 +20,7 @@ export class NotificationService { |
20 | 20 | title = NotificationService.DEFAULT_ERROR_TITLE, |
21 | 21 | showConfirmButton = true |
22 | 22 | } = {}) { |
23 | - this.$log.debug("Notification error:", title, message, this.translatorService.currentLanguage()); | |
24 | - this.SweetAlert.swal({ | |
25 | - title: this.translatorService.translate(title), | |
26 | - text: this.translatorService.translate(message), | |
27 | - type: "error", | |
28 | - showConfirmButton: showConfirmButton | |
29 | - }); | |
23 | + this.showMessage({ title: title, text: message, showConfirmButton: showConfirmButton, type: "error" }); | |
30 | 24 | } |
31 | 25 | |
32 | 26 | httpError(status: number, data: any): boolean { |
... | ... | @@ -39,11 +33,17 @@ export class NotificationService { |
39 | 33 | message, |
40 | 34 | timer = NotificationService.DEFAULT_SUCCESS_TIMER |
41 | 35 | }) { |
36 | + this.showMessage({ title: title, text: message, timer: timer }); | |
37 | + } | |
38 | + | |
39 | + private showMessage({title, text, type = "success", timer = null, showConfirmButton = true}) { | |
40 | + this.$log.debug("Notification message:", title, text, type, this.translatorService.currentLanguage()); | |
42 | 41 | this.SweetAlert.swal({ |
43 | - title: title, | |
44 | - text: message, | |
45 | - type: "success", | |
46 | - timer: timer | |
42 | + title: this.translatorService.translate(title), | |
43 | + text: this.translatorService.translate(text), | |
44 | + type: type, | |
45 | + timer: timer, | |
46 | + showConfirmButton: showConfirmButton | |
47 | 47 | }); |
48 | 48 | } |
49 | 49 | ... | ... |
... | ... | @@ -31,5 +31,9 @@ |
31 | 31 | "notification.http_error.401.message": "Unauthorized", |
32 | 32 | "notification.http_error.500.message": "Server error", |
33 | 33 | "comment.post": "Post a comment", |
34 | + "comment.post.placeholder": "Join the discussion...", | |
35 | + "comment.pagination.more": "More", | |
36 | + "comment.post.success.title": "Good job!", | |
37 | + "comment.post.success.message": "Comment saved!", | |
34 | 38 | "comment.reply": "reply" |
35 | 39 | } | ... | ... |
... | ... | @@ -31,5 +31,9 @@ |
31 | 31 | "notification.http_error.401.message": "Não autorizado", |
32 | 32 | "notification.http_error.500.message": "Erro no servidor", |
33 | 33 | "comment.post": "Commentar", |
34 | + "comment.post.placeholder": "Participe da discussão...", | |
35 | + "comment.pagination.more": "Mais", | |
36 | + "comment.post.success.title": "Bom trabalho!", | |
37 | + "comment.post.success.message": "Comentário salvo com sucesso!", | |
34 | 38 | "comment.reply": "responder" |
35 | 39 | } | ... | ... |
... | ... | @@ -22,8 +22,8 @@ describe("Services", () => { |
22 | 22 | |
23 | 23 | it("should return comments by article", (done) => { |
24 | 24 | let articleId = 1; |
25 | - $httpBackend.expectGET(`/api/v1/articles/${articleId}/comments`).respond(200, { comments: [{ name: "comment1" }] }); | |
26 | - commentService.getByArticle(<noosfero.Article>{id: articleId}).then((result: noosfero.RestResult<noosfero.Comment[]>) => { | |
25 | + $httpBackend.expectGET(`/api/v1/articles/${articleId}/comments?without_reply=true`).respond(200, { comments: [{ name: "comment1" }] }); | |
26 | + commentService.getByArticle(<noosfero.Article>{ id: articleId }).then((result: noosfero.RestResult<noosfero.Comment[]>) => { | |
27 | 27 | expect(result.data).toEqual([{ name: "comment1" }]); |
28 | 28 | done(); |
29 | 29 | }); |
... | ... | @@ -32,9 +32,9 @@ describe("Services", () => { |
32 | 32 | |
33 | 33 | it("should create a comment in an article", (done) => { |
34 | 34 | let articleId = 1; |
35 | - let comment: noosfero.Comment = <any>{ id: null}; | |
36 | - $httpBackend.expectPOST(`/api/v1/articles/${articleId}/comments`, comment ).respond(200, {comment: { id: 2 }}); | |
37 | - commentService.createInArticle(<noosfero.Article>{id: articleId}, comment).then((result: noosfero.RestResult<noosfero.Comment>) => { | |
35 | + let comment: noosfero.Comment = <any>{ id: null }; | |
36 | + $httpBackend.expectPOST(`/api/v1/articles/${articleId}/comments`, comment).respond(200, { comment: { id: 2 } }); | |
37 | + commentService.createInArticle(<noosfero.Article>{ id: articleId }, comment).then((result: noosfero.RestResult<noosfero.Comment>) => { | |
38 | 38 | expect(result.data).toEqual({ id: 2 }); |
39 | 39 | done(); |
40 | 40 | }); | ... | ... |
... | ... | @@ -21,9 +21,10 @@ export class CommentService extends RestangularService<noosfero.Comment> { |
21 | 21 | }; |
22 | 22 | } |
23 | 23 | |
24 | - getByArticle(article: noosfero.Article, params?: any): ng.IPromise<noosfero.RestResult<noosfero.Comment[]>> { | |
24 | + getByArticle(article: noosfero.Article, params: any = {}): ng.IPromise<noosfero.RestResult<noosfero.Comment[]>> { | |
25 | + params['without_reply'] = true; | |
25 | 26 | let articleElement = this.articleService.getElement(<number>article.id); |
26 | - return this.list(articleElement); | |
27 | + return this.list(articleElement, params); | |
27 | 28 | } |
28 | 29 | |
29 | 30 | createInArticle(article: noosfero.Article, comment: noosfero.Comment): ng.IPromise<noosfero.RestResult<noosfero.Comment>> { | ... | ... |
-
Milestone changed to 2016.04
-
Added 1 new commit:
- 8202814b - Refactor comments component to permit extensions
-
Added 1 new commit:
- 06a2fc8d - Translate success message of post comment
-
Added 10 new commits:
- 556724ef - Fixed home link
- f0b9c7a0 - Display replies of comments
- 8b4048cc - Improve layout of post comment component
- 20a7654b - Toggle reply form when clicked from comment component
- 734399ac - Sort comments by creation date
- b4c8800b - Fix layout of comments replies
- cb5558ce - Add pagination button for comment listing
- 3e93892b - Hide more comments button when there is no more pages to load
- de7418b4 - Refactor comments component to permit extensions
- 95a63439 - Translate success message of post comment
-
Added 13 new commits:
- efa64a13 - Fix helpers.ts type problems and added conditional to show profile custom-fields table
- 6d10324a - People block refactoring. Created component-test-helper
- 458f2ccd - Review Modifications
- 7bab2b41 - Merge branch 'people-block' into 'master'
- 986f9d29 - Display replies of comments
- 89d0707b - Improve layout of post comment component
- 50ef7e70 - Toggle reply form when clicked from comment component
- d78752ef - Sort comments by creation date
- db57fad4 - Fix layout of comments replies
- 34b31510 - Add pagination button for comment listing
- 07583059 - Hide more comments button when there is no more pages to load
- 37a2a450 - Refactor comments component to permit extensions
- 5d2ebeec - Translate success message of post comment
-
I would like to deliver some feedback about the comment system implemented:
1 - The "More" button is showing even when there isn't more comments avaiable;
2 - I think would be better minimize the identation to represent replies, maybe to just one level and use some text+icon to represent the comment is a reply. I think the comments would have anchors and so the reply text+icon would link to the comment it's replying.
3 - I realy liked the Post Comment Button Animation. :D
-
Looks like there is some problem here because this button is showing even when there is more comments avaialble.
-
I'll be fixed with https://gitlab.com/noosfero/noosfero/merge_requests/854
-
I liked the animation here. But maybe would be better provide this animation at the default theme instead. Would be hard to override this on themes.
-
Added 16 new commits:
- 5c75ac60 - Adding a Vagrantfile
- 697684e6 - fix date format for general locales
- 50d18589 - change README install instructions
- dce2b87d - Cleaning up unneeded files
- f9896e22 - Refactoring build task
- d80617bf - Update README.md with new build instructions
- a5c48faf - Merge branch 'dev-fixes' into 'master'
- a944f06a - Display replies of comments
- 4b876c39 - Improve layout of post comment component
- 2ebd4ad0 - Toggle reply form when clicked from comment component
- 6911e123 - Sort comments by creation date
- 1d6363e0 - Fix layout of comments replies
- 6e2ef9ed - Add pagination button for comment listing
- 16b1a6fa - Hide more comments button when there is no more pages to load
- d247ad88 - Refactor comments component to permit extensions
- 845f879b - Translate success message of post comment
-
Added 1 new commit:
- 6061cf6e - Refactor post comment event to use EventEmitter
-
Assignee removed
-
o commit 00882cc3edbc26721fd392b5a314c0a24bee977a não apareceu aqui no MergeRequest
1 | 1 | <div class="comments"> |
2 | - <noosfero-post-comment [article]="ctrl.article"></noosfero-post-comment> | |
2 | + <noosfero-post-comment ng-if="ctrl.showForm" [article]="ctrl.article" [parent]="ctrl.parent"></noosfero-post-comment> | |
3 | 3 | |
4 | 4 | <div class="comments-list"> |
5 | - <noosfero-comment ng-repeat="comment in ctrl.comments" [comment]="comment" [article]="ctrl.article"></noosfero-comment> | |
5 | + <noosfero-comment ng-repeat="comment in ctrl.comments | orderBy: 'created_at':true" [comment]="comment" [article]="ctrl.article"></noosfero-comment> | |
6 | 6 | </div> |
7 | + <button type="button" ng-if="ctrl.displayMore()" class="more-comments btn btn-default btn-block" ng-click="ctrl.loadNextPage()">{{"comment.pagination.more" | translate}}</button> | |
2 |
|
1 | +.comments { | |
2 | + .post-comment { | |
3 | + .media { | |
4 | + border-top: 2px solid #F3F3F3; | |
5 | + padding-top: 10px; | |
6 | + .media-left { | |
7 | + padding: 10px 0; | |
8 | + } | |
9 | + button { | |
1 |
|