Commit 1894afc0521954895e6b817afa85c8c4a51e8d5e
Exists in
master
and in
27 other branches
Merge branch 'create-article' into 'master'
Basic form to create and edit articles See merge request !11
Showing
27 changed files
with
406 additions
and
164 deletions
Show diff stats
bower.json
@@ -34,7 +34,9 @@ | @@ -34,7 +34,9 @@ | ||
34 | "angular-dynamic-locale": "^0.1.30", | 34 | "angular-dynamic-locale": "^0.1.30", |
35 | "angular-i18n": "^1.5.0", | 35 | "angular-i18n": "^1.5.0", |
36 | "angular-load": "^0.4.1", | 36 | "angular-load": "^0.4.1", |
37 | - "angular-translate-interpolation-messageformat": "^2.10.0" | 37 | + "angular-translate-interpolation-messageformat": "^2.10.0", |
38 | + "ng-ckeditor": "^0.2.1", | ||
39 | + "ckeditor": "^4.5.8" | ||
38 | }, | 40 | }, |
39 | "devDependencies": { | 41 | "devDependencies": { |
40 | "angular-mocks": "~1.5.0" | 42 | "angular-mocks": "~1.5.0" |
src/app/article/article.html
@@ -4,6 +4,9 @@ | @@ -4,6 +4,9 @@ | ||
4 | </div> | 4 | </div> |
5 | 5 | ||
6 | <div class="sub-header clearfix"> | 6 | <div class="sub-header clearfix"> |
7 | + <a href="#" class="btn btn-default btn-xs" ui-sref="main.cmsEdit({profile: ctrl.profile.identifier, id: ctrl.article.id})"> | ||
8 | + <i class="fa fa-pencil-square-o fa-fw fa-lg"></i> {{"article.actions.edit" | translate}} | ||
9 | + </a> | ||
7 | <div class="page-info pull-right small text-muted"> | 10 | <div class="page-info pull-right small text-muted"> |
8 | <span class="time"> | 11 | <span class="time"> |
9 | <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span> | 12 | <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span> |
src/app/article/basic-editor.component.spec.ts
@@ -1,55 +0,0 @@ | @@ -1,55 +0,0 @@ | ||
1 | -import {quickCreateComponent} from "../../spec/helpers"; | ||
2 | -import {BasicEditorComponent} from "./basic-editor.component"; | ||
3 | - | ||
4 | - | ||
5 | -describe("Article BasicEditor", () => { | ||
6 | - | ||
7 | - let $rootScope: ng.IRootScopeService; | ||
8 | - let $q: ng.IQService; | ||
9 | - let articleServiceMock: any; | ||
10 | - let profileServiceMock: any; | ||
11 | - let $state: any; | ||
12 | - let profile = { id: 1 }; | ||
13 | - let notification: any; | ||
14 | - | ||
15 | - | ||
16 | - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { | ||
17 | - $rootScope = _$rootScope_; | ||
18 | - $q = _$q_; | ||
19 | - })); | ||
20 | - | ||
21 | - beforeEach(() => { | ||
22 | - $state = jasmine.createSpyObj("$state", ["transitionTo"]); | ||
23 | - notification = jasmine.createSpyObj("notification", ["success"]); | ||
24 | - profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile"]); | ||
25 | - articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["createInProfile"]); | ||
26 | - | ||
27 | - let getCurrentProfileResponse = $q.defer(); | ||
28 | - getCurrentProfileResponse.resolve(profile); | ||
29 | - | ||
30 | - let articleCreate = $q.defer(); | ||
31 | - articleCreate.resolve({ data: { path: "path", profile: { identifier: "profile" } } }); | ||
32 | - | ||
33 | - profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise); | ||
34 | - articleServiceMock.createInProfile = jasmine.createSpy("createInProfile").and.returnValue(articleCreate.promise); | ||
35 | - }); | ||
36 | - | ||
37 | - it("create an article in the current profile when save", done => { | ||
38 | - let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification); | ||
39 | - component.save(); | ||
40 | - $rootScope.$apply(); | ||
41 | - expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled(); | ||
42 | - expect(articleServiceMock.createInProfile).toHaveBeenCalledWith(profile, component.article); | ||
43 | - done(); | ||
44 | - }); | ||
45 | - | ||
46 | - it("got to the new article page and display an alert when saving sucessfully", done => { | ||
47 | - let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification); | ||
48 | - component.save(); | ||
49 | - $rootScope.$apply(); | ||
50 | - expect($state.transitionTo).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" }); | ||
51 | - expect(notification.success).toHaveBeenCalled(); | ||
52 | - done(); | ||
53 | - }); | ||
54 | - | ||
55 | -}); |
src/app/article/basic-editor.component.ts
@@ -1,35 +0,0 @@ | @@ -1,35 +0,0 @@ | ||
1 | -import {StateConfig, Component, Inject, provide} from 'ng-forward'; | ||
2 | -import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service"; | ||
3 | -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | ||
4 | -import {NotificationService} from "../shared/services/notification.service.ts"; | ||
5 | - | ||
6 | -@Component({ | ||
7 | - selector: 'article-basic-editor', | ||
8 | - templateUrl: "app/article/basic-editor.html", | ||
9 | - providers: [ | ||
10 | - provide('articleService', { useClass: ArticleService }), | ||
11 | - provide('profileService', { useClass: ProfileService }), | ||
12 | - provide('notification', { useClass: NotificationService }) | ||
13 | - ] | ||
14 | -}) | ||
15 | -@Inject(ArticleService, ProfileService, "$state", NotificationService) | ||
16 | -export class BasicEditorComponent { | ||
17 | - | ||
18 | - article: noosfero.Article = <noosfero.Article>{}; | ||
19 | - | ||
20 | - constructor(private articleService: ArticleService, | ||
21 | - private profileService: ProfileService, | ||
22 | - private $state: ng.ui.IStateService, | ||
23 | - private notification: NotificationService) { } | ||
24 | - | ||
25 | - save() { | ||
26 | - this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { | ||
27 | - return this.articleService.createInProfile(profile, this.article); | ||
28 | - }).then((response: noosfero.RestResult<noosfero.Article>) => { | ||
29 | - let article = (<noosfero.Article>response.data); | ||
30 | - this.$state.transitionTo('main.profile.page', { page: article.path, profile: article.profile.identifier }); | ||
31 | - this.notification.success({ title: "Good job!", message: "Article saved!" }); | ||
32 | - }); | ||
33 | - } | ||
34 | - | ||
35 | -} |
src/app/article/basic-editor.html
@@ -1,11 +0,0 @@ | @@ -1,11 +0,0 @@ | ||
1 | -<form> | ||
2 | - <div class="form-group"> | ||
3 | - <label for="titleInput">Title</label> | ||
4 | - <input type="text" class="form-control" id="titleInput" placeholder="title" ng-model="vm.article.name"> | ||
5 | - </div> | ||
6 | - <div class="form-group"> | ||
7 | - <label for="bodyInput">Text</label> | ||
8 | - <textarea class="form-control" id="bodyInput" rows="10" ng-model="vm.article.body"></textarea> | ||
9 | - </div> | ||
10 | - <button type="submit" class="btn btn-default" ng-click="vm.save()">Save</button> | ||
11 | -</form> |
src/app/article/basic-editor/basic-editor.component.spec.ts
0 → 100644
@@ -0,0 +1,84 @@ | @@ -0,0 +1,84 @@ | ||
1 | +import {quickCreateComponent} from "../../../spec/helpers"; | ||
2 | +import {BasicEditorComponent} from "./basic-editor.component"; | ||
3 | + | ||
4 | + | ||
5 | +describe("Article BasicEditor", () => { | ||
6 | + | ||
7 | + let $rootScope: ng.IRootScopeService; | ||
8 | + let $q: ng.IQService; | ||
9 | + let articleServiceMock: any; | ||
10 | + let profileServiceMock: any; | ||
11 | + let $state: any; | ||
12 | + let $stateParams: any; | ||
13 | + let $window: any; | ||
14 | + let profile = { id: 1 }; | ||
15 | + let notification: any; | ||
16 | + | ||
17 | + | ||
18 | + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { | ||
19 | + $rootScope = _$rootScope_; | ||
20 | + $q = _$q_; | ||
21 | + })); | ||
22 | + | ||
23 | + beforeEach(() => { | ||
24 | + $window = jasmine.createSpyObj("$window", ["back"]); | ||
25 | + $state = jasmine.createSpyObj("$state", ["go"]); | ||
26 | + notification = jasmine.createSpyObj("notification", ["success"]); | ||
27 | + profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["setCurrentProfileByIdentifier"]); | ||
28 | + articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["createInParent", "updateArticle", "get"]); | ||
29 | + | ||
30 | + $stateParams = { profile: "profile" }; | ||
31 | + | ||
32 | + let setCurrentProfileByIdentifierResponse = $q.defer(); | ||
33 | + setCurrentProfileByIdentifierResponse.resolve(profile); | ||
34 | + | ||
35 | + let articleCreate = $q.defer(); | ||
36 | + articleCreate.resolve({ data: { path: "path", profile: { identifier: "profile" } } }); | ||
37 | + | ||
38 | + let articleGet = $q.defer(); | ||
39 | + articleGet.resolve({ data: { path: "parent-path", profile: { identifier: "profile" } } }); | ||
40 | + | ||
41 | + profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(setCurrentProfileByIdentifierResponse.promise); | ||
42 | + articleServiceMock.createInParent = jasmine.createSpy("createInParent").and.returnValue(articleCreate.promise); | ||
43 | + articleServiceMock.updateArticle = jasmine.createSpy("updateArticle").and.returnValue(articleCreate.promise); | ||
44 | + articleServiceMock.get = jasmine.createSpy("get").and.returnValue(articleGet.promise); | ||
45 | + }); | ||
46 | + | ||
47 | + it("create an article in the current profile when save", done => { | ||
48 | + $stateParams['parent_id'] = 1; | ||
49 | + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window); | ||
50 | + component.save(); | ||
51 | + $rootScope.$apply(); | ||
52 | + expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); | ||
53 | + expect(articleServiceMock.createInParent).toHaveBeenCalledWith(1, component.article); | ||
54 | + done(); | ||
55 | + }); | ||
56 | + | ||
57 | + it("got to the new article page and display an alert when saving sucessfully", done => { | ||
58 | + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window); | ||
59 | + component.save(); | ||
60 | + $rootScope.$apply(); | ||
61 | + expect($state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" }); | ||
62 | + expect(notification.success).toHaveBeenCalled(); | ||
63 | + done(); | ||
64 | + }); | ||
65 | + | ||
66 | + it("go back when cancel article edition", done => { | ||
67 | + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window); | ||
68 | + $window.history = { back: jasmine.createSpy('back') }; | ||
69 | + component.cancel(); | ||
70 | + expect($window.history.back).toHaveBeenCalled(); | ||
71 | + done(); | ||
72 | + }); | ||
73 | + | ||
74 | + it("edit existing article when save", done => { | ||
75 | + $stateParams['parent_id'] = null; | ||
76 | + $stateParams['id'] = 2; | ||
77 | + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window); | ||
78 | + component.save(); | ||
79 | + $rootScope.$apply(); | ||
80 | + expect(articleServiceMock.updateArticle).toHaveBeenCalledWith(component.article); | ||
81 | + done(); | ||
82 | + }); | ||
83 | + | ||
84 | +}); |
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | +import {StateConfig, Component, Inject, provide} from 'ng-forward'; | ||
2 | +import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service"; | ||
3 | +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service"; | ||
4 | +import {NotificationService} from "../../shared/services/notification.service.ts"; | ||
5 | + | ||
6 | +@Component({ | ||
7 | + selector: 'article-basic-editor', | ||
8 | + templateUrl: "app/article/basic-editor/basic-editor.html", | ||
9 | + providers: [ | ||
10 | + provide('articleService', { useClass: ArticleService }), | ||
11 | + provide('profileService', { useClass: ProfileService }), | ||
12 | + provide('notification', { useClass: NotificationService }) | ||
13 | + ] | ||
14 | +}) | ||
15 | +@Inject(ArticleService, ProfileService, "$state", NotificationService, "$stateParams", "$window") | ||
16 | +export class BasicEditorComponent { | ||
17 | + | ||
18 | + article: noosfero.Article = <noosfero.Article>{ type: "TextArticle" }; | ||
19 | + parent: noosfero.Article = <noosfero.Article>{}; | ||
20 | + | ||
21 | + id: number; | ||
22 | + parentId: number; | ||
23 | + profileIdentifier: string; | ||
24 | + | ||
25 | + constructor(private articleService: ArticleService, | ||
26 | + private profileService: ProfileService, | ||
27 | + private $state: ng.ui.IStateService, | ||
28 | + private notification: NotificationService, | ||
29 | + private $stateParams: ng.ui.IStateParamsService, | ||
30 | + private $window: ng.IWindowService) { | ||
31 | + | ||
32 | + this.parentId = this.$stateParams['parent_id']; | ||
33 | + this.profileIdentifier = this.$stateParams["profile"]; | ||
34 | + this.id = this.$stateParams['id']; | ||
35 | + | ||
36 | + if (this.parentId) { | ||
37 | + this.articleService.get(this.parentId).then((result: noosfero.RestResult<noosfero.Article>) => { | ||
38 | + this.parent = result.data; | ||
39 | + }); | ||
40 | + } | ||
41 | + if (this.id) { | ||
42 | + this.articleService.get(this.id).then((result: noosfero.RestResult<noosfero.Article>) => { | ||
43 | + this.article = result.data; | ||
44 | + this.article.name = this.article.title; // FIXME | ||
45 | + }); | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | + save() { | ||
50 | + this.profileService.setCurrentProfileByIdentifier(this.profileIdentifier).then((profile: noosfero.Profile) => { | ||
51 | + if (this.id) { | ||
52 | + return this.articleService.updateArticle(this.article); | ||
53 | + } else { | ||
54 | + return this.articleService.createInParent(this.parentId, this.article); | ||
55 | + } | ||
56 | + }).then((response: noosfero.RestResult<noosfero.Article>) => { | ||
57 | + let article = (<noosfero.Article>response.data); | ||
58 | + this.$state.go('main.profile.page', { page: article.path, profile: article.profile.identifier }); | ||
59 | + this.notification.success({ title: "article.basic_editor.success.title", message: "article.basic_editor.success.message" }); | ||
60 | + }).catch(() => { | ||
61 | + this.notification.error({ message: "article.basic_editor.save.failed" }); | ||
62 | + }); | ||
63 | + } | ||
64 | + | ||
65 | + cancel() { | ||
66 | + this.$window.history.back(); | ||
67 | + } | ||
68 | + | ||
69 | +} |
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +<div class="basic-editor"> | ||
2 | + <div class="row"> | ||
3 | + <div class="col-md-1"></div> | ||
4 | + <div class="col-md-8"> | ||
5 | + <form> | ||
6 | + <div class="form-group"> | ||
7 | + <label for="titleInput">{{"article.basic_editor.title" | translate}}</label> | ||
8 | + <input type="text" class="form-control" id="titleInput" placeholder="{{'article.basic_editor.title' | translate}}" ng-model="vm.article.name"> | ||
9 | + </div> | ||
10 | + <div class="form-group"> | ||
11 | + <label for="bodyInput">{{"article.basic_editor.body" | translate}}</label> | ||
12 | + <html-editor [(value)]="vm.article.body"></html-editor> | ||
13 | + </div> | ||
14 | + <button type="submit" class="btn btn-default" ng-click="vm.save()">{{"article.basic_editor.save" | translate}}</button> | ||
15 | + <button type="button" class="btn btn-danger" ng-click="vm.cancel()">{{"article.basic_editor.cancel" | translate}}</button> | ||
16 | + </form> | ||
17 | + </div> | ||
18 | + <div class="side-options"> | ||
19 | + <div class="visibility panel panel-default"> | ||
20 | + <div class="panel-heading">{{"article.basic_editor.visibility" | translate}}</div> | ||
21 | + <div class="panel-body"> | ||
22 | + <div> | ||
23 | + <input type="radio" ng-model="vm.article.published" ng-value="true"> | ||
24 | + <i class="fa fa-unlock fa-fw"></i> {{"article.basic_editor.visibility.public" | translate}} | ||
25 | + </div> | ||
26 | + <div> | ||
27 | + <input type="radio" ng-model="vm.article.published" ng-value="false"> | ||
28 | + <i class="fa fa-lock fa-fw"></i> {{"article.basic_editor.visibility.private" | translate}} | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + </div> | ||
34 | +</div> |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +.basic-editor { | ||
2 | + @extend .container-fluid; | ||
3 | + padding: 0 1%; | ||
4 | + | ||
5 | + .side-options { | ||
6 | + @extend .col-md-3; | ||
7 | + margin-top: 25px; | ||
8 | + | ||
9 | + .visibility { | ||
10 | + .panel-heading { | ||
11 | + background-color: transparent; | ||
12 | + font-weight: bold; | ||
13 | + } | ||
14 | + .panel-body { | ||
15 | + i { | ||
16 | + color: #A5A5A5; | ||
17 | + } | ||
18 | + } | ||
19 | + } | ||
20 | + } | ||
21 | +} |
src/app/article/content-viewer/content-viewer-actions.component.spec.ts
1 | -import {providers} from 'ng-forward/cjs/testing/providers'; | ||
2 | - | ||
3 | import {Input, Component, provide} from 'ng-forward'; | 1 | import {Input, Component, provide} from 'ng-forward'; |
4 | 2 | ||
5 | import * as helpers from "../../../spec/helpers"; | 3 | import * as helpers from "../../../spec/helpers"; |
6 | - | ||
7 | -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | 4 | +import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper'; |
8 | import {ContentViewerActionsComponent} from './content-viewer-actions.component'; | 5 | import {ContentViewerActionsComponent} from './content-viewer-actions.component'; |
9 | 6 | ||
10 | // this htmlTemplate will be re-used between the container components in this spec file | 7 | // this htmlTemplate will be re-used between the container components in this spec file |
@@ -12,56 +9,57 @@ const htmlTemplate: string = '<content-viewer-actions [article]="ctrl.article" [ | @@ -12,56 +9,57 @@ const htmlTemplate: string = '<content-viewer-actions [article]="ctrl.article" [ | ||
12 | 9 | ||
13 | describe('Content Viewer Actions Component', () => { | 10 | describe('Content Viewer Actions Component', () => { |
14 | 11 | ||
15 | - beforeEach(() => { | 12 | + let helper: ComponentTestHelper<ContentViewerActionsComponent>; |
16 | 13 | ||
17 | - angular.mock.module("templates"); | 14 | + beforeEach(angular.mock.module("templates")); |
18 | 15 | ||
19 | - providers((provide: any) => { | ||
20 | - return <any>[ | ||
21 | - provide('ProfileService', { | ||
22 | - useValue: helpers.mocks.profileService | ||
23 | - }) | ||
24 | - ]; | ||
25 | - }); | ||
26 | - }); | 16 | + let providers = [ |
17 | + provide('ProfileService', { | ||
18 | + useValue: helpers.mocks.profileService | ||
19 | + }), | ||
20 | + provide('ArticleService', { | ||
21 | + useValue: helpers.mocks.articleService | ||
22 | + }) | ||
23 | + ].concat(helpers.provideFilters("translateFilter")); | ||
27 | 24 | ||
28 | - let buildComponent = (): Promise<ComponentFixture> => { | ||
29 | - return helpers.quickCreateComponent({ | ||
30 | - providers: [ | ||
31 | - helpers.provideEmptyObjects('Restangular'), | ||
32 | - helpers.provideFilters('translateFilter') | ||
33 | - ], | 25 | + beforeEach((done) => { |
26 | + let cls = createClass({ | ||
27 | + template: htmlTemplate, | ||
34 | directives: [ContentViewerActionsComponent], | 28 | directives: [ContentViewerActionsComponent], |
35 | - template: htmlTemplate | 29 | + providers: providers |
36 | }); | 30 | }); |
37 | - }; | 31 | + helper = new ComponentTestHelper<ContentViewerActionsComponent>(cls, done); |
32 | + }); | ||
38 | 33 | ||
39 | - it('renders content viewer actions directive', (done: Function) => { | ||
40 | - buildComponent().then((fixture: ComponentFixture) => { | ||
41 | - expect(fixture.debugElement.query('content-viewer-actions').length).toEqual(1); | 34 | + it('renders content viewer actions directive', () => { |
35 | + expect(helper.all("content-viewer-actions").length).toEqual(1); | ||
36 | + }); | ||
42 | 37 | ||
43 | - done(); | ||
44 | - }); | 38 | + it('return article parent as container when it is not a folder', () => { |
39 | + let article = <noosfero.Article>({ id: 1, type: 'TextArticle', parent: { id: 2 } }); | ||
40 | + expect(helper.component.getArticleContainer(article)).toEqual(2); | ||
41 | + }); | ||
42 | + | ||
43 | + it('return article as container when it is a folder', () => { | ||
44 | + let article = <noosfero.Article>({ id: 1, type: 'Folder' }); | ||
45 | + expect(helper.component.getArticleContainer(article)).toEqual(1); | ||
45 | }); | 46 | }); |
46 | 47 | ||
47 | - it('check if profile was loaded', (done: Function) => { | 48 | + it('return article as container when it is a blog', () => { |
49 | + let article = <noosfero.Article>({ id: 1, type: 'Blog' }); | ||
50 | + expect(helper.component.getArticleContainer(article)).toEqual(1); | ||
51 | + }); | ||
52 | + | ||
53 | + it('check if profile was loaded', () => { | ||
48 | let profile: any = { | 54 | let profile: any = { |
49 | id: 1, | 55 | id: 1, |
50 | identifier: 'the-profile-test', | 56 | identifier: 'the-profile-test', |
51 | type: 'Person' | 57 | type: 'Person' |
52 | }; | 58 | }; |
53 | - | ||
54 | helpers.mocks.profileService.getCurrentProfile = () => { | 59 | helpers.mocks.profileService.getCurrentProfile = () => { |
55 | return helpers.mocks.promiseResultTemplate(profile); | 60 | return helpers.mocks.promiseResultTemplate(profile); |
56 | }; | 61 | }; |
57 | - | ||
58 | - buildComponent().then((fixture: ComponentFixture) => { | ||
59 | - let contentViewerComp: ContentViewerActionsComponent = fixture.debugElement.componentViewChildren[0].componentInstance; | ||
60 | - | ||
61 | - expect(contentViewerComp.profile).toEqual(jasmine.objectContaining(profile)); | ||
62 | - | ||
63 | - done(); | ||
64 | - }); | 62 | + let component = new ContentViewerActionsComponent(<any>helpers.mocks.profileService, <any>helpers.mocks.articleService); |
63 | + expect(component.profile).toEqual(jasmine.objectContaining(profile)); | ||
65 | }); | 64 | }); |
66 | - | ||
67 | }); | 65 | }); |
src/app/article/content-viewer/content-viewer-actions.component.ts
1 | import {Component, Inject, provide} from "ng-forward"; | 1 | import {Component, Inject, provide} from "ng-forward"; |
2 | import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service"; | 2 | import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service"; |
3 | +import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service"; | ||
3 | 4 | ||
4 | @Component({ | 5 | @Component({ |
5 | selector: "content-viewer-actions", | 6 | selector: "content-viewer-actions", |
6 | templateUrl: "app/article/content-viewer/navbar-actions.html", | 7 | templateUrl: "app/article/content-viewer/navbar-actions.html", |
7 | - providers: [provide('profileService', { useClass: ProfileService })] | 8 | + providers: [ |
9 | + provide('profileService', { useClass: ProfileService }), | ||
10 | + provide('articleService', { useClass: ArticleService }) | ||
11 | + ] | ||
8 | }) | 12 | }) |
9 | -@Inject(ProfileService) | 13 | +@Inject(ProfileService, ArticleService) |
10 | export class ContentViewerActionsComponent { | 14 | export class ContentViewerActionsComponent { |
11 | 15 | ||
12 | article: noosfero.Article; | 16 | article: noosfero.Article; |
13 | profile: noosfero.Profile; | 17 | profile: noosfero.Profile; |
18 | + parentId: number; | ||
14 | 19 | ||
15 | - constructor(profileService: ProfileService) { | 20 | + constructor(profileService: ProfileService, articleService: ArticleService) { |
16 | profileService.getCurrentProfile().then((profile: noosfero.Profile) => { | 21 | profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
17 | this.profile = profile; | 22 | this.profile = profile; |
23 | + return articleService.getCurrent(); | ||
24 | + }).then((article: noosfero.Article) => { | ||
25 | + this.article = article; | ||
26 | + this.parentId = this.getArticleContainer(article); | ||
18 | }); | 27 | }); |
19 | } | 28 | } |
29 | + | ||
30 | + getArticleContainer(article: noosfero.Article) { | ||
31 | + // FIXME get folder types from api | ||
32 | + if (article.type === "Blog" || article.type === "Folder") { | ||
33 | + return article.id; | ||
34 | + } else if (article.parent) { | ||
35 | + return article.parent.id; | ||
36 | + } | ||
37 | + } | ||
20 | } | 38 | } |
src/app/article/content-viewer/content-viewer.component.ts
@@ -28,11 +28,12 @@ export class ContentViewerComponent { | @@ -28,11 +28,12 @@ export class ContentViewerComponent { | ||
28 | } | 28 | } |
29 | 29 | ||
30 | activate() { | 30 | activate() { |
31 | - this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { | 31 | + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
32 | this.profile = profile; | 32 | this.profile = profile; |
33 | return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]); | 33 | return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]); |
34 | }).then((result: noosfero.RestResult<any>) => { | 34 | }).then((result: noosfero.RestResult<any>) => { |
35 | this.article = <noosfero.Article>result.data; | 35 | this.article = <noosfero.Article>result.data; |
36 | + this.articleService.setCurrent(this.article); | ||
36 | }); | 37 | }); |
37 | } | 38 | } |
38 | } | 39 | } |
src/app/article/content-viewer/navbar-actions.html
1 | <ul class="nav navbar-nav"> | 1 | <ul class="nav navbar-nav"> |
2 | <li ng-show="vm.profile"> | 2 | <li ng-show="vm.profile"> |
3 | - <a href="#" role="button" ui-sref="main.profile.cms({profile: vm.profile.identifier})"> | 3 | + <a ng-show="vm.parentId" href="#" role="button" ui-sref="main.cms({profile: vm.profile.identifier, parent_id: vm.parentId})"> |
4 | <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}} | 4 | <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}} |
5 | </a> | 5 | </a> |
6 | </li> | 6 | </li> |
src/app/article/index.ts
1 | /* Module Index Entry - generated using the script npm run generate-index */ | 1 | /* Module Index Entry - generated using the script npm run generate-index */ |
2 | export * from "./article-default-view.component"; | 2 | export * from "./article-default-view.component"; |
3 | -export * from "./basic-editor.component"; |
src/app/index.ts
@@ -14,7 +14,7 @@ declare var moment: any; | @@ -14,7 +14,7 @@ declare var moment: any; | ||
14 | 14 | ||
15 | let noosferoApp: any = bundle("noosferoApp", MainComponent, ["ngAnimate", "ngCookies", "ngStorage", "ngTouch", | 15 | let noosferoApp: any = bundle("noosferoApp", MainComponent, ["ngAnimate", "ngCookies", "ngStorage", "ngTouch", |
16 | "ngSanitize", "ngMessages", "ngAria", "restangular", | 16 | "ngSanitize", "ngMessages", "ngAria", "restangular", |
17 | - "ui.router", "ui.bootstrap", "toastr", | 17 | + "ui.router", "ui.bootstrap", "toastr", "ngCkeditor", |
18 | "angularMoment", "angular.filter", "akoenig.deckgrid", | 18 | "angularMoment", "angular.filter", "akoenig.deckgrid", |
19 | "angular-timeline", "duScroll", "oitozero.ngSweetAlert", | 19 | "angular-timeline", "duScroll", "oitozero.ngSweetAlert", |
20 | "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad"]).publish(); | 20 | "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad"]).publish(); |
src/app/main/main.component.ts
@@ -29,6 +29,7 @@ import {BodyStateClassesService} from "./../layout/services/body-state-classes.s | @@ -29,6 +29,7 @@ import {BodyStateClassesService} from "./../layout/services/body-state-classes.s | ||
29 | import {Navbar} from "../layout/navbar/navbar"; | 29 | import {Navbar} from "../layout/navbar/navbar"; |
30 | 30 | ||
31 | import {MainBlockComponent} from "../layout/blocks/main-block/main-block.component"; | 31 | import {MainBlockComponent} from "../layout/blocks/main-block/main-block.component"; |
32 | +import {HtmlEditorComponent} from "../shared/components/html-editor/html-editor.component"; | ||
32 | 33 | ||
33 | 34 | ||
34 | /** | 35 | /** |
@@ -82,7 +83,7 @@ export class EnvironmentContent { | @@ -82,7 +83,7 @@ export class EnvironmentContent { | ||
82 | directives: [ | 83 | directives: [ |
83 | ArticleBlogComponent, ArticleViewComponent, BoxesComponent, BlockComponent, | 84 | ArticleBlogComponent, ArticleViewComponent, BoxesComponent, BlockComponent, |
84 | EnvironmentComponent, PeopleBlockComponent, | 85 | EnvironmentComponent, PeopleBlockComponent, |
85 | - LinkListBlockComponent, CommunitiesBlockComponent, | 86 | + LinkListBlockComponent, CommunitiesBlockComponent, HtmlEditorComponent, |
86 | MainBlockComponent, RecentDocumentsBlockComponent, Navbar, ProfileImageBlockComponent, | 87 | MainBlockComponent, RecentDocumentsBlockComponent, Navbar, ProfileImageBlockComponent, |
87 | MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent | 88 | MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent |
88 | ], | 89 | ], |
src/app/profile/profile.component.ts
1 | import {StateConfig, Component, Inject, provide} from 'ng-forward'; | 1 | import {StateConfig, Component, Inject, provide} from 'ng-forward'; |
2 | import {ProfileInfoComponent} from './info/profile-info.component'; | 2 | import {ProfileInfoComponent} from './info/profile-info.component'; |
3 | import {ProfileHomeComponent} from './profile-home.component'; | 3 | import {ProfileHomeComponent} from './profile-home.component'; |
4 | -import {BasicEditorComponent} from '../article/basic-editor.component'; | 4 | +import {BasicEditorComponent} from '../article/basic-editor/basic-editor.component'; |
5 | import {ContentViewerComponent} from "../article/content-viewer/content-viewer.component"; | 5 | import {ContentViewerComponent} from "../article/content-viewer/content-viewer.component"; |
6 | import {ContentViewerActionsComponent} from "../article/content-viewer/content-viewer-actions.component"; | 6 | import {ContentViewerActionsComponent} from "../article/content-viewer/content-viewer-actions.component"; |
7 | import {ActivitiesComponent} from "./activities/activities.component"; | 7 | import {ActivitiesComponent} from "./activities/activities.component"; |
@@ -45,12 +45,24 @@ import {MyProfileComponent} from "./myprofile.component"; | @@ -45,12 +45,24 @@ import {MyProfileComponent} from "./myprofile.component"; | ||
45 | component: MyProfileComponent | 45 | component: MyProfileComponent |
46 | }, | 46 | }, |
47 | { | 47 | { |
48 | - name: 'main.profile.cms', | ||
49 | - url: "^/myprofile/:profile/cms", | 48 | + name: 'main.cms', |
49 | + url: "^/myprofile/:profile/cms?parent_id", | ||
50 | component: BasicEditorComponent, | 50 | component: BasicEditorComponent, |
51 | views: { | 51 | views: { |
52 | - "mainBlockContent": { | ||
53 | - templateUrl: "app/article/basic-editor.html", | 52 | + "content": { |
53 | + templateUrl: "app/article/basic-editor/basic-editor.html", | ||
54 | + controller: BasicEditorComponent, | ||
55 | + controllerAs: "vm" | ||
56 | + } | ||
57 | + } | ||
58 | + }, | ||
59 | + { | ||
60 | + name: 'main.cmsEdit', | ||
61 | + url: "^/myprofile/:profile/cms/edit/:id", | ||
62 | + component: BasicEditorComponent, | ||
63 | + views: { | ||
64 | + "content": { | ||
65 | + templateUrl: "app/article/basic-editor/basic-editor.html", | ||
54 | controller: BasicEditorComponent, | 66 | controller: BasicEditorComponent, |
55 | controllerAs: "vm" | 67 | controllerAs: "vm" |
56 | } | 68 | } |
@@ -98,7 +110,7 @@ export class ProfileComponent { | @@ -98,7 +110,7 @@ export class ProfileComponent { | ||
98 | }).then((response: restangular.IResponse) => { | 110 | }).then((response: restangular.IResponse) => { |
99 | this.boxes = response.data.boxes; | 111 | this.boxes = response.data.boxes; |
100 | }).catch(() => { | 112 | }).catch(() => { |
101 | - $state.transitionTo('main'); | 113 | + $state.transitionTo('main.environment.home'); |
102 | notificationService.error({ message: "notification.profile.not_found" }); | 114 | notificationService.error({ message: "notification.profile.not_found" }); |
103 | }); | 115 | }); |
104 | } | 116 | } |
src/app/shared/components/html-editor/html-editor.component.spec.ts
0 → 100644
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper'; | ||
2 | +import {HtmlEditorComponent} from "./html-editor.component"; | ||
3 | + | ||
4 | +const htmlTemplate: string = '<html-editor [(value)]="ctrl.value" [options]="ctrl.options"></html-editor>'; | ||
5 | + | ||
6 | +describe("Components", () => { | ||
7 | + describe("Html Editor Component", () => { | ||
8 | + | ||
9 | + let helper: ComponentTestHelper<HtmlEditorComponent>; | ||
10 | + beforeEach(angular.mock.module("templates")); | ||
11 | + | ||
12 | + beforeEach((done) => { | ||
13 | + let properties = { value: "value" }; | ||
14 | + let cls = createClass({ | ||
15 | + template: htmlTemplate, | ||
16 | + directives: [HtmlEditorComponent], | ||
17 | + properties: properties | ||
18 | + }); | ||
19 | + helper = new ComponentTestHelper<HtmlEditorComponent>(cls, done); | ||
20 | + }); | ||
21 | + | ||
22 | + it("render a textarea", () => { | ||
23 | + expect(helper.find("textarea").length).toEqual(1); | ||
24 | + }); | ||
25 | + }); | ||
26 | +}); |
src/app/shared/components/html-editor/html-editor.component.ts
0 → 100644
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +import {Component, Input} from "ng-forward"; | ||
2 | + | ||
3 | +@Component({ | ||
4 | + selector: 'html-editor', | ||
5 | + templateUrl: "app/shared/components/html-editor/html-editor.html", | ||
6 | +}) | ||
7 | +export class HtmlEditorComponent { | ||
8 | + | ||
9 | + @Input() options: any = {}; | ||
10 | + @Input() value: any; | ||
11 | +} |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<textarea ckeditor="ctrl.options" class="form-control" ng-model="ctrl.value"></textarea> |
src/app/shared/services/notification.service.ts
@@ -25,7 +25,7 @@ export class NotificationService { | @@ -25,7 +25,7 @@ export class NotificationService { | ||
25 | 25 | ||
26 | httpError(status: number, data: any): boolean { | 26 | httpError(status: number, data: any): boolean { |
27 | this.error({ message: `notification.http_error.${status}.message` }); | 27 | this.error({ message: `notification.http_error.${status}.message` }); |
28 | - return true; // return true to indicate that the error was already handled | 28 | + return false; // return true to indicate that the error was already handled |
29 | } | 29 | } |
30 | 30 | ||
31 | success({ | 31 | success({ |
src/languages/en.json
@@ -35,5 +35,16 @@ | @@ -35,5 +35,16 @@ | ||
35 | "comment.pagination.more": "More", | 35 | "comment.pagination.more": "More", |
36 | "comment.post.success.title": "Good job!", | 36 | "comment.post.success.title": "Good job!", |
37 | "comment.post.success.message": "Comment saved!", | 37 | "comment.post.success.message": "Comment saved!", |
38 | - "comment.reply": "reply" | 38 | + "comment.reply": "reply", |
39 | + "article.actions.edit": "Edit", | ||
40 | + "article.basic_editor.title": "Title", | ||
41 | + "article.basic_editor.body": "Body", | ||
42 | + "article.basic_editor.save": "Save", | ||
43 | + "article.basic_editor.save.failed": "This article could not be saved", | ||
44 | + "article.basic_editor.cancel": "Cancel", | ||
45 | + "article.basic_editor.success.title": "Good job!", | ||
46 | + "article.basic_editor.success.message": "Article saved!", | ||
47 | + "article.basic_editor.visibility": "Visibility", | ||
48 | + "article.basic_editor.visibility.public": "Public", | ||
49 | + "article.basic_editor.visibility.private": "Private" | ||
39 | } | 50 | } |
src/languages/pt.json
@@ -35,5 +35,16 @@ | @@ -35,5 +35,16 @@ | ||
35 | "comment.pagination.more": "Mais", | 35 | "comment.pagination.more": "Mais", |
36 | "comment.post.success.title": "Bom trabalho!", | 36 | "comment.post.success.title": "Bom trabalho!", |
37 | "comment.post.success.message": "Comentário salvo com sucesso!", | 37 | "comment.post.success.message": "Comentário salvo com sucesso!", |
38 | - "comment.reply": "responder" | 38 | + "comment.reply": "responder", |
39 | + "article.actions.edit": "Editar", | ||
40 | + "article.basic_editor.title": "Título", | ||
41 | + "article.basic_editor.body": "Corpo", | ||
42 | + "article.basic_editor.save": "Salvar", | ||
43 | + "article.basic_editor.save.failed": "O artigo não pode ser salvo", | ||
44 | + "article.basic_editor.cancel": "Cancelar", | ||
45 | + "article.basic_editor.success.title": "Bom trabalho!", | ||
46 | + "article.basic_editor.success.message": "Artigo salvo com sucesso!", | ||
47 | + "article.basic_editor.visibility": "Visibilidade", | ||
48 | + "article.basic_editor.visibility.public": "Público", | ||
49 | + "article.basic_editor.visibility.private": "Privado" | ||
39 | } | 50 | } |
src/lib/ng-noosfero-api/http/article.service.ts
@@ -22,6 +22,17 @@ export class ArticleService extends RestangularService<noosfero.Article> { | @@ -22,6 +22,17 @@ export class ArticleService extends RestangularService<noosfero.Article> { | ||
22 | }; | 22 | }; |
23 | } | 23 | } |
24 | 24 | ||
25 | + updateArticle(article: noosfero.Article) { | ||
26 | + let headers = { | ||
27 | + 'Content-Type': 'application/json' | ||
28 | + }; | ||
29 | + let deferred = this.$q.defer<noosfero.RestResult<noosfero.Article>>(); | ||
30 | + let attributesToUpdate: any = { article: { name: article.name, body: article.body, published: article.published } }; | ||
31 | + let restRequest: ng.IPromise<noosfero.RestResult<noosfero.Article>> = this.getElement(article.id).customPOST(attributesToUpdate, null, null, headers); | ||
32 | + restRequest.then(this.getHandleSuccessFunction(deferred)) | ||
33 | + .catch(this.getHandleErrorFunction(deferred)); | ||
34 | + return deferred.promise; | ||
35 | + } | ||
25 | 36 | ||
26 | createInProfile(profile: noosfero.Profile, article: noosfero.Article): ng.IPromise<noosfero.RestResult<noosfero.Article>> { | 37 | createInProfile(profile: noosfero.Profile, article: noosfero.Article): ng.IPromise<noosfero.RestResult<noosfero.Article>> { |
27 | let profileElement = this.profileService.get(<number>profile.id); | 38 | let profileElement = this.profileService.get(<number>profile.id); |
@@ -32,6 +43,14 @@ export class ArticleService extends RestangularService<noosfero.Article> { | @@ -32,6 +43,14 @@ export class ArticleService extends RestangularService<noosfero.Article> { | ||
32 | return this.create(article, <noosfero.RestModel>profileElement, null, headers); | 43 | return this.create(article, <noosfero.RestModel>profileElement, null, headers); |
33 | } | 44 | } |
34 | 45 | ||
46 | + createInParent(parentId: number, article: noosfero.Article): ng.IPromise<noosfero.RestResult<noosfero.Article>> { | ||
47 | + let headers = { | ||
48 | + 'Content-Type': 'application/json' | ||
49 | + }; | ||
50 | + | ||
51 | + let parent = this.getElement(parentId); | ||
52 | + return this.create(article, parent, null, headers, true, "children"); | ||
53 | + } | ||
35 | 54 | ||
36 | getAsCollectionChildrenOf<C>(rootElement: noosfero.Environment | noosfero.Article | noosfero.Profile, path: string, queryParams?: any, headers?: any): restangular.ICollectionPromise<C> { | 55 | getAsCollectionChildrenOf<C>(rootElement: noosfero.Environment | noosfero.Article | noosfero.Profile, path: string, queryParams?: any, headers?: any): restangular.ICollectionPromise<C> { |
37 | return rootElement.getList<C>(path, queryParams, headers); | 56 | return rootElement.getList<C>(path, queryParams, headers); |
@@ -77,5 +96,4 @@ export class ArticleService extends RestangularService<noosfero.Article> { | @@ -77,5 +96,4 @@ export class ArticleService extends RestangularService<noosfero.Article> { | ||
77 | } | 96 | } |
78 | 97 | ||
79 | 98 | ||
80 | - | ||
81 | } | 99 | } |
src/lib/ng-noosfero-api/http/restangular_service.ts
@@ -11,6 +11,8 @@ | @@ -11,6 +11,8 @@ | ||
11 | export abstract class RestangularService<T extends noosfero.RestModel> { | 11 | export abstract class RestangularService<T extends noosfero.RestModel> { |
12 | 12 | ||
13 | private baseResource: restangular.IElement; | 13 | private baseResource: restangular.IElement; |
14 | + private currentPromise: ng.IDeferred<T>; | ||
15 | + | ||
14 | /** | 16 | /** |
15 | * Creates an instance of RestangularService. | 17 | * Creates an instance of RestangularService. |
16 | * | 18 | * |
@@ -20,6 +22,7 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | @@ -20,6 +22,7 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | ||
20 | */ | 22 | */ |
21 | constructor(protected restangularService: restangular.IService, protected $q: ng.IQService, protected $log: ng.ILogService) { | 23 | constructor(protected restangularService: restangular.IService, protected $q: ng.IQService, protected $log: ng.ILogService) { |
22 | this.baseResource = restangularService.all(this.getResourcePath()); | 24 | this.baseResource = restangularService.all(this.getResourcePath()); |
25 | + this.resetCurrent(); | ||
23 | // TODO | 26 | // TODO |
24 | // this.restangularService.setResponseInterceptor((data, operation, what, url, response, deferred) => { | 27 | // this.restangularService.setResponseInterceptor((data, operation, what, url, response, deferred) => { |
25 | // let transformedData: any = data; | 28 | // let transformedData: any = data; |
@@ -32,6 +35,18 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | @@ -32,6 +35,18 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | ||
32 | // }); | 35 | // }); |
33 | } | 36 | } |
34 | 37 | ||
38 | + public resetCurrent() { | ||
39 | + this.currentPromise = this.$q.defer(); | ||
40 | + } | ||
41 | + | ||
42 | + public getCurrent(): ng.IPromise<T> { | ||
43 | + return this.currentPromise.promise; | ||
44 | + } | ||
45 | + | ||
46 | + public setCurrent(object: T) { | ||
47 | + this.currentPromise.resolve(object); | ||
48 | + } | ||
49 | + | ||
35 | protected extractData(response: restangular.IResponse): noosfero.RestResult<T> { | 50 | protected extractData(response: restangular.IResponse): noosfero.RestResult<T> { |
36 | let dataKey: string; | 51 | let dataKey: string; |
37 | if (response.data && this.getDataKeys()) { | 52 | if (response.data && this.getDataKeys()) { |
@@ -221,7 +236,7 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | @@ -221,7 +236,7 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | ||
221 | * Creates a new Resource into the resource collection | 236 | * Creates a new Resource into the resource collection |
222 | * calls POST /resourcePath | 237 | * calls POST /resourcePath |
223 | */ | 238 | */ |
224 | - public create(obj: T, rootElement?: noosfero.RestModel, queryParams?: any, headers?: any, isSub: boolean = true): ng.IPromise<noosfero.RestResult<T>> { | 239 | + public create(obj: T, rootElement?: noosfero.RestModel, queryParams?: any, headers?: any, isSub: boolean = true, path?: string): ng.IPromise<noosfero.RestResult<T>> { |
225 | let deferred = this.$q.defer<noosfero.RestResult<T>>(); | 240 | let deferred = this.$q.defer<noosfero.RestResult<T>>(); |
226 | 241 | ||
227 | let restRequest: ng.IPromise<noosfero.RestResult<T>>; | 242 | let restRequest: ng.IPromise<noosfero.RestResult<T>>; |
@@ -233,8 +248,9 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | @@ -233,8 +248,9 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | ||
233 | data = obj; | 248 | data = obj; |
234 | } | 249 | } |
235 | 250 | ||
251 | + let subpath = path || this.getResourcePath(); | ||
236 | if (rootElement) { | 252 | if (rootElement) { |
237 | - restRequest = rootElement.all(this.getResourcePath()).post(data, queryParams, headers); | 253 | + restRequest = rootElement.all(subpath).post(data, queryParams, headers); |
238 | } else { | 254 | } else { |
239 | restRequest = this.baseResource.post(data, queryParams, headers); | 255 | restRequest = this.baseResource.post(data, queryParams, headers); |
240 | } | 256 | } |
src/lib/ng-noosfero-api/interfaces/article.ts
1 | 1 | ||
2 | namespace noosfero { | 2 | namespace noosfero { |
3 | - export interface Article extends RestModel { | 3 | + export interface Article extends RestModel { |
4 | path: string; | 4 | path: string; |
5 | profile: Profile; | 5 | profile: Profile; |
6 | type: string; | 6 | type: string; |
7 | + parent: Article; | ||
8 | + body: string; | ||
9 | + title: string; | ||
10 | + name: string; | ||
11 | + published: boolean; | ||
7 | } | 12 | } |
8 | -} | ||
9 | \ No newline at end of file | 13 | \ No newline at end of file |
14 | +} |
src/spec/mocks.ts
1 | const DEBUG = false; | 1 | const DEBUG = false; |
2 | 2 | ||
3 | -let log = (message: string, ...args: any[]) => { | 3 | +let log = (message: string, ...args: any[]) => { |
4 | if (DEBUG) { | 4 | if (DEBUG) { |
5 | console.log(message); | 5 | console.log(message); |
6 | } | 6 | } |
@@ -70,7 +70,9 @@ export var mocks = { | @@ -70,7 +70,9 @@ export var mocks = { | ||
70 | return { | 70 | return { |
71 | then: (func?: Function) => { if (func) func(); } | 71 | then: (func?: Function) => { if (func) func(); } |
72 | }; | 72 | }; |
73 | - } | 73 | + }, |
74 | + setCurrent: (article: noosfero.Article) => { }, | ||
75 | + getCurrent: () => { return Promise.resolve({}); } | ||
74 | }, | 76 | }, |
75 | environmentService: { | 77 | environmentService: { |
76 | getEnvironmentPeople: (params: any) => { | 78 | getEnvironmentPeople: (params: any) => { |