Commit f9a71d965e2c8a7440dd7f9fcc357c3ea4a801da

Authored by Victor Costa
1 parent 12039f0c

Refactor of article cms

src/app/article/basic-editor/basic-editor.component.spec.ts
... ... @@ -1,84 +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 $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   -});
src/app/article/basic-editor/basic-editor.component.ts
... ... @@ -1,69 +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/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   -}
src/app/article/basic-editor/basic-editor.html
... ... @@ -1,34 +0,0 @@
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>
src/app/article/basic-editor/basic-editor.scss
... ... @@ -1,21 +0,0 @@
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/cms/basic-editor/basic-editor.component.ts 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +import {Component, Input} from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: 'article-basic-editor',
  5 + templateUrl: "app/article/cms/basic-editor/basic-editor.html"
  6 +})
  7 +export class BasicEditorComponent {
  8 +
  9 + @Input() article: noosfero.Article;
  10 +
  11 +}
... ...
src/app/article/cms/basic-editor/basic-editor.html 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<form>
  2 + <div class="form-group">
  3 + <label for="titleInput">{{"article.basic_editor.title" | translate}}</label>
  4 + <input type="text" class="form-control" id="titleInput" placeholder="{{'article.basic_editor.title' | translate}}" ng-model="ctrl.article.name">
  5 + </div>
  6 + <div class="form-group">
  7 + <label for="bodyInput">{{"article.basic_editor.body" | translate}}</label>
  8 + <html-editor [(value)]="ctrl.article.body"></html-editor>
  9 + </div>
  10 +</form>
... ...
src/app/article/cms/basic-editor/basic-editor.scss 0 → 100644
src/app/article/cms/basic-options/basic-options.component.ts 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +import {Component, Input} from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: 'article-basic-options',
  5 + templateUrl: "app/article/cms/basic-options/basic-options.html"
  6 +})
  7 +export class BasicOptionsComponent {
  8 +
  9 + @Input() article: noosfero.Article;
  10 +
  11 +}
... ...
src/app/article/cms/basic-options/basic-options.html 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +<div class="side-options">
  2 + <div class="visibility panel panel-default">
  3 + <div class="panel-heading">{{"article.basic_editor.visibility" | translate}}</div>
  4 + <div class="panel-body">
  5 + <div>
  6 + <input type="radio" ng-model="ctrl.article.published" ng-value="true">
  7 + <i class="fa fa-unlock fa-fw"></i> {{"article.basic_editor.visibility.public" | translate}}
  8 + </div>
  9 + <div>
  10 + <input type="radio" ng-model="ctrl.article.published" ng-value="false">
  11 + <i class="fa fa-lock fa-fw"></i> {{"article.basic_editor.visibility.private" | translate}}
  12 + </div>
  13 + </div>
  14 + </div>
  15 +</div>
... ...
src/app/article/cms/basic-options/basic-options.scss 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +.side-options {
  2 + margin-top: 25px;
  3 +
  4 + .visibility {
  5 + .panel-heading {
  6 + background-color: transparent;
  7 + font-weight: bold;
  8 + }
  9 + .panel-body {
  10 + i {
  11 + color: #A5A5A5;
  12 + }
  13 + }
  14 + }
  15 +}
... ...
src/app/article/cms/cms.component.spec.ts 0 → 100644
... ... @@ -0,0 +1,84 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {CmsComponent} from "./cms.component";
  3 +
  4 +
  5 +describe("Article Cms", () => {
  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: CmsComponent = new CmsComponent(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: CmsComponent = new CmsComponent(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: CmsComponent = new CmsComponent(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: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
  78 + component.save();
  79 + $rootScope.$apply();
  80 + expect(articleServiceMock.updateArticle).toHaveBeenCalledWith(component.article);
  81 + done();
  82 + });
  83 +
  84 +});
... ...
src/app/article/cms/cms.component.ts 0 → 100644
... ... @@ -0,0 +1,73 @@
  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 +import {BasicOptionsComponent} from './basic-options/basic-options.component';
  6 +import {BasicEditorComponent} from './basic-editor/basic-editor.component';
  7 +
  8 +@Component({
  9 + selector: 'article-cms',
  10 + templateUrl: "app/article/cms/cms.html",
  11 + providers: [
  12 + provide('articleService', { useClass: ArticleService }),
  13 + provide('profileService', { useClass: ProfileService }),
  14 + provide('notification', { useClass: NotificationService })
  15 + ],
  16 + directives: [BasicOptionsComponent, BasicEditorComponent]
  17 +})
  18 +@Inject(ArticleService, ProfileService, "$state", NotificationService, "$stateParams", "$window")
  19 +export class CmsComponent {
  20 +
  21 + article: noosfero.Article;
  22 + parent: noosfero.Article = <noosfero.Article>{};
  23 +
  24 + id: number;
  25 + parentId: number;
  26 + profileIdentifier: string;
  27 +
  28 + constructor(private articleService: ArticleService,
  29 + private profileService: ProfileService,
  30 + private $state: ng.ui.IStateService,
  31 + private notification: NotificationService,
  32 + private $stateParams: ng.ui.IStateParamsService,
  33 + private $window: ng.IWindowService) {
  34 +
  35 + this.parentId = this.$stateParams['parent_id'];
  36 + this.profileIdentifier = this.$stateParams["profile"];
  37 + this.id = this.$stateParams['id'];
  38 +
  39 + if (this.parentId) {
  40 + this.article = <noosfero.Article>{ type: this.$stateParams['type'] || "TextArticle", published: true };
  41 + this.articleService.get(this.parentId).then((result: noosfero.RestResult<noosfero.Article>) => {
  42 + this.parent = result.data;
  43 + });
  44 + }
  45 + if (this.id) {
  46 + this.articleService.get(this.id).then((result: noosfero.RestResult<noosfero.Article>) => {
  47 + this.article = result.data;
  48 + this.article.name = this.article.title; // FIXME
  49 + });
  50 + }
  51 + }
  52 +
  53 + save() {
  54 + this.profileService.setCurrentProfileByIdentifier(this.profileIdentifier).then((profile: noosfero.Profile) => {
  55 + if (this.id) {
  56 + return this.articleService.updateArticle(this.article);
  57 + } else {
  58 + return this.articleService.createInParent(this.parentId, this.article);
  59 + }
  60 + }).then((response: noosfero.RestResult<noosfero.Article>) => {
  61 + let article = (<noosfero.Article>response.data);
  62 + this.$state.go('main.profile.page', { page: article.path, profile: article.profile.identifier });
  63 + this.notification.success({ title: "article.basic_editor.success.title", message: "article.basic_editor.success.message" });
  64 + }).catch(() => {
  65 + this.notification.error({ message: "article.basic_editor.save.failed" });
  66 + });
  67 + }
  68 +
  69 + cancel() {
  70 + this.$window.history.back();
  71 + }
  72 +
  73 +}
... ...
src/app/article/cms/cms.html 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +<div class="cms">
  2 + <div class="row">
  3 + <div class="col-md-1"></div>
  4 + <div class="col-md-8">
  5 + <article-basic-editor ng-if="vm.article" [article]="vm.article"></article-basic-editor>
  6 + </div>
  7 + <div class="col-md-3">
  8 + <article-basic-options ng-if="vm.article" [article]="vm.article"></article-basic-options>
  9 + </div>
  10 + </div>
  11 + <div class="row">
  12 + <div class="col-md-1"></div>
  13 + <div class="col-md-8">
  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 + </div>
  17 + </div>
  18 +</div>
... ...
src/app/article/cms/cms.scss 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +.cms {
  2 + @extend .container-fluid;
  3 + padding: 0 1%;
  4 +}
... ...
src/app/profile/profile.component.ts
1 1 import {StateConfig, Component, Inject, provide} from 'ng-forward';
2 2 import {ProfileInfoComponent} from './info/profile-info.component';
3 3 import {ProfileHomeComponent} from './profile-home.component';
4   -import {BasicEditorComponent} from '../article/basic-editor/basic-editor.component';
  4 +import {BasicEditorComponent} from '../article/cms/basic-editor/basic-editor.component';
  5 +import {CmsComponent} from '../article/cms/cms.component';
5 6 import {ContentViewerComponent} from "../article/content-viewer/content-viewer.component";
6 7 import {ContentViewerActionsComponent} from "../article/content-viewer/content-viewer-actions.component";
7 8 import {ActivitiesComponent} from "./activities/activities.component";
... ... @@ -46,12 +47,12 @@ import {MyProfileComponent} from &quot;./myprofile.component&quot;;
46 47 },
47 48 {
48 49 name: 'main.cms',
49   - url: "^/myprofile/:profile/cms?parent_id",
50   - component: BasicEditorComponent,
  50 + url: "^/myprofile/:profile/cms?parent_id&type",
  51 + component: CmsComponent,
51 52 views: {
52 53 "content": {
53   - templateUrl: "app/article/basic-editor/basic-editor.html",
54   - controller: BasicEditorComponent,
  54 + templateUrl: "app/article/cms/cms.html",
  55 + controller: CmsComponent,
55 56 controllerAs: "vm"
56 57 }
57 58 }
... ... @@ -59,11 +60,11 @@ import {MyProfileComponent} from &quot;./myprofile.component&quot;;
59 60 {
60 61 name: 'main.cmsEdit',
61 62 url: "^/myprofile/:profile/cms/edit/:id",
62   - component: BasicEditorComponent,
  63 + component: CmsComponent,
63 64 views: {
64 65 "content": {
65   - templateUrl: "app/article/basic-editor/basic-editor.html",
66   - controller: BasicEditorComponent,
  66 + templateUrl: "app/article/cms/cms.html",
  67 + controller: CmsComponent,
67 68 controllerAs: "vm"
68 69 }
69 70 }
... ...