Commit 7044b1ae115fc6d86408eeb89aa97a8e2b356ebc

Authored by ABNER SILVA DE OLIVEIRA
1 parent 5ef3ec06
Exists in master and in 1 other branch dev-fixes

refactory of the folder structure and file name convention

Showing 232 changed files with 3197 additions and 3132 deletions   Show diff stats
.vscode/settings.json
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 "files.exclude": { 3 "files.exclude": {
4 "**/.git": true, 4 "**/.git": true,
5 "**/.DS_Store": true, 5 "**/.DS_Store": true,
6 - "src/app/*.js": false 6 + "src/**/*.js": true,
  7 + "src/**/*.js.map": true,
  8 + "coverage": true
7 }, 9 },
8 "editor.fontSize": 14, 10 "editor.fontSize": 14,
9 "typescript.useCodeSnippetsOnMethodSuggest": true 11 "typescript.useCodeSnippetsOnMethodSuggest": true
src/app/admin/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/article/article-default-view-component.spec.ts 0 → 100644
@@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
  1 +
  2 +import {Input, provide, Component} from 'ng-forward';
  3 +import {ArticleViewComponent, ArticleDefaultViewComponent} from './article-default-view.component';
  4 +
  5 +import {createComponentFromClass, quickCreateComponent} from "../../spec/helpers";
  6 +
  7 +// this htmlTemplate will be re-used between the container components in this spec file
  8 +const htmlTemplate: string = '<noosfero-article [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-article>';
  9 +
  10 +
  11 +describe("Components", () => {
  12 +
  13 + describe("ArticleView Component", () => {
  14 +
  15 + // the karma preprocessor html2js transform the templates html into js files which put
  16 + // the templates to the templateCache into the module templates
  17 + // we need to load the module templates here as the template for the
  18 + // component Noosfero ArtileView will be load on our tests
  19 + beforeEach(angular.mock.module("templates"));
  20 +
  21 + it("renders the default component when no specific component is found", (done: Function) => {
  22 + // Creating a container component (ArticleContainerComponent) to include
  23 + // the component under test (ArticleView)
  24 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent] })
  25 + class ArticleContainerComponent {
  26 + article = { type: 'anyArticleType' };
  27 + profile = { name: 'profile-name' };
  28 + constructor() {
  29 + }
  30 + }
  31 +
  32 + createComponentFromClass(ArticleContainerComponent).then((fixture) => {
  33 + // and here we can inspect and run the test assertions
  34 +
  35 + // gets the children component of ArticleContainerComponent
  36 + let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  37 +
  38 + // and checks if the article View rendered was the Default Article View
  39 + expect(articleView.constructor.prototype).toEqual(ArticleDefaultViewComponent.prototype);
  40 +
  41 + // done needs to be called (it isn't really needed, as we can read in
  42 + // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
  43 + // because createAsync in ng-forward is not really async, but as the intention
  44 + // here is write tests in angular 2 ways, this is recommended
  45 + done();
  46 + });
  47 +
  48 + });
  49 +
  50 + it("receives the article and profile as inputs", (done: Function) => {
  51 +
  52 + // Creating a container component (ArticleContainerComponent) to include
  53 + // the component under test (ArticleView)
  54 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent] })
  55 + class ArticleContainerComponent {
  56 + article = { type: 'anyArticleType' };
  57 + profile = { name: 'profile-name' };
  58 + constructor() {
  59 + }
  60 + }
  61 +
  62 + // uses the TestComponentBuilder instance to initialize the component
  63 + createComponentFromClass(ArticleContainerComponent).then((fixture) => {
  64 + // and here we can inspect and run the test assertions
  65 + let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  66 +
  67 + // assure the article object inside the ArticleView matches
  68 + // the provided through the parent component
  69 + expect(articleView.article.type).toEqual("anyArticleType");
  70 + expect(articleView.profile.name).toEqual("profile-name");
  71 +
  72 + // done needs to be called (it isn't really needed, as we can read in
  73 + // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
  74 + // because createAsync in ng-forward is not really async, but as the intention
  75 + // here is write tests in angular 2 ways, this is recommended
  76 + done();
  77 + });
  78 + });
  79 +
  80 +
  81 + it("renders a article view which matches to the article type", done => {
  82 + // NoosferoTinyMceArticle component created to check if it will be used
  83 + // when a article with type 'TinyMceArticle' is provided to the noosfero-article (ArticleView)
  84 + // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider
  85 + @Component({ selector: 'noosfero-tiny-mce-article', template: "<h1>TinyMceArticle</h1>" })
  86 + class TinyMceArticleView {
  87 + @Input() article: any;
  88 + @Input() profile: any;
  89 + }
  90 +
  91 + // Creating a container component (ArticleContainerComponent) to include our NoosferoTinyMceArticle
  92 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent, TinyMceArticleView] })
  93 + class CustomArticleType {
  94 + article = { type: 'TinyMceArticle' };
  95 + profile = { name: 'profile-name' };
  96 + constructor() {
  97 + }
  98 + }
  99 + createComponentFromClass(CustomArticleType).then(fixture => {
  100 + let myComponent: CustomArticleType = fixture.componentInstance;
  101 + expect(myComponent.article.type).toEqual("TinyMceArticle");
  102 + expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("TinyMceArticle");
  103 + done();
  104 + });
  105 + });
  106 +
  107 + });
  108 +});
0 \ No newline at end of file 109 \ No newline at end of file
src/app/article/article-default-view.component.ts 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +import { bundle, Input, Inject, Component, Directive } from 'ng-forward';
  2 +import {ArticleBlogComponent} from "./types/blog/blog.component";
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name ArticleDefaultView
  7 + * @description
  8 + * A default view for Noosfero Articles. If the specific article view is
  9 + * not implemented, then this view is used.
  10 + */
  11 +@Component({
  12 + selector: 'noosfero-default-article',
  13 + templateUrl: 'app/article/article.html'
  14 +})
  15 +export class ArticleDefaultViewComponent {
  16 +
  17 + @Input() article: noosfero.Article;
  18 + @Input() profile: noosfero.Profile;
  19 +
  20 +}
  21 +
  22 +/**
  23 + * @ngdoc controller
  24 + * @name ArticleView
  25 + * @description
  26 + * A dynamic view for articles. It uses the article type to replace
  27 + * the default template with the custom article directive.
  28 + */
  29 +@Component({
  30 + selector: 'noosfero-article',
  31 + template: 'not-used',
  32 + directives: [ArticleDefaultViewComponent, ArticleBlogComponent]
  33 +})
  34 +@Inject("$element", "$scope", "$injector", "$compile")
  35 +export class ArticleViewComponent {
  36 +
  37 + @Input() article: noosfero.Article;
  38 + @Input() profile: noosfero.Profile;
  39 + directiveName: string;
  40 +
  41 + ngOnInit() {
  42 + let specificDirective = 'noosfero' + this.article.type;
  43 + this.directiveName = "noosfero-default-article";
  44 + if (this.$injector.has(specificDirective + 'Directive')) {
  45 + this.directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
  46 + }
  47 + this.$element.replaceWith(this.$compile('<' + this.directiveName + ' [article]="ctrl.article" [profile]="ctrl.profile"></' + this.directiveName + '>')(this.$scope));
  48 + }
  49 +
  50 + constructor(
  51 + private $element: any,
  52 + private $scope: ng.IScope,
  53 + private $injector: ng.auto.IInjectorService,
  54 + private $compile: ng.ICompileService) {
  55 +
  56 + }
  57 +}
src/app/article/article.html 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +<div class="article">
  2 + <div class="page-header">
  3 + <h3 ng-bind="ctrl.article.title"></h3>
  4 + </div>
  5 +
  6 + <div class="sub-header clearfix">
  7 + <div class="page-info pull-right small text-muted">
  8 + <span class="time">
  9 + <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span>
  10 + </span>
  11 + <span class="author" ng-if="ctrl.article.author">
  12 + <i class="fa fa-user"></i>
  13 + <a ui-sref="main.profile.home({profile: ctrl.article.author.identifier})">
  14 + <span class="author-name" ng-bind="ctrl.article.author.name"></span>
  15 + </a>
  16 + </span>
  17 + </div>
  18 + </div>
  19 +
  20 + <div class="page-body">
  21 + <div ng-bind-html="ctrl.article.body"></div>
  22 + </div>
  23 +</div>
src/app/article/article.scss 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +.article {
  2 + .page-info {
  3 + .author {
  4 + a {
  5 + color: #b4bcc2;
  6 + }
  7 + }
  8 + }
  9 +
  10 + .page-header {
  11 + margin-bottom: 5px;
  12 + }
  13 +
  14 + .sub-header {
  15 + margin-bottom: 20px;
  16 + }
  17 +}
src/app/article/basic-editor.component.spec.ts 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  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 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  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("Good job!", "Article saved!");
  32 + });
  33 + }
  34 +
  35 +}
src/app/article/basic-editor.html 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  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/content-viewer/content-viewer-actions.component.spec.ts 0 → 100644
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
  1 +import {providers} from 'ng-forward/cjs/testing/providers';
  2 +
  3 +import {Input, Component, provide} from 'ng-forward';
  4 +
  5 +import * as helpers from "../../../spec/helpers";
  6 +
  7 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  8 +import {ContentViewerActions} from './content-viewer-actions.component';
  9 +
  10 +// this htmlTemplate will be re-used between the container components in this spec file
  11 +const htmlTemplate: string = '<content-viewer-actions [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer-actions>';
  12 +
  13 +describe('Content Viewer Actions Component', () => {
  14 +
  15 + beforeEach(() => {
  16 +
  17 + angular.mock.module("templates");
  18 +
  19 + providers((provide: any) => {
  20 + return <any>[
  21 + provide('ProfileService', {
  22 + useValue: helpers.mocks.profileService
  23 + })
  24 + ];
  25 + });
  26 + });
  27 +
  28 + let buildComponent = (): Promise<ComponentFixture> => {
  29 + return helpers.quickCreateComponent({
  30 + providers: [
  31 + helpers.provideEmptyObjects('Restangular'),
  32 + helpers.provideFilters('translateFilter')
  33 + ],
  34 + directives: [ContentViewerActions],
  35 + template: htmlTemplate
  36 + });
  37 + };
  38 +
  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);
  42 +
  43 + done();
  44 + });
  45 + });
  46 +
  47 + it('check if profile was loaded', (done: Function) => {
  48 + let profile: any = {
  49 + id: 1,
  50 + identifier: 'the-profile-test',
  51 + type: 'Person'
  52 + };
  53 +
  54 + helpers.mocks.profileService.getCurrentProfile = () => {
  55 + return helpers.mocks.promiseResultTemplate(profile);
  56 + };
  57 +
  58 + buildComponent().then((fixture: ComponentFixture) => {
  59 + let contentViewerComp: ContentViewerActions = fixture.debugElement.componentViewChildren[0].componentInstance;
  60 +
  61 + expect(contentViewerComp.profile).toEqual(jasmine.objectContaining(profile));
  62 +
  63 + done();
  64 + });
  65 + });
  66 +
  67 +});
src/app/article/content-viewer/content-viewer-actions.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {Component, Inject, provide} from "ng-forward";
  2 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: "content-viewer-actions",
  6 + templateUrl: "app/article/content-viewer/navbar-actions.html",
  7 + providers: [provide('profileService', { useClass: ProfileService })]
  8 +})
  9 +@Inject(ProfileService)
  10 +export class ContentViewerActions {
  11 +
  12 + article: noosfero.Article;
  13 + profile: noosfero.Profile;
  14 +
  15 + constructor(profileService: ProfileService) {
  16 + profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  17 + this.profile = profile;
  18 + });
  19 + }
  20 +}
src/app/article/content-viewer/content-viewer.component.spec.ts 0 → 100644
@@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
  1 +import {providers} from 'ng-forward/cjs/testing/providers';
  2 +
  3 +import {Input, Component, provide} from 'ng-forward';
  4 +
  5 +import * as helpers from "../../../spec/helpers";
  6 +
  7 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  8 +import {ContentViewerComponent} from './content-viewer.component';
  9 +
  10 +// this htmlTemplate will be re-used between the container components in this spec file
  11 +const htmlTemplate: string = '<content-viewer [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer>';
  12 +
  13 +describe('Content Viewer Component', () => {
  14 +
  15 + let stateParamsService: any;
  16 +
  17 + // loading the templates
  18 + beforeEach(() => {
  19 + angular.mock.module("templates");
  20 +
  21 + stateParamsService = { page: 1 };
  22 +
  23 + providers((provide: any) => {
  24 + return <any>[
  25 + provide('ArticleService', {
  26 + useValue: helpers.mocks.articleService
  27 + }),
  28 + provide('ProfileService', {
  29 + useValue: helpers.mocks.profileService
  30 + }),
  31 + // TODO: Como criar um mock do atributo "page" de stateParams
  32 + provide('$stateParams', {
  33 + useValue: stateParamsService
  34 + })
  35 + ];
  36 + });
  37 + });
  38 +
  39 + let buildComponent = (): Promise<ComponentFixture> => {
  40 + return helpers.quickCreateComponent({
  41 + providers: [
  42 + helpers.provideEmptyObjects('Restangular')
  43 + ],
  44 + directives: [ContentViewerComponent],
  45 + template: htmlTemplate
  46 + });
  47 + };
  48 +
  49 + it('renders content viewer directive', (done: Function) => {
  50 + buildComponent().then((fixture: ComponentFixture) => {
  51 + expect(fixture.debugElement.query('content-viewer').length).toEqual(1);
  52 +
  53 + done();
  54 + });
  55 + });
  56 +
  57 + it('check if article was loaded', (done: Function) => {
  58 + let article: any = {
  59 + id: 1,
  60 + title: 'The article test'
  61 + };
  62 + let profile: any = {
  63 + id: 1,
  64 + identifier: 'the-profile-test',
  65 + type: 'Person'
  66 + };
  67 +
  68 + helpers.mocks.profileService.getCurrentProfile = () => {
  69 + return helpers.mocks.promiseResultTemplate(profile);
  70 + };
  71 +
  72 + helpers.mocks.articleService.getArticleByProfileAndPath = (profile: noosfero.Profile, path: string) => {
  73 + return helpers.mocks.promiseResultTemplate({
  74 + data: article
  75 + });
  76 + };
  77 +
  78 +
  79 + buildComponent().then((fixture: ComponentFixture) => {
  80 + let contentViewerComp: ContentViewerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  81 +
  82 + expect(contentViewerComp.profile).toEqual(profile);
  83 + expect(contentViewerComp.article).toEqual(article);
  84 +
  85 + done();
  86 + });
  87 + });
  88 +});
src/app/article/content-viewer/content-viewer.component.ts 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +import {ArticleViewComponent} from "./../article-default-view.component";
  2 +import {Input, Component, StateConfig, Inject, provide} from "ng-forward";
  3 +
  4 +import {ArticleBlogComponent} from "./../types/blog/blog.component";
  5 +import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service";
  6 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  7 +
  8 +@Component({
  9 + selector: "content-viewer",
  10 + templateUrl: "app/article/content-viewer/page.html",
  11 + directives: [ArticleBlogComponent, ArticleViewComponent],
  12 + providers: [
  13 + provide('articleService', { useClass: ArticleService }),
  14 + provide('profileService', { useClass: ProfileService })
  15 + ]
  16 +})
  17 +@Inject(ArticleService, ProfileService, "$log", "$stateParams")
  18 +export class ContentViewerComponent {
  19 +
  20 + @Input()
  21 + article: noosfero.Article = null;
  22 +
  23 + @Input()
  24 + profile: noosfero.Profile = null;
  25 +
  26 + constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) {
  27 + this.activate();
  28 + }
  29 +
  30 + activate() {
  31 + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  32 + this.profile = profile;
  33 + return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]);
  34 + }).then((result: noosfero.RestResult<any>) => {
  35 + this.article = <noosfero.Article>result.data;
  36 + });
  37 + }
  38 +}
src/app/article/content-viewer/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./content-viewer-actions.component";
  3 +export * from "./content-viewer.component";
src/app/article/content-viewer/navbar-actions.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<ul class="nav navbar-nav">
  2 + <li ng-show="vm.profile">
  3 + <a href="#" role="button" ui-sref="main.profile.cms({profile: vm.profile.identifier})">
  4 + <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}}
  5 + </a>
  6 + </li>
  7 +</ul>
src/app/article/content-viewer/page.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<noosfero-article ng-if="vm.article" [article]="vm.article" [profile]="vm.profile"></noosfero-article>
src/app/article/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./article-default-view.component";
  3 +export * from "./basic-editor.component";
src/app/article/types/blog/blog.component.spec.ts 0 → 100644
@@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
  1 +import {
  2 +providers
  3 +} from 'ng-forward/cjs/testing/providers';
  4 +
  5 +import {
  6 +Input,
  7 +Component
  8 +} from 'ng-forward';
  9 +import {
  10 +ArticleBlogComponent
  11 +} from './blog.component';
  12 +
  13 +import {
  14 +createComponentFromClass,
  15 +quickCreateComponent,
  16 +provideEmptyObjects,
  17 +createProviderToValue,
  18 +provideFilters
  19 +} from "../../../../spec/helpers.ts";
  20 +
  21 +// this htmlTemplate will be re-used between the container components in this spec file
  22 +const htmlTemplate: string = '<noosfero-blog [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-blog>';
  23 +
  24 +describe("Blog Component", () => {
  25 +
  26 + function promiseResultTemplate(response?: {}) {
  27 + let thenFuncEmpty = (func: Function) => {
  28 + // does nothing
  29 + };
  30 + if (response) {
  31 + return {
  32 + then: (func: (response: any) => void) => {
  33 + func(response);
  34 + }
  35 + };
  36 + } else {
  37 + return {
  38 + then: (func: (response: any) => void) => {
  39 + // does nothing
  40 + }
  41 + };
  42 + }
  43 + }
  44 +
  45 + let articleService = {
  46 + getChildren: (article_id: number, filters: {}) => {
  47 + return promiseResultTemplate(null);
  48 + }
  49 + };
  50 +
  51 + @Component({
  52 + selector: 'test-container-component',
  53 + template: htmlTemplate,
  54 + directives: [ArticleBlogComponent],
  55 + providers: [
  56 + provideEmptyObjects('Restangular'),
  57 + createProviderToValue('ArticleService', articleService),
  58 + provideFilters('truncateFilter')
  59 + ]
  60 + })
  61 + class BlogContainerComponent {
  62 + article = {
  63 + type: 'anyArticleType'
  64 + };
  65 + profile = {
  66 + name: 'profile-name'
  67 + };
  68 + }
  69 +
  70 + beforeEach(() => {
  71 +
  72 + // the karma preprocessor html2js transform the templates html into js files which put
  73 + // the templates to the templateCache into the module templates
  74 + // we need to load the module templates here as the template for the
  75 + // component Noosfero ArtileView will be load on our tests
  76 + angular.mock.module("templates");
  77 +
  78 + providers((provide: any) => {
  79 + return <any>[
  80 + provide('ArticleService', {
  81 + useValue: articleService
  82 + })
  83 + ];
  84 + });
  85 + });
  86 +
  87 + it("renders the blog content", (done: Function) => {
  88 +
  89 + createComponentFromClass(BlogContainerComponent).then((fixture) => {
  90 +
  91 + expect(fixture.debugElement.query('div.blog').length).toEqual(1);
  92 +
  93 + done();
  94 + });
  95 + });
  96 +
  97 + it("verify the blog data", (done: Function) => {
  98 +
  99 + let articles = [{
  100 + id: 1,
  101 + title: 'The article test'
  102 + }];
  103 +
  104 + let result = { data: articles, headers: (name: string) => { return 1; } };
  105 +
  106 + // defining a mock result to articleService.getChildren method
  107 + articleService.getChildren = (article_id: number, filters: {}) => {
  108 + return promiseResultTemplate(result);
  109 + };
  110 +
  111 + createComponentFromClass(BlogContainerComponent).then((fixture) => {
  112 +
  113 + // gets the children component of BlogContainerComponent
  114 + let articleBlog: BlogContainerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  115 +
  116 + // check if the component property are the provided by the mocked articleService
  117 + let post = {
  118 + id: 1,
  119 + title: 'The article test'
  120 + };
  121 + expect((<any>articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post));
  122 + expect((<any>articleBlog)["totalPosts"]).toEqual(1);
  123 +
  124 + done();
  125 + });
  126 +
  127 + });
  128 +
  129 +});
0 \ No newline at end of file 130 \ No newline at end of file
src/app/article/types/blog/blog.component.ts 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +import {Component, Input, Inject} from "ng-forward";
  2 +
  3 +import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";
  4 +
  5 +/**
  6 + * @ngdoc controller
  7 + * @name ArticleBlog
  8 + * @description
  9 + * An specific {@link ArticleView} for Blog articles.
  10 + */
  11 +@Component({
  12 + selector: "noosfero-blog",
  13 + templateUrl: "app/article/types/blog/blog.html"
  14 +})
  15 +@Inject(ArticleService)
  16 +export class ArticleBlogComponent {
  17 +
  18 + @Input() article: noosfero.Article;
  19 + @Input() profile: noosfero.Profile;
  20 +
  21 + private posts: noosfero.Article[];
  22 + private perPage: number = 3;
  23 + private currentPage: number;
  24 + private totalPosts: number = 0;
  25 +
  26 + constructor(private articleService: ArticleService) { }
  27 +
  28 + ngOnInit() {
  29 + this.loadPage();
  30 + }
  31 +
  32 + loadPage() {
  33 + let filters = {
  34 + content_type: "TinyMceArticle",
  35 + per_page: this.perPage,
  36 + page: this.currentPage
  37 + };
  38 +
  39 + this.articleService
  40 + .getChildren(this.article, filters)
  41 + .then((result: noosfero.RestResult<noosfero.Article[]>) => {
  42 + this.totalPosts = <number>result.headers("total");
  43 + this.posts = result.data;
  44 + });
  45 + }
  46 +
  47 +}
src/app/article/types/blog/blog.html 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +<div class="blog">
  2 + <div class="blog-cover" ng-show="ctrl.article.image">
  3 + <img ng-src="{{ctrl.article.image.url}}" class="img-responsive">
  4 + <h3 ng-bind="ctrl.article.title"></h3>
  5 + </div>
  6 +
  7 + <div class="page-header" ng-show="!ctrl.article.image">
  8 + <h3 ng-bind="ctrl.article.title"></h3>
  9 + </div>
  10 +
  11 + <div>
  12 + <div ng-repeat="child in ctrl.posts | orderBy: 'created_at':true">
  13 + <div class="page-header">
  14 + <a class="title" ui-sref="main.profile.page({profile: ctrl.profile.identifier, page: child.path})"><h4 ng-bind="child.title"></h4></a>
  15 + <div class="post-lead" ng-bind-html="child.body | truncate: 500: '...': true"></div>
  16 + </div>
  17 + </div>
  18 + </div>
  19 +
  20 + <pagination ng-model="ctrl.currentPage" total-items="ctrl.totalPosts" class="pagination-sm center-block"
  21 + boundary-links="true" items-per-page="ctrl.perPage" ng-change="ctrl.loadPage()"
  22 + first-text="«" last-text="»" previous-text="‹" next-text="›">
  23 + </pagination>
  24 +</div>
src/app/article/types/blog/blog.scss 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +.blog {
  2 + .blog-cover {
  3 + margin: -15px;
  4 + position: relative;
  5 + h3 {
  6 + position: absolute;
  7 + bottom: 0;
  8 + background-color: rgba(0, 0, 0, 0.4);
  9 + color: white;
  10 + padding: 10px 15px;
  11 + margin: 0;
  12 + width: 100%;
  13 + }
  14 + }
  15 +}
src/app/article/types/blog/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./blog.component";
src/app/article/types/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/cms/cms.component.spec.ts
@@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
1 -import {quickCreateComponent} from "../../spec/helpers";  
2 -import {Cms} from "./cms.component";  
3 -  
4 -describe("Components", () => {  
5 - describe("Cms Component", () => {  
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: Cms = new Cms(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: Cms = new Cms(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 - });  
56 -});  
src/app/cms/cms.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 {Notification} from "../components/notification/notification.component";  
5 -  
6 -@Component({  
7 - selector: 'cms',  
8 - templateUrl: "app/cms/cms.html",  
9 - providers: [  
10 - provide('articleService', { useClass: ArticleService }),  
11 - provide('profileService', { useClass: ProfileService }),  
12 - provide('notification', { useClass: Notification })  
13 - ]  
14 -})  
15 -@Inject(ArticleService, ProfileService, "$state", Notification)  
16 -export class Cms {  
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: Notification) { }  
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("Good job!", "Article saved!");  
32 - });  
33 - }  
34 -  
35 -}  
src/app/cms/cms.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/cms/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./cms.component";  
src/app/components/auth/auth_controller.spec.ts
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -import {AuthController} from "./auth_controller";  
2 -import {AuthService} from "./auth_service";  
3 -  
4 -describe("Controllers", () => {  
5 -  
6 -  
7 - describe("AuthController", () => {  
8 -  
9 - it("calls authenticate on AuthService when login called", () => {  
10 -  
11 - // creating a Mock AuthService  
12 - let AuthServiceMock: AuthService = jasmine.createSpyObj("AuthService", ["login"]);  
13 -  
14 - // pass AuthServiceMock into the constructor  
15 - let authController = new AuthController(null, null, AuthServiceMock);  
16 -  
17 - // setup of authController -> set the credentials instance property  
18 - let credentials = { username: "username", password: "password" };  
19 -  
20 - authController.credentials = credentials;  
21 -  
22 - // calls the authController login method  
23 - authController.login();  
24 -  
25 - // checks if the method login of the injected AuthService has been called  
26 - expect(AuthServiceMock.login).toHaveBeenCalledWith(credentials);  
27 -  
28 - });  
29 -  
30 -  
31 -  
32 - });  
33 -});  
src/app/components/auth/auth_controller.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {AuthService} from "./auth_service";  
2 -  
3 -export class AuthController {  
4 -  
5 - static $inject = ["$log", "$stateParams", "AuthService"];  
6 -  
7 - constructor(  
8 - private $log: ng.ILogService,  
9 - private $stateParams: any,  
10 - private AuthService: AuthService  
11 - ) {  
12 -  
13 - }  
14 -  
15 - credentials: noosfero.Credentials;  
16 -  
17 - login() {  
18 - this.AuthService.login(this.credentials);  
19 - }  
20 -}  
src/app/components/auth/auth_events.ts
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -export interface IAuthEvents {  
2 - loginSuccess: string;  
3 - loginFailed: string;  
4 - logoutSuccess: string;  
5 -}  
6 -  
7 -export const AUTH_EVENTS: IAuthEvents = {  
8 - loginSuccess: "auth-login-success",  
9 - loginFailed: "auth-login-failed",  
10 - logoutSuccess: "auth-logout-success"  
11 -};  
12 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/auth_service.spec.ts
@@ -1,81 +0,0 @@ @@ -1,81 +0,0 @@
1 -  
2 -  
3 -import {AuthService, AUTH_EVENTS} from "./";  
4 -  
5 -describe("Services", () => {  
6 -  
7 -  
8 - describe("Auth Service", () => {  
9 -  
10 - let $httpBackend: ng.IHttpBackendService;  
11 - let authService: AuthService;  
12 - let credentials: noosfero.Credentials;  
13 - let $rootScope: ng.IRootScopeService;  
14 - let user: noosfero.User;  
15 -  
16 - beforeEach(angular.mock.module("noosferoApp", ($translateProvider: angular.translate.ITranslateProvider) => {  
17 - $translateProvider.translations('en', {});  
18 - }));  
19 -  
20 - beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _$rootScope_: ng.IRootScopeService, _AuthService_: AuthService) => {  
21 - $httpBackend = _$httpBackend_;  
22 - authService = _AuthService_;  
23 - $rootScope = _$rootScope_;  
24 -  
25 - user = <noosfero.User>{  
26 - id: 1,  
27 - login: "user"  
28 - };  
29 - }));  
30 -  
31 -  
32 - describe("Succesffull login", () => {  
33 -  
34 - beforeEach(() => {  
35 - credentials = { username: "user", password: "password" };  
36 -  
37 - $httpBackend.expectPOST("/api/v1/login", "login=user&password=password").respond(200, { user: user });  
38 - });  
39 -  
40 - it("should return loggedUser", (done) => {  
41 - authService.login(credentials).then((loggedUser) => {  
42 - expect(loggedUser).toBeDefined();  
43 - done();  
44 - });  
45 - $httpBackend.flush();  
46 - expect($httpBackend.verifyNoOutstandingRequest());  
47 - });  
48 -  
49 -  
50 - it("should emit event loggin successful with user logged data", () => {  
51 -  
52 - authService.login(credentials);  
53 -  
54 - let eventEmmited: boolean = false;  
55 - $rootScope.$on(AUTH_EVENTS.loginSuccess, (event: ng.IAngularEvent, userThroughEvent: noosfero.User) => {  
56 - eventEmmited = true;  
57 - expect(userThroughEvent).toEqual(user);  
58 - });  
59 -  
60 - $httpBackend.flush();  
61 -  
62 - expect(eventEmmited).toBeTruthy(AUTH_EVENTS.loginSuccess + " was not emmited!");  
63 - });  
64 -  
65 - it("should return the current logged in user", () => {  
66 - authService.login(credentials);  
67 - $httpBackend.flush();  
68 - let actual: noosfero.User = authService.currentUser();  
69 - expect(actual).toEqual(user, "The returned user must be present");  
70 - });  
71 -  
72 - it("should not return the current user after logout", () => {  
73 - authService.logout();  
74 - let actual: any = authService.currentUser();  
75 - expect(actual).toEqual(undefined, "The returned user must not be defined");  
76 - });  
77 - });  
78 -  
79 -  
80 - });  
81 -});  
src/app/components/auth/auth_service.ts
@@ -1,69 +0,0 @@ @@ -1,69 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -  
3 -import {NoosferoRootScope, UserResponse} from "./../../models/interfaces";  
4 -import {Session} from "./session";  
5 -  
6 -import {AUTH_EVENTS, IAuthEvents} from "./auth_events";  
7 -  
8 -@Injectable()  
9 -@Inject("$q", "$http", "$rootScope", "Session", "$log", "AUTH_EVENTS")  
10 -export class AuthService {  
11 -  
12 - constructor(private $q: ng.IQService,  
13 - private $http: ng.IHttpService,  
14 - private $rootScope: NoosferoRootScope,  
15 - private session: Session,  
16 - private $log: ng.ILogService,  
17 - private auth_events: IAuthEvents) {  
18 -  
19 - }  
20 -  
21 - loginFromCookie() {  
22 - let url: string = '/api/v1/login_from_cookie';  
23 - return this.$http.post(url, null).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));  
24 - }  
25 -  
26 -  
27 - private loginSuccessCallback(response: ng.IHttpPromiseCallbackArg<UserResponse>) {  
28 - this.$log.debug('AuthService.login [SUCCESS] response', response);  
29 - let currentUser: noosfero.User = this.session.create(response.data);  
30 - this.$rootScope.currentUser = currentUser;  
31 - this.$rootScope.$broadcast(this.auth_events.loginSuccess, currentUser);  
32 - return currentUser;  
33 - }  
34 -  
35 - login(credentials: noosfero.Credentials): ng.IPromise<noosfero.User> {  
36 - let url = '/api/v1/login';  
37 - let encodedData = 'login=' + credentials.username + '&password=' + credentials.password;  
38 - return this.$http.post(url, encodedData).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));  
39 - }  
40 -  
41 - private loginFailedCallback(response: ng.IHttpPromiseCallbackArg<any>): any {  
42 - this.$log.debug('AuthService.login [FAIL] response', response);  
43 - this.$rootScope.$broadcast(this.auth_events.loginFailed);  
44 - // return $q.reject(response);  
45 - return null;  
46 - }  
47 -  
48 - public logout() {  
49 - this.session.destroy();  
50 - this.$rootScope.currentUser = undefined;  
51 - this.$rootScope.$broadcast(this.auth_events.logoutSuccess);  
52 - this.$http.jsonp('/account/logout'); // FIXME logout from noosfero to sync login state  
53 - }  
54 -  
55 - public isAuthenticated() {  
56 - return !!this.session.currentUser();  
57 - }  
58 -  
59 - public currentUser(): noosfero.User {  
60 - return this.session.currentUser();  
61 - }  
62 -  
63 - public isAuthorized(authorizedRoles: string | string[]) {  
64 - if (!angular.isArray(authorizedRoles)) {  
65 - authorizedRoles = [<string>authorizedRoles];  
66 - }  
67 - return (this.isAuthenticated() && authorizedRoles.indexOf(this.session.currentUser().userRole) !== -1);  
68 - }  
69 -}  
70 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/index.ts
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./auth_controller";  
3 -export * from "./auth_events";  
4 -export * from "./auth_service";  
5 -export * from "./session";  
src/app/components/auth/login.html
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -<div class="modal-header">  
2 - <h3 class="modal-title">{{"auth.title" | translate}}</h3>  
3 -</div>  
4 -<div class="modal-body">  
5 - <form>  
6 - <div class="form-group">  
7 - <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>  
8 - <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="vm.credentials.username">  
9 - </div>  
10 - <div class="form-group">  
11 - <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>  
12 - <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="vm.credentials.password">  
13 - </div>  
14 - <button type="submit" class="btn btn-default" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>  
15 - </form>  
16 -</div>  
src/app/components/auth/session.ts
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -import {UserResponse, INoosferoLocalStorage} from "./../../models/interfaces";  
3 -  
4 -@Injectable()  
5 -@Inject("$localStorage", "$log")  
6 -export class Session {  
7 -  
8 - constructor(private $localStorage: INoosferoLocalStorage, private $log: ng.ILogService) {  
9 -  
10 - }  
11 -  
12 - create(data: UserResponse): noosfero.User {  
13 - this.$localStorage.currentUser = data.user;  
14 - this.$log.debug('User session created.', this.$localStorage.currentUser);  
15 - return this.$localStorage.currentUser;  
16 - };  
17 -  
18 - destroy() {  
19 - delete this.$localStorage.currentUser;  
20 - this.$log.debug('User session destroyed.');  
21 - };  
22 -  
23 - currentUser(): noosfero.User {  
24 - return this.$localStorage.currentUser;  
25 - };  
26 -  
27 -}  
28 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/session_spec.ts
@@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
1 -import {Component} from "ng-forward";  
2 -import {Session} from "./";  
3 -import {fixtures, createComponentFromClass, createProviderToValue} from "./../../../spec/helpers";  
4 -import {UserResponse, INoosferoLocalStorage} from "./../../models/interfaces";  
5 -  
6 -  
7 -describe("Services", () => {  
8 -  
9 -  
10 - describe("Session Service", () => {  
11 -  
12 - let $localStorage: INoosferoLocalStorage = null;  
13 - let $log: any;  
14 -  
15 - beforeEach(() => {  
16 - $localStorage = <INoosferoLocalStorage>{ currentUser: null };  
17 - $log = jasmine.createSpyObj('$log', ['debug']);  
18 - });  
19 -  
20 - it("method 'create()' saves the current user on $localstorage service", () => {  
21 - let session = new Session($localStorage, $log);  
22 - let userResponse = <UserResponse>{  
23 - user: fixtures.user  
24 - };  
25 - session.create(userResponse);  
26 - expect($localStorage.currentUser).toEqual(userResponse.user);  
27 - });  
28 -  
29 - it("method 'destroy()' clean the currentUser on $localstorage", () => {  
30 - let session = new Session($localStorage, $log);  
31 - let userResponse = <UserResponse>{  
32 - user: fixtures.user  
33 - };  
34 - $localStorage.currentUser = fixtures.user;  
35 - session.destroy();  
36 - expect($localStorage.currentUser).toBeUndefined();  
37 - });  
38 -  
39 - it("method 'currentUser()' returns the user recorded on $localstorage service", () => {  
40 - let session = new Session($localStorage, $log);  
41 - let userResponse = <UserResponse>{  
42 - user: fixtures.user  
43 - };  
44 - $localStorage.currentUser = fixtures.user;  
45 - expect(session.currentUser()).toEqual($localStorage.currentUser);  
46 - });  
47 - });  
48 -  
49 -});  
50 \ No newline at end of file 0 \ No newline at end of file
src/app/components/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/language-selector/language-selector.component.ts
@@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
1 -import {Component, Inject} from "ng-forward";  
2 -import {TranslatorService} from "../translator/translator.service";  
3 -  
4 -@Component({  
5 - selector: "language-selector",  
6 - templateUrl: "app/components/language-selector/language-selector.html"  
7 -})  
8 -@Inject(TranslatorService)  
9 -export class LanguageSelector {  
10 -  
11 - constructor(private translatorService: TranslatorService) { }  
12 -  
13 - currentLanguage() {  
14 - return this.translatorService.currentLanguage();  
15 - }  
16 -  
17 - changeLanguage(language: string) {  
18 - this.translatorService.changeLanguage(language);  
19 - }  
20 -  
21 - availableLanguages() {  
22 - return this.translatorService.availableLanguages;  
23 - }  
24 -}  
src/app/components/language-selector/language-selector.html
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -<li class="dropdown profile-menu" dropdown>  
2 - <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>  
3 - <span>{{"language.selector" | translate}}</span> <b class="caret"></b>  
4 - </a>  
5 - <ul class="dropdown-menu" dropdown-menu>  
6 - <li ng-repeat="(language, description) in ctrl.availableLanguages()"  
7 - class="language language-{{language}}" ng-class="{'active': language==ctrl.currentLanguage()}">  
8 - <a href="#" ng-click="ctrl.changeLanguage(language)">  
9 - {{description}}  
10 - </a>  
11 - </li>  
12 - </ul>  
13 -</li>  
src/app/components/navbar/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./navbar";  
src/app/components/navbar/navbar.directive.spec.js
@@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
1 -(function() {  
2 - 'use strict';  
3 -  
4 - describe('directive navbar', function() {  
5 - var vm;  
6 - var el;  
7 - var AUTH_EVENTS;  
8 - var $state;  
9 -  
10 - beforeEach(module('angular'));  
11 - beforeEach(inject(function($compile, $rootScope, $httpBackend, _AUTH_EVENTS_, _$state_) {  
12 - $state = _$state_;  
13 - AUTH_EVENTS = _AUTH_EVENTS_;  
14 - $httpBackend.when('POST','/api/v1/login_from_cookie').respond({});  
15 -  
16 - el = angular.element('<acme-navbar></acme-navbar>');  
17 -  
18 - $compile(el)($rootScope.$new());  
19 - $rootScope.$digest();  
20 - vm = el.isolateScope().vm;  
21 - }));  
22 -  
23 - it('should be compiled', function() {  
24 - expect(el.html()).not.toEqual(null);  
25 - });  
26 -  
27 - it('should have isolate scope object with instanciate members', function() {  
28 - expect(vm).toEqual(jasmine.any(Object));  
29 - expect(vm.currentUser).toEqual(undefined);  
30 - });  
31 -  
32 - it('should reload current state after login', function() {  
33 - spyOn($state, 'go');  
34 - el.isolateScope().$broadcast(AUTH_EVENTS.loginSuccess, {});  
35 - expect($state.go).toHaveBeenCalled();  
36 - });  
37 -  
38 - it('should open login when not logged in', function() {  
39 - spyOn(vm, 'openLogin');  
40 - vm.activate();  
41 - expect(vm.openLogin).toHaveBeenCalled();  
42 - });  
43 -  
44 - });  
45 -})();  
src/app/components/navbar/navbar.html
@@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
1 -<nav class="navbar navbar-static-top navbar-inverse">  
2 - <div class="container-fluid">  
3 - <div class="navbar-header">  
4 - <button type="button" class="navbar-toggle collapsed" ng-click="isCollapsed = !isCollapsed">  
5 - <span class="sr-only">{{"navbar.toggle_menu" | translate}}</span>  
6 - <span class="icon-bar"></span>  
7 - <span class="icon-bar"></span>  
8 - <span class="icon-bar"></span>  
9 - </button>  
10 - <a class="navbar-brand" ui-sref="main">  
11 - <span class="noosfero-logo"><img src="assets/images/logo-noosfero.png"></span> {{"noosfero.name" | translate}}  
12 - </a>  
13 - </div>  
14 -  
15 - <div class="collapse navbar-collapse" id="navbar-collapse" collapse="isCollapsed">  
16 - <ul class="nav navbar-nav">  
17 - </ul>  
18 -  
19 - <ul class="nav navbar-nav navbar-right">  
20 - <li ng-show="!ctrl.currentUser">  
21 - <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>  
22 - </li>  
23 -  
24 - <li class="dropdown profile-menu" ng-show="ctrl.currentUser" dropdown>  
25 - <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>  
26 - <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image>  
27 - <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b>  
28 - </a>  
29 - <ul class="dropdown-menu" dropdown-menu>  
30 - <li>  
31 - <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>  
32 - </li>  
33 - <li>  
34 - <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>  
35 - </li>  
36 - <li class="divider"></li>  
37 - <li>  
38 - <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>  
39 - </li>  
40 - </ul>  
41 - </li>  
42 - </ul>  
43 - <ul class="nav navbar-nav navbar-right">  
44 - <language-selector class="nav navbar-nav navbar-right"></language-selector>  
45 - </ul>  
46 - <div ui-view="actions"></div>  
47 - </div>  
48 - </div>  
49 -</nav>  
src/app/components/navbar/navbar.scss
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -.navbar {  
2 -  
3 - .container-fluid {  
4 - padding-right: 12%;  
5 - padding-left: 12%;  
6 - @media (max-width: 978px) {  
7 - padding-right: 2%;  
8 - padding-left: 2%;  
9 - }  
10 -  
11 - .navbar-brand {  
12 - .noosfero-logo img {  
13 - height: 35px;  
14 - }  
15 - }  
16 -  
17 - .navbar-nav {  
18 - .profile-menu .profile-image {  
19 - img {  
20 - height: 30px;  
21 - width: 30px;  
22 - display: inline-block;  
23 - @extend .img-circle;  
24 - }  
25 - i {  
26 - font-size: 1.7em;  
27 - }  
28 - }  
29 - }  
30 - }  
31 -}  
src/app/components/navbar/navbar.spec.ts
@@ -1,187 +0,0 @@ @@ -1,187 +0,0 @@
1 -import * as helpers from "./../../../spec/helpers";  
2 -import {Navbar} from "./navbar";  
3 -import {AUTH_EVENTS} from "./../auth";  
4 -import {Injectable, Provider, provide} from "ng-forward";  
5 -  
6 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
7 -  
8 -import {Session, AuthService, AuthController, IAuthEvents} from "./../auth";  
9 -  
10 -  
11 -describe("Components", () => {  
12 -  
13 - describe("Navbar Component", () => {  
14 -  
15 - let user: noosfero.User = null;  
16 - let scope: any;  
17 - let $rootScope: ng.IRootScopeService;  
18 -  
19 - let modalInstance: any;  
20 - let $modal: any;  
21 - let authService: any;  
22 - let stateService: any;  
23 - let sessionService: Session;  
24 -  
25 - let provideFunc = provide;  
26 -  
27 - // before Each -> loading mocks on locals variables  
28 - beforeEach(() => {  
29 - user = <noosfero.User>{  
30 - id: 1,  
31 - login: "user"  
32 - };  
33 - scope = helpers.mocks.scopeWithEvents;  
34 - modalInstance = helpers.mocks.modalInstance;  
35 - $modal = helpers.mocks.$modal;  
36 - authService = helpers.mocks.authService;  
37 - stateService = jasmine.createSpyObj("$state", ["go"]);  
38 - sessionService = <any>helpers.mocks.sessionWithCurrentUser(user);  
39 - });  
40 -  
41 -  
42 - // loading the templates  
43 - beforeEach(angular.mock.module("templates"));  
44 -  
45 -  
46 - // this function allow build the fixture of the container component  
47 - // and is reused in each test  
48 - // The main idea behing not prebuild it on a general beforeEach block is  
49 - // to allow tests configure the mock services accordilly their own needs  
50 - let buildComponent = (): Promise<ComponentFixture> => {  
51 - return helpers.quickCreateComponent({  
52 - providers: [  
53 - provide('$modal', {  
54 - useValue: $modal  
55 - }),  
56 - provide('AuthService', {  
57 - useValue: authService  
58 - }),  
59 - helpers.provideEmptyObjects('moment'),  
60 - provide('$state', {  
61 - useValue: stateService  
62 - }),  
63 - provide("$scope", {  
64 - useValue: scope  
65 - }),  
66 - provide('Session', {  
67 - useValue: sessionService  
68 - }),  
69 - provide('AUTH_EVENTS', {  
70 - useValue: {  
71 - AUTH_EVENTS  
72 - }  
73 - }),  
74 - provide('TranslatorService', {  
75 - useValue: helpers.mocks.translatorService  
76 - })  
77 - ].concat(helpers.provideFilters("translateFilter")),  
78 - directives: [Navbar],  
79 - template: '<acme-navbar></acme-navbar>'  
80 - });  
81 - };  
82 -  
83 -  
84 - it('should get the loggedIn user', (done: Function) => {  
85 - buildComponent().then((fixture: ComponentFixture) => {  
86 - let navbarInstance: Navbar = fixture.debugElement.componentViewChildren[0].componentInstance;  
87 - expect(navbarInstance).toBeDefined();  
88 - expect(navbarInstance["currentUser"]).toEqual(user);  
89 - done();  
90 - });  
91 - });  
92 -  
93 - it('should open on click', (done: Function) => {  
94 - spyOn($modal, "open");  
95 - buildComponent().then((fixture: ComponentFixture) => {  
96 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
97 - navbarComp.openLogin();  
98 - expect($modal.open).toHaveBeenCalled();  
99 - expect($modal.open).toHaveBeenCalledWith({  
100 - templateUrl: 'app/components/auth/login.html',  
101 - controller: AuthController,  
102 - controllerAs: 'vm',  
103 - bindToController: true  
104 - });  
105 - done();  
106 - });  
107 - });  
108 -  
109 - it('should logout', (done: Function) => {  
110 - buildComponent().then((fixture: ComponentFixture) => {  
111 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
112 - spyOn(authService, "logout");  
113 - try {  
114 - navbarComp.logout();  
115 - expect(authService.logout).toHaveBeenCalled();  
116 - done();  
117 - } catch (e) {  
118 - console.error(e);  
119 - fail(e.message);  
120 - done();  
121 - }  
122 - });  
123 - });  
124 -  
125 -  
126 - it('should not activate user when logged in', (done: Function) => {  
127 - buildComponent().then((fixture: ComponentFixture) => {  
128 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
129 - spyOn(navbarComp, "openLogin");  
130 - navbarComp.activate();  
131 - expect((<any>navbarComp.openLogin).calls.count()).toBe(0);  
132 - done();  
133 - });  
134 - });  
135 -  
136 - it('should activate when user not logged in', (done: Function) => {  
137 - spyOn(sessionService, 'currentUser').and.returnValue(null);  
138 - buildComponent().then((fixture: ComponentFixture) => {  
139 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
140 - spyOn(navbarComp, "openLogin");  
141 - navbarComp.activate();  
142 - expect(navbarComp.openLogin).toHaveBeenCalled();  
143 - done();  
144 - });  
145 - });  
146 -  
147 -  
148 - it('closes the modal after login', (done: Function) => {  
149 - modalInstance = jasmine.createSpyObj("modalInstance", ["close"]);  
150 - modalInstance.close = jasmine.createSpy("close");  
151 -  
152 - $modal.open = () => {  
153 - return modalInstance;  
154 - };  
155 -  
156 - buildComponent().then((fixture: ComponentFixture) => {  
157 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
158 - let localScope: ng.IScope = navbarComp["$scope"];  
159 -  
160 - navbarComp.openLogin();  
161 - localScope.$emit(AUTH_EVENTS.loginSuccess);  
162 - expect(modalInstance.close).toHaveBeenCalled();  
163 - done();  
164 - });  
165 - });  
166 -  
167 - it('updates current user on logout', (done: Function) => {  
168 - buildComponent().then((fixture: ComponentFixture) => {  
169 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
170 - let localScope: ng.IScope = navbarComp["$scope"];  
171 -  
172 - // init navbar currentUser with some user  
173 - navbarComp["currentUser"] = user;  
174 -  
175 - // changes the current User to return null,  
176 - // and emmit the 'logoutSuccess' event  
177 - // just what happens when user logsout  
178 - sessionService.currentUser = () => { return null; };  
179 - localScope.$emit(AUTH_EVENTS.logoutSuccess);  
180 - expect(navbarComp["currentUser"]).toBeNull();  
181 - done();  
182 - });  
183 - });  
184 -  
185 -  
186 - });  
187 -});  
src/app/components/navbar/navbar.ts
@@ -1,66 +0,0 @@ @@ -1,66 +0,0 @@
1 -import {Component, Inject} from "ng-forward";  
2 -import {LanguageSelector} from "../language-selector/language-selector.component";  
3 -  
4 -  
5 -import {Session, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../auth";  
6 -  
7 -@Component({  
8 - selector: "acme-navbar",  
9 - templateUrl: "app/components/navbar/navbar.html",  
10 - directives: [LanguageSelector],  
11 - providers: [AuthService, Session]  
12 -})  
13 -@Inject("$modal", AuthService, "Session", "$scope", "$state")  
14 -export class Navbar {  
15 -  
16 - private currentUser: noosfero.User;  
17 - private modalInstance: any = null;  
18 - /**  
19 - *  
20 - */  
21 - constructor(  
22 - private $modal: any,  
23 - private authService: AuthService,  
24 - private session: Session,  
25 - private $scope: ng.IScope,  
26 - private $state: ng.ui.IStateService  
27 - ) {  
28 - this.currentUser = this.session.currentUser();  
29 -  
30 - this.$scope.$on(AUTH_EVENTS.loginSuccess, () => {  
31 - if (this.modalInstance) {  
32 - this.modalInstance.close();  
33 - this.modalInstance = null;  
34 - }  
35 -  
36 - this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth  
37 - });  
38 -  
39 - this.$scope.$on(AUTH_EVENTS.logoutSuccess, () => {  
40 - this.currentUser = this.session.currentUser();  
41 - });  
42 - }  
43 -  
44 - openLogin() {  
45 - this.modalInstance = this.$modal.open({  
46 - templateUrl: 'app/components/auth/login.html',  
47 - controller: AuthController,  
48 - controllerAs: 'vm',  
49 - bindToController: true  
50 - });  
51 - };  
52 -  
53 - logout() {  
54 - this.authService.logout();  
55 - this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth  
56 - };  
57 -  
58 -  
59 -  
60 - activate() {  
61 - if (!this.currentUser) {  
62 - this.openLogin();  
63 - }  
64 - }  
65 -  
66 -}  
src/app/components/noosfero-activities/activities.component.spec.ts
@@ -1,36 +0,0 @@ @@ -1,36 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../spec/helpers';  
4 -  
5 -import {NoosferoActivities} from './activities.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-activities [activities]="ctrl.activities"></noosfero-activities>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Noosfero Activities", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [NoosferoActivities],  
22 - providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - activities = [{ name: "activity1", verb: "create_article" }, { name: "activity2", verb: "create_article" }];  
26 - }  
27 -  
28 - it("render a noosfero activity tag for each activity", done => {  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - expect(fixture.debugElement.queryAll("noosfero-activity").length).toEqual(2);  
31 - done();  
32 - });  
33 - });  
34 - });  
35 -  
36 -});  
src/app/components/noosfero-activities/activities.component.ts
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -import {NoosferoActivity} from "./activity/activity.component";  
3 -  
4 -/**  
5 - * @ngdoc controller  
6 - * @name NoosferoActivities  
7 - * @description  
8 - * The controller responsible to retreive profile activities.  
9 - */  
10 -  
11 -@Component({  
12 - selector: "noosfero-activities",  
13 - templateUrl: 'app/components/noosfero-activities/activities.html',  
14 - directives: [NoosferoActivity]  
15 -})  
16 -export class NoosferoActivities {  
17 -  
18 - /**  
19 - * @ngdoc property  
20 - * @propertyOf NoosferoActivities  
21 - * @name activities  
22 - * @returns {Activity[]} An array of {@link Activity}.  
23 - */  
24 - @Input() activities: noosfero.Activity[];  
25 -  
26 -  
27 -}  
src/app/components/noosfero-activities/activities.html
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<timeline>  
2 - <timeline-event ng-repeat="activity in ctrl.activities | orderBy: 'created_at':true">  
3 - <noosfero-activity [activity]="activity"></noosfero-activity>  
4 - </timeline-event>  
5 -</timeline>  
src/app/components/noosfero-activities/activities.scss
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -.comma-separated {  
2 - .separated-item {  
3 - &:after {  
4 - content: ", ";  
5 - margin-left: -3px;  
6 - }  
7 - &:last-child:after {  
8 - content: "";  
9 - }  
10 - }  
11 -}  
src/app/components/noosfero-activities/activity/activity.component.spec.ts
@@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -  
5 -import {NoosferoActivity} from './activity.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-activity [activity]="ctrl.activity"></noosfero-activity>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Noosfero Activity", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [NoosferoActivity],  
22 - providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - activity = { name: "activity1", verb: "create_article" };  
26 - }  
27 -  
28 - it("render the specific template for an activity verb", done => {  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - let component: NoosferoActivity = fixture.debugElement.componentViewChildren[0].componentInstance;  
31 - expect(component.getActivityTemplate()).toEqual('app/components/noosfero-activities/activity/create_article.html');  
32 - expect(fixture.debugElement.queryAll(".activity.create_article").length).toEqual(1);  
33 - done();  
34 - });  
35 - });  
36 - });  
37 -  
38 -});  
src/app/components/noosfero-activities/activity/activity.component.ts
@@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -  
3 -@Component({  
4 - selector: "noosfero-activity",  
5 - templateUrl: 'app/components/noosfero-activities/activity/activity.html'  
6 -})  
7 -export class NoosferoActivity {  
8 -  
9 - @Input() activity: noosfero.Activity;  
10 -  
11 - getActivityTemplate() {  
12 - return 'app/components/noosfero-activities/activity/' + this.activity.verb + '.html';  
13 - }  
14 -  
15 -}  
src/app/components/noosfero-activities/activity/activity.html
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -<div class="activity {{ctrl.activity.verb}}">  
2 - <ng-include src="ctrl.getActivityTemplate()"></ng-include>  
3 -</div>  
src/app/components/noosfero-activities/activity/add_member_in_community.html
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -<timeline-badge class="info">  
2 - <i class="fa fa-user-plus"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
6 - <h4 class="timeline-title">  
7 - <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>  
8 - <span> {{"activities.add_member_in_community.description" | translate}}</span>  
9 - </h4>  
10 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
11 - </timeline-heading>  
12 - <div class="timeline-body"></div>  
13 -</timeline-panel>  
src/app/components/noosfero-activities/activity/create_article.html
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -<timeline-badge class="success">  
2 - <i class="fa fa-file-text"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
6 - <h4 class="timeline-title">  
7 - <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>  
8 - <span> {{"activities.create_article.description" | translate}} </span>  
9 - <a ui-sref="main.profile.info({profile: ctrl.activity.target.article.profile.identifier})">  
10 - <strong ng-bind="ctrl.activity.target.article.profile.name"></strong></span>  
11 - </a>  
12 - </h4>  
13 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
14 - </timeline-heading>  
15 - <div class="timeline-body">  
16 - <div class="article">  
17 - <div class="title">  
18 - <a ui-sref="main.profile.page({profile: ctrl.activity.target.article.profile.identifier, page: ctrl.activity.target.article.path})"  
19 - ng-bind="ctrl.activity.target.article.title"></a>  
20 - </div>  
21 - <div class="lead small">  
22 - <div ng-bind-html="ctrl.activity.target.article.body | stripTags | truncate: 100 : '...': true"></div>  
23 - </div>  
24 - </div>  
25 - </div>  
26 -</timeline-panel>  
src/app/components/noosfero-activities/activity/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-activities/activity/new_friendship.html
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -<timeline-badge class="info">  
2 - <i class="fa fa-user-plus"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
6 - <h4 class="timeline-title">  
7 - <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>  
8 - <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length}:"messageformat" }} </span>  
9 - <span class="comma-separated">  
10 - <a class="separated-item" ui-sref="main.profile.info({profile: ctrl.activity.params.friend_url[$index].profile})" ng-repeat="friend in ctrl.activity.params.friend_name">  
11 - <strong ng-bind="friend"></strong>  
12 - </a>  
13 - </span>  
14 - </h4>  
15 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
16 - </timeline-heading>  
17 - <div class="timeline-body"></div>  
18 -</timeline-panel>  
src/app/components/noosfero-activities/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-articles/article/article.html
@@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
1 -<div class="article">  
2 - <div class="page-header">  
3 - <h3 ng-bind="ctrl.article.title"></h3>  
4 - </div>  
5 -  
6 - <div class="sub-header clearfix">  
7 - <div class="page-info pull-right small text-muted">  
8 - <span class="time">  
9 - <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span>  
10 - </span>  
11 - <span class="author" ng-if="ctrl.article.author">  
12 - <i class="fa fa-user"></i>  
13 - <a ui-sref="main.profile.home({profile: ctrl.article.author.identifier})">  
14 - <span class="author-name" ng-bind="ctrl.article.author.name"></span>  
15 - </a>  
16 - </span>  
17 - </div>  
18 - </div>  
19 -  
20 - <div class="page-body">  
21 - <div ng-bind-html="ctrl.article.body"></div>  
22 - </div>  
23 -</div>  
src/app/components/noosfero-articles/article/article.scss
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -.article {  
2 - .page-info {  
3 - .author {  
4 - a {  
5 - color: #b4bcc2;  
6 - }  
7 - }  
8 - }  
9 -  
10 - .page-header {  
11 - margin-bottom: 5px;  
12 - }  
13 -  
14 - .sub-header {  
15 - margin-bottom: 20px;  
16 - }  
17 -}  
src/app/components/noosfero-articles/article/article_view.spec.ts
@@ -1,108 +0,0 @@ @@ -1,108 +0,0 @@
1 -  
2 -import {Input, provide, Component} from 'ng-forward';  
3 -import {ArticleView, ArticleDefaultView} from './article_view';  
4 -  
5 -import {createComponentFromClass, quickCreateComponent} from "../../../../spec/helpers";  
6 -  
7 -// this htmlTemplate will be re-used between the container components in this spec file  
8 -const htmlTemplate: string = '<noosfero-article [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-article>';  
9 -  
10 -  
11 -describe("Components", () => {  
12 -  
13 - describe("ArticleView Component", () => {  
14 -  
15 - // the karma preprocessor html2js transform the templates html into js files which put  
16 - // the templates to the templateCache into the module templates  
17 - // we need to load the module templates here as the template for the  
18 - // component Noosfero ArtileView will be load on our tests  
19 - beforeEach(angular.mock.module("templates"));  
20 -  
21 - it("renders the default component when no specific component is found", (done: Function) => {  
22 - // Creating a container component (ArticleContainerComponent) to include  
23 - // the component under test (ArticleView)  
24 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView] })  
25 - class ArticleContainerComponent {  
26 - article = { type: 'anyArticleType' };  
27 - profile = { name: 'profile-name' };  
28 - constructor() {  
29 - }  
30 - }  
31 -  
32 - createComponentFromClass(ArticleContainerComponent).then((fixture) => {  
33 - // and here we can inspect and run the test assertions  
34 -  
35 - // gets the children component of ArticleContainerComponent  
36 - let articleView: ArticleView = fixture.debugElement.componentViewChildren[0].componentInstance;  
37 -  
38 - // and checks if the article View rendered was the Default Article View  
39 - expect(articleView.constructor.prototype).toEqual(ArticleDefaultView.prototype);  
40 -  
41 - // done needs to be called (it isn't really needed, as we can read in  
42 - // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)  
43 - // because createAsync in ng-forward is not really async, but as the intention  
44 - // here is write tests in angular 2 ways, this is recommended  
45 - done();  
46 - });  
47 -  
48 - });  
49 -  
50 - it("receives the article and profile as inputs", (done: Function) => {  
51 -  
52 - // Creating a container component (ArticleContainerComponent) to include  
53 - // the component under test (ArticleView)  
54 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView] })  
55 - class ArticleContainerComponent {  
56 - article = { type: 'anyArticleType' };  
57 - profile = { name: 'profile-name' };  
58 - constructor() {  
59 - }  
60 - }  
61 -  
62 - // uses the TestComponentBuilder instance to initialize the component  
63 - createComponentFromClass(ArticleContainerComponent).then((fixture) => {  
64 - // and here we can inspect and run the test assertions  
65 - let articleView: ArticleView = fixture.debugElement.componentViewChildren[0].componentInstance;  
66 -  
67 - // assure the article object inside the ArticleView matches  
68 - // the provided through the parent component  
69 - expect(articleView.article.type).toEqual("anyArticleType");  
70 - expect(articleView.profile.name).toEqual("profile-name");  
71 -  
72 - // done needs to be called (it isn't really needed, as we can read in  
73 - // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)  
74 - // because createAsync in ng-forward is not really async, but as the intention  
75 - // here is write tests in angular 2 ways, this is recommended  
76 - done();  
77 - });  
78 - });  
79 -  
80 -  
81 - it("renders a article view which matches to the article type", done => {  
82 - // NoosferoTinyMceArticle component created to check if it will be used  
83 - // when a article with type 'TinyMceArticle' is provided to the noosfero-article (ArticleView)  
84 - // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider  
85 - @Component({ selector: 'noosfero-tiny-mce-article', template: "<h1>TinyMceArticle</h1>" })  
86 - class TinyMceArticleView {  
87 - @Input() article: any;  
88 - @Input() profile: any;  
89 - }  
90 -  
91 - // Creating a container component (ArticleContainerComponent) to include our NoosferoTinyMceArticle  
92 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView, TinyMceArticleView] })  
93 - class CustomArticleType {  
94 - article = { type: 'TinyMceArticle' };  
95 - profile = { name: 'profile-name' };  
96 - constructor() {  
97 - }  
98 - }  
99 - createComponentFromClass(CustomArticleType).then(fixture => {  
100 - let myComponent: CustomArticleType = fixture.componentInstance;  
101 - expect(myComponent.article.type).toEqual("TinyMceArticle");  
102 - expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("TinyMceArticle");  
103 - done();  
104 - });  
105 - });  
106 -  
107 - });  
108 -});  
109 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-articles/article/article_view.ts
@@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
1 -import { bundle, Input, Inject, Component, Directive } from 'ng-forward';  
2 -import {ArticleBlog} from "../blog/blog.component";  
3 -  
4 -/**  
5 - * @ngdoc controller  
6 - * @name ArticleDefaultView  
7 - * @description  
8 - * A default view for Noosfero Articles. If the specific article view is  
9 - * not implemented, then this view is used.  
10 - */  
11 -@Component({  
12 - selector: 'noosfero-default-article',  
13 - templateUrl: 'app/components/noosfero-articles/article/article.html'  
14 -})  
15 -export class ArticleDefaultView {  
16 -  
17 - @Input() article: noosfero.Article;  
18 - @Input() profile: noosfero.Profile;  
19 -  
20 -}  
21 -  
22 -/**  
23 - * @ngdoc controller  
24 - * @name ArticleView  
25 - * @description  
26 - * A dynamic view for articles. It uses the article type to replace  
27 - * the default template with the custom article directive.  
28 - */  
29 -@Component({  
30 - selector: 'noosfero-article',  
31 - template: 'not-used',  
32 - directives: [ArticleDefaultView, ArticleBlog]  
33 -})  
34 -@Inject("$element", "$scope", "$injector", "$compile")  
35 -export class ArticleView {  
36 -  
37 - @Input() article: noosfero.Article;  
38 - @Input() profile: noosfero.Profile;  
39 - directiveName: string;  
40 -  
41 - ngOnInit() {  
42 - let specificDirective = 'noosfero' + this.article.type;  
43 - this.directiveName = "noosfero-default-article";  
44 - if (this.$injector.has(specificDirective + 'Directive')) {  
45 - this.directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();  
46 - }  
47 - this.$element.replaceWith(this.$compile('<' + this.directiveName + ' [article]="ctrl.article" [profile]="ctrl.profile"></' + this.directiveName + '>')(this.$scope));  
48 - }  
49 -  
50 - constructor(  
51 - private $element: any,  
52 - private $scope: ng.IScope,  
53 - private $injector: ng.auto.IInjectorService,  
54 - private $compile: ng.ICompileService) {  
55 -  
56 - }  
57 -}  
src/app/components/noosfero-articles/article/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./article_view";  
src/app/components/noosfero-articles/blog/blog.component.spec.ts
@@ -1,129 +0,0 @@ @@ -1,129 +0,0 @@
1 -import {  
2 -providers  
3 -} from 'ng-forward/cjs/testing/providers';  
4 -  
5 -import {  
6 -Input,  
7 -Component  
8 -} from 'ng-forward';  
9 -import {  
10 -ArticleBlog  
11 -} from './blog.component';  
12 -  
13 -import {  
14 -createComponentFromClass,  
15 -quickCreateComponent,  
16 -provideEmptyObjects,  
17 -createProviderToValue,  
18 -provideFilters  
19 -} from "../../../../spec/helpers.ts";  
20 -  
21 -// this htmlTemplate will be re-used between the container components in this spec file  
22 -const htmlTemplate: string = '<noosfero-blog [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-blog>';  
23 -  
24 -describe("Blog Component", () => {  
25 -  
26 - function promiseResultTemplate(response?: {}) {  
27 - let thenFuncEmpty = (func: Function) => {  
28 - // does nothing  
29 - };  
30 - if (response) {  
31 - return {  
32 - then: (func: (response: any) => void) => {  
33 - func(response);  
34 - }  
35 - };  
36 - } else {  
37 - return {  
38 - then: (func: (response: any) => void) => {  
39 - // does nothing  
40 - }  
41 - };  
42 - }  
43 - }  
44 -  
45 - let articleService = {  
46 - getChildren: (article_id: number, filters: {}) => {  
47 - return promiseResultTemplate(null);  
48 - }  
49 - };  
50 -  
51 - @Component({  
52 - selector: 'test-container-component',  
53 - template: htmlTemplate,  
54 - directives: [ArticleBlog],  
55 - providers: [  
56 - provideEmptyObjects('Restangular'),  
57 - createProviderToValue('ArticleService', articleService),  
58 - provideFilters('truncateFilter')  
59 - ]  
60 - })  
61 - class BlogContainerComponent {  
62 - article = {  
63 - type: 'anyArticleType'  
64 - };  
65 - profile = {  
66 - name: 'profile-name'  
67 - };  
68 - }  
69 -  
70 - beforeEach(() => {  
71 -  
72 - // the karma preprocessor html2js transform the templates html into js files which put  
73 - // the templates to the templateCache into the module templates  
74 - // we need to load the module templates here as the template for the  
75 - // component Noosfero ArtileView will be load on our tests  
76 - angular.mock.module("templates");  
77 -  
78 - providers((provide: any) => {  
79 - return <any>[  
80 - provide('ArticleService', {  
81 - useValue: articleService  
82 - })  
83 - ];  
84 - });  
85 - });  
86 -  
87 - it("renders the blog content", (done: Function) => {  
88 -  
89 - createComponentFromClass(BlogContainerComponent).then((fixture) => {  
90 -  
91 - expect(fixture.debugElement.query('div.blog').length).toEqual(1);  
92 -  
93 - done();  
94 - });  
95 - });  
96 -  
97 - it("verify the blog data", (done: Function) => {  
98 -  
99 - let articles = [{  
100 - id: 1,  
101 - title: 'The article test'  
102 - }];  
103 -  
104 - let result = { data: articles, headers: (name: string) => { return 1; } };  
105 -  
106 - // defining a mock result to articleService.getChildren method  
107 - articleService.getChildren = (article_id: number, filters: {}) => {  
108 - return promiseResultTemplate(result);  
109 - };  
110 -  
111 - createComponentFromClass(BlogContainerComponent).then((fixture) => {  
112 -  
113 - // gets the children component of BlogContainerComponent  
114 - let articleBlog: BlogContainerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;  
115 -  
116 - // check if the component property are the provided by the mocked articleService  
117 - let post = {  
118 - id: 1,  
119 - title: 'The article test'  
120 - };  
121 - expect((<any>articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post));  
122 - expect((<any>articleBlog)["totalPosts"]).toEqual(1);  
123 -  
124 - done();  
125 - });  
126 -  
127 - });  
128 -  
129 -});  
130 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-articles/blog/blog.component.ts
@@ -1,47 +0,0 @@ @@ -1,47 +0,0 @@
1 -import {Component, Input, Inject} from "ng-forward";  
2 -  
3 -import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";  
4 -  
5 -/**  
6 - * @ngdoc controller  
7 - * @name ArticleBlog  
8 - * @description  
9 - * An specific {@link ArticleView} for Blog articles.  
10 - */  
11 -@Component({  
12 - selector: "noosfero-blog",  
13 - templateUrl: "app/components/noosfero-articles/blog/blog.html"  
14 -})  
15 -@Inject(ArticleService)  
16 -export class ArticleBlog {  
17 -  
18 - @Input() article: noosfero.Article;  
19 - @Input() profile: noosfero.Profile;  
20 -  
21 - private posts: noosfero.Article[];  
22 - private perPage: number = 3;  
23 - private currentPage: number;  
24 - private totalPosts: number = 0;  
25 -  
26 - constructor(private articleService: ArticleService) { }  
27 -  
28 - ngOnInit() {  
29 - this.loadPage();  
30 - }  
31 -  
32 - loadPage() {  
33 - let filters = {  
34 - content_type: "TinyMceArticle",  
35 - per_page: this.perPage,  
36 - page: this.currentPage  
37 - };  
38 -  
39 - this.articleService  
40 - .getChildren(this.article, filters)  
41 - .then((result: noosfero.RestResult<noosfero.Article[]>) => {  
42 - this.totalPosts = <number>result.headers("total");  
43 - this.posts = result.data;  
44 - });  
45 - }  
46 -  
47 -}  
src/app/components/noosfero-articles/blog/blog.html
@@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
1 -<div class="blog">  
2 - <div class="blog-cover" ng-show="ctrl.article.image">  
3 - <img ng-src="{{ctrl.article.image.url}}" class="img-responsive">  
4 - <h3 ng-bind="ctrl.article.title"></h3>  
5 - </div>  
6 -  
7 - <div class="page-header" ng-show="!ctrl.article.image">  
8 - <h3 ng-bind="ctrl.article.title"></h3>  
9 - </div>  
10 -  
11 - <div>  
12 - <div ng-repeat="child in ctrl.posts | orderBy: 'created_at':true">  
13 - <div class="page-header">  
14 - <a class="title" ui-sref="main.profile.page({profile: ctrl.profile.identifier, page: child.path})"><h4 ng-bind="child.title"></h4></a>  
15 - <div class="post-lead" ng-bind-html="child.body | truncate: 500: '...': true"></div>  
16 - </div>  
17 - </div>  
18 - </div>  
19 -  
20 - <pagination ng-model="ctrl.currentPage" total-items="ctrl.totalPosts" class="pagination-sm center-block"  
21 - boundary-links="true" items-per-page="ctrl.perPage" ng-change="ctrl.loadPage()"  
22 - first-text="«" last-text="»" previous-text="‹" next-text="›">  
23 - </pagination>  
24 -</div>  
src/app/components/noosfero-articles/blog/blog.scss
@@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
1 -.blog {  
2 - .blog-cover {  
3 - margin: -15px;  
4 - position: relative;  
5 - h3 {  
6 - position: absolute;  
7 - bottom: 0;  
8 - background-color: rgba(0, 0, 0, 0.4);  
9 - color: white;  
10 - padding: 10px 15px;  
11 - margin: 0;  
12 - width: 100%;  
13 - }  
14 - }  
15 -}  
src/app/components/noosfero-articles/blog/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./blog.component";  
src/app/components/noosfero-articles/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/block.component.spec.ts
@@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {Block} from './block.component';  
5 -  
6 -const tcb = new TestComponentBuilder();  
7 -  
8 -const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-block>';  
9 -  
10 -describe("Components", () => {  
11 - describe("Block Component", () => {  
12 -  
13 - // the karma preprocessor html2js transform the templates html into js files which put  
14 - // the templates to the templateCache into the module templates  
15 - // we need to load the module templates here as the template for the  
16 - // component Block will be load on our tests  
17 - beforeEach(angular.mock.module("templates"));  
18 -  
19 - it("receives the block and the owner as inputs", done => {  
20 -  
21 - // Creating a container component (BlockContainerComponent) to include  
22 - // the component under test (Block)  
23 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block] })  
24 - class BlockContainerComponent {  
25 - block = { type: 'Block' };  
26 - owner = { name: 'profile-name' };  
27 - constructor() {  
28 - }  
29 - }  
30 -  
31 - // uses the TestComponentBuilder instance to initialize the component  
32 - tcb  
33 - .createAsync(BlockContainerComponent).then(fixture => {  
34 - // and here we can inspect and run the test assertions  
35 - let myComponent: Block = fixture.componentInstance;  
36 -  
37 - // assure the block object inside the Block matches  
38 - // the provided through the parent component  
39 - expect(myComponent.block.type).toEqual("Block");  
40 - expect(myComponent.owner.name).toEqual("profile-name");  
41 - done();  
42 - });  
43 - });  
44 -  
45 -  
46 - it("renders a component which matches to the block type", done => {  
47 - // CustomBlock component created to check if it will be used  
48 - // when a block with type 'CustomBlock' is provided to the noosfero-block (Block)  
49 - // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider  
50 - @Component({ selector: 'noosfero-custom-block', template: "<h1>My Custom Block</h1>" })  
51 - class CustomBlock {  
52 - @Input() block: any;  
53 - @Input() owner: any;  
54 - }  
55 -  
56 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block, CustomBlock] })  
57 - class CustomBlockType {  
58 - block = { type: 'CustomBlock' };  
59 - owner = { name: 'profile-name' };  
60 - constructor() {  
61 - }  
62 - }  
63 - tcb  
64 - .createAsync(CustomBlockType).then(fixture => {  
65 - let myComponent: CustomBlockType = fixture.componentInstance;  
66 - expect(myComponent.block.type).toEqual("CustomBlock");  
67 - expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("My Custom Block");  
68 - done();  
69 - });  
70 - });  
71 -  
72 -  
73 - it("renders the default block when hasn't defined a block type", done => {  
74 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block] })  
75 - class CustomBlockType {  
76 - block: any = { type: null };  
77 - owner: any = { name: 'profile-name' };  
78 - constructor() {  
79 - }  
80 - }  
81 - tcb  
82 - .createAsync(CustomBlockType).then(fixture => {  
83 - let myComponent: CustomBlockType = fixture.componentInstance;  
84 - expect(myComponent.block.type).toBeNull();  
85 - expect(!!fixture.debugElement.nativeElement.querySelector("noosfero-default-block")).toBeTruthy();  
86 - done();  
87 - });  
88 - });  
89 -  
90 - });  
91 -});  
92 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/block.component.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import { Input, Inject, Component } from 'ng-forward';  
2 -  
3 -@Component({  
4 - selector: 'noosfero-block',  
5 - template: '<div></div>'  
6 -})  
7 -@Inject("$element", "$scope", "$injector", "$compile")  
8 -export class Block {  
9 -  
10 - @Input() block: any;  
11 - @Input() owner: any;  
12 -  
13 - ngOnInit() {  
14 - let blockName = (this.block && this.block.type) ? this.block.type.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : "default-block";  
15 - this.$element.replaceWith(this.$compile('<noosfero-' + blockName + ' [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-' + blockName + '>')(this.$scope));  
16 - }  
17 -  
18 - constructor(private $element: any, private $scope: ng.IScope, private $injector: ng.auto.IInjectorService, private $compile: ng.ICompileService) {  
19 - }  
20 -}  
src/app/components/noosfero-blocks/block.scss
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -.block {  
2 - .panel-title {  
3 - font-size: 15px;  
4 - font-weight: bold;  
5 - }  
6 - .panel-heading {  
7 - background-color: transparent;  
8 - border: 0;  
9 - }  
10 -}  
src/app/components/noosfero-blocks/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./block.component";  
src/app/components/noosfero-blocks/link-list/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./link-list.component";  
src/app/components/noosfero-blocks/link-list/link-list.component.spec.ts
@@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -  
5 -import {LinkListBlock} from './link-list.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-link-list-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-link-list-block>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Link List Block Component", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - it("receives the block and the owner as inputs", done => {  
19 -  
20 - // Creating a container component (BlockContainerComponent) to include  
21 - // the component under test (Block)  
22 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [LinkListBlock] })  
23 - class BlockContainerComponent {  
24 - block = { type: 'Block' };  
25 - owner = { name: 'profile-name' };  
26 - constructor() {  
27 - }  
28 - }  
29 -  
30 - // uses the TestComponentBuilder instance to initialize the component  
31 - // .overrideView(LinkListBlock, { template: 'asdasdasd', pipes: [NoosferoTemplate] })  
32 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
33 - // and here we can inspect and run the test assertions  
34 - let myComponent: LinkListBlock = fixture.componentInstance;  
35 -  
36 - // assure the block object inside the Block matches  
37 - // the provided through the parent component  
38 - expect(myComponent.block.type).toEqual("Block");  
39 - expect(myComponent.owner.name).toEqual("profile-name");  
40 - done();  
41 - });  
42 - });  
43 -  
44 -  
45 - it("display links stored in block settings", done => {  
46 -  
47 - @Component({  
48 - selector: 'test-container-component',  
49 - template: htmlTemplate,  
50 - directives: [LinkListBlock],  
51 - providers: provideFilters("noosferoTemplateFilter")  
52 - })  
53 - class CustomBlockType {  
54 - block: any = { settings: { links: [{ name: 'link1', address: 'address1' }, { name: 'link2', address: 'address2' }] } };  
55 - owner: any = { name: 'profile-name' };  
56 - }  
57 - tcb.createAsync(CustomBlockType).then(fixture => {  
58 - expect(fixture.debugElement.queryAll(".link-list-block a").length).toEqual(2);  
59 - done();  
60 - });  
61 - });  
62 -  
63 - });  
64 -  
65 -});  
66 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/link-list/link-list.component.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -  
3 -@Component({  
4 - selector: "noosfero-link-list-block",  
5 - templateUrl: "app/components/noosfero-blocks/link-list/link-list.html"  
6 -})  
7 -export class LinkListBlock {  
8 -  
9 - @Input() block: any;  
10 - @Input() owner: any;  
11 -  
12 - links: any;  
13 -  
14 - ngOnInit() {  
15 - if (this.block && this.block.settings) {  
16 - this.links = this.block.settings.links;  
17 - }  
18 - }  
19 -  
20 -}  
src/app/components/noosfero-blocks/link-list/link-list.html
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -<div class="link-list-block">  
2 - <div ng-repeat="link in ctrl.links">  
3 - <a ng-href="{{link.address | noosferoTemplate:{profile: ctrl.owner.identifier} }}">  
4 - <i class="fa fa-fw icon-{{link.icon}}"></i> <span>{{link.name}}</span>  
5 - </a>  
6 - </div>  
7 -</div>  
src/app/components/noosfero-blocks/link-list/link-list.scss
@@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
1 -.icon-event {  
2 - @extend .fa-calendar;  
3 -}  
4 -.icon-photos {  
5 - @extend .fa-photo;  
6 -}  
7 -.icon-edit {  
8 - @extend .fa-edit;  
9 -}  
10 -.icon-ok {  
11 - @extend .fa-check;  
12 -}  
13 -.icon-send {  
14 - @extend .fa-send-o;  
15 -}  
16 -.icon-menu-people {  
17 - @extend .fa-user;  
18 -}  
19 -.icon-forum {  
20 - @extend .fa-users;  
21 -}  
22 -.icon-new {  
23 - @extend .fa-file-o;  
24 -}  
25 -.icon-save {  
26 - @extend .fa-save;  
27 -}  
28 -  
29 -.link-list-block {  
30 - a i {  
31 - line-height: 25px;  
32 - color: #949494;  
33 - }  
34 -}  
src/app/components/noosfero-blocks/main-block/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/main-block/main-block.component.spec.ts
@@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Input, provide, Component, StateConfig} from 'ng-forward';  
3 -  
4 -import {MainBlock} from './main-block.component';  
5 -import {NoosferoApp} from '../../../index.module';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-main-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-main-block>';  
10 -  
11 -describe("Components", () => {  
12 - describe("Main Block Component", () => {  
13 -  
14 - // the karma preprocessor html2js transform the templates html into js files which put  
15 - // the templates to the templateCache into the module templates  
16 - // we need to load the module templates here as the template for the  
17 - // component Block will be load on our tests  
18 - beforeEach(angular.mock.module("templates"));  
19 -  
20 - it("check if the main block has a tag with ui-view attribute", done => {  
21 -  
22 - // Creating a container component (BlockContainerComponent) to include  
23 - // the component under test (Block)  
24 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MainBlock] })  
25 - class BlockContainerComponent {  
26 - }  
27 -  
28 - // uses the TestComponentBuilder instance to initialize the component  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - // and here we can inspect and run the test assertions  
31 - // let myComponent: MainBlock = fixture.componentInstance;  
32 -  
33 - // assure the block object inside the Block matches  
34 - // the provided through the parent component  
35 - expect(fixture.debugElement.queryAll('[ui-view="mainBlockContent"]').length).toEqual(1);  
36 - done();  
37 - });  
38 - });  
39 - });  
40 -});  
41 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/main-block/main-block.component.ts
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -import {Component, Input} from 'ng-forward';  
2 -import {Block} from '../block.component';  
3 -  
4 -@Component({  
5 - selector: 'noosfero-main-block',  
6 - templateUrl: 'app/components/noosfero-blocks/main-block/main-block.html'  
7 -})  
8 -export class MainBlock {  
9 -  
10 -}  
src/app/components/noosfero-blocks/main-block/main-block.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<div ui-view="mainBlockContent" autoscroll></div>  
src/app/components/noosfero-blocks/members-block/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/members-block/members-block.component.spec.ts
@@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Provider, Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {MembersBlock} from './members-block.component';  
5 -  
6 -const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>';  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -describe("Components", () => {  
11 - describe("Members Block Component", () => {  
12 -  
13 - beforeEach(angular.mock.module("templates"));  
14 -  
15 - let state = jasmine.createSpyObj("state", ["go"]);  
16 - let providers = [  
17 - new Provider('truncateFilter', { useValue: () => { } }),  
18 - new Provider('stripTagsFilter', { useValue: () => { } }),  
19 - new Provider('$state', { useValue: state }),  
20 - new Provider('ProfileService', {  
21 - useValue: {  
22 - getProfileMembers: (profileId: number, filters: any): any => {  
23 - return Promise.resolve({ data: { people: [{ identifier: "person1" }] } });  
24 - }  
25 - }  
26 - }),  
27 - ];  
28 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MembersBlock], providers: providers })  
29 - class BlockContainerComponent {  
30 - block = { type: 'Block', settings: {} };  
31 - owner = { name: 'profile-name' };  
32 - constructor() {  
33 - }  
34 - }  
35 -  
36 - it("get members of the block owner", done => {  
37 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
38 - let block: MembersBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
39 - expect(block.members).toEqual([{ identifier: "person1" }]);  
40 - done();  
41 - });  
42 - });  
43 -  
44 - it("render the profile image for each member", done => {  
45 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
46 - fixture.debugElement.getLocal("$rootScope").$apply();  
47 - expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);  
48 - done();  
49 - });  
50 - });  
51 -  
52 - });  
53 -});  
54 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/members-block/members-block.component.ts
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -import {Input, Inject, Component} from "ng-forward";  
2 -import {ProfileService} from "../../../../lib/ng-noosfero-api/http/profile.service";  
3 -  
4 -@Component({  
5 - selector: "noosfero-members-block",  
6 - templateUrl: 'app/components/noosfero-blocks/members-block/members-block.html',  
7 -})  
8 -@Inject(ProfileService)  
9 -export class MembersBlock {  
10 -  
11 - @Input() block: noosfero.Block;  
12 - @Input() owner: noosfero.Profile;  
13 -  
14 - members: any = [];  
15 -  
16 - constructor(private profileService: ProfileService) {  
17 -  
18 - }  
19 -  
20 - ngOnInit() {  
21 - this.profileService.getProfileMembers(this.owner.id, { per_page: 6 }).then((response: any) => {  
22 - this.members = response.data.people;  
23 - });  
24 - }  
25 -}  
src/app/components/noosfero-blocks/members-block/members-block.html
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<div class="members-block">  
2 - <a ng-repeat="member in ctrl.members" ui-sref="main.profile.home({profile: member.identifier})" class="member">  
3 - <noosfero-profile-image [profile]="member"></noosfero-profile-image>  
4 - </a>  
5 -</div>  
src/app/components/noosfero-blocks/members-block/members-block.scss
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -.members-block {  
2 - .member {  
3 - img, i.profile-image {  
4 - width: 60px;  
5 - }  
6 - img {  
7 - display: inline-block;  
8 - vertical-align: top;  
9 - }  
10 - i.profile-image {  
11 - text-align: center;  
12 - background-color: #889DB1;  
13 - color: #F1F1F1;  
14 - font-size: 4.5em;  
15 - }  
16 - }  
17 -}  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.component.spec.ts
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {ProfileImageBlock} from './profile-image-block.component';  
5 -  
6 -import * as helpers from "./../../../../spec/helpers";  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -const htmlTemplate: string = '<noosfero-profile-image-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-profile-image-block>';  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Profile Image Block Component", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [ProfileImageBlock],  
22 - providers: helpers.provideFilters("translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - block = { type: 'Block' };  
26 - owner = { name: 'profile-name' };  
27 - constructor() {  
28 - }  
29 - }  
30 -  
31 - it("show image if present", () => {  
32 - helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {  
33 - let elProfile = fixture.debugElement.componentViewChildren[0];  
34 - expect(elProfile.query('div.profile-image-block').length).toEqual(1);  
35 - });  
36 - });  
37 -  
38 - it("has link to the profile", () => {  
39 - helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {  
40 - let elProfile = fixture.debugElement.componentViewChildren[0];  
41 - expect(elProfile.query('a.settings-link').length).toEqual(1);  
42 - });  
43 - });  
44 -  
45 - });  
46 -});  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.component.ts
@@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
1 -import {Inject, Input, Component} from "ng-forward";  
2 -import {ProfileImage} from "./../../../components/noosfero/profile-image/profile-image.component";  
3 -  
4 -@Component({  
5 - selector: "noosfero-profile-image-block",  
6 - templateUrl: 'app/components/noosfero-blocks/profile-image-block/profile-image-block.html',  
7 - directives: [ProfileImage]  
8 -})  
9 -export class ProfileImageBlock {  
10 -  
11 - @Input() block: noosfero.Block;  
12 - @Input() owner: noosfero.Profile;  
13 -  
14 -}  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.html
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -<div class="center-block text-center profile-image-block">  
2 - <a ui-sref="main.profile.info({profile: ctrl.owner.identifier})">  
3 - <noosfero-profile-image [profile]="ctrl.owner"></noosfero-profile-image>  
4 - </a>  
5 - <a class="settings-link" target="_self" ui-sref="main.profile.settings({profile: ctrl.owner.identifier})">{{"blocks.profile_image.control_panel" | translate}}</a>  
6 -</div>  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.scss
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -.profile-image-block {  
2 - .settings-link {  
3 - display: block;  
4 - }  
5 -}  
src/app/components/noosfero-blocks/raw-html/raw-html.component.spec.ts
@@ -1,36 +0,0 @@ @@ -1,36 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Component} from 'ng-forward';  
3 -  
4 -import {RawHTMLBlock} from './raw-html.component';  
5 -  
6 -const tcb = new TestComponentBuilder();  
7 -  
8 -const htmlTemplate: string = '<noosfero-raw-htmlblock [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-raw-htmlblock>';  
9 -  
10 -describe("Components", () => {  
11 -  
12 - describe("Raw Html Block Component", () => {  
13 -  
14 - beforeEach(angular.mock.module("templates"));  
15 - beforeEach(angular.mock.module("ngSanitize"));  
16 -  
17 - it("display html stored in block settings", done => {  
18 -  
19 - @Component({  
20 - selector: 'test-container-component',  
21 - template: htmlTemplate,  
22 - directives: [RawHTMLBlock],  
23 - })  
24 - class CustomBlockType {  
25 - block: any = { settings: { html: '<em>block content</em>' } };  
26 - owner: any = { name: 'profile-name' };  
27 - }  
28 - tcb.createAsync(CustomBlockType).then(fixture => {  
29 - expect(fixture.debugElement.query(".raw-html-block em").text().trim()).toEqual('block content');  
30 - done();  
31 - });  
32 - });  
33 -  
34 - });  
35 -  
36 -});  
src/app/components/noosfero-blocks/raw-html/raw-html.component.ts
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -  
3 -@Component({  
4 - selector: "noosfero-raw-htmlblock",  
5 - templateUrl: 'app/components/noosfero-blocks/raw-html/raw-html.html'  
6 -})  
7 -  
8 -export class RawHTMLBlock {  
9 -  
10 - @Input() block: any;  
11 - @Input() owner: any;  
12 -  
13 - html: string;  
14 -  
15 - ngOnInit() {  
16 - this.html = this.block.settings.html;  
17 - }  
18 -}  
src/app/components/noosfero-blocks/raw-html/raw-html.html
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -<div class="raw-html-block" ng-bind-html="ctrl.html">  
2 -</div>  
src/app/components/noosfero-blocks/recent-documents/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/recent-documents/recent-documents.component.spec.ts
@@ -1,80 +0,0 @@ @@ -1,80 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Provider, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -import {RecentDocumentsBlock} from './recent-documents.component';  
5 -  
6 -const htmlTemplate: string = '<noosfero-recent-documents-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-recent-documents-block>';  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -describe("Components", () => {  
11 - describe("Recent Documents Block Component", () => {  
12 -  
13 - let settingsObj = {};  
14 - let mockedArticleService = {  
15 - getByProfile: (profile: noosfero.Profile, filters: any): any => {  
16 - return Promise.resolve({ data: [{ name: "article1" }], headers: (name: string) => { return name; } });  
17 - }  
18 - };  
19 - let profile = { name: 'profile-name' };  
20 - beforeEach(angular.mock.module("templates"));  
21 -  
22 - let state = jasmine.createSpyObj("state", ["go"]);  
23 -  
24 -  
25 - function getProviders() {  
26 - return [  
27 - new Provider('$state', { useValue: state }),  
28 - new Provider('ArticleService', {  
29 - useValue: mockedArticleService  
30 - }),  
31 - ].concat(provideFilters("truncateFilter", "stripTagsFilter"));  
32 - }  
33 - let componentClass: any = null;  
34 -  
35 - function getComponent() {  
36 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [RecentDocumentsBlock], providers: getProviders() })  
37 - class BlockContainerComponent {  
38 - block = { type: 'Block', settings: settingsObj };  
39 - owner = profile;  
40 - constructor() {  
41 - }  
42 - }  
43 - return BlockContainerComponent;  
44 - }  
45 -  
46 -  
47 - it("get recent documents from the article service", done => {  
48 - tcb.createAsync(getComponent()).then(fixture => {  
49 - let recentDocumentsBlock: RecentDocumentsBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
50 - expect(recentDocumentsBlock.documents).toEqual([{ name: "article1" }]);  
51 - done();  
52 - });  
53 - });  
54 -  
55 - it("go to article page when open a document", done => {  
56 - tcb.createAsync(getComponent()).then(fixture => {  
57 - let recentDocumentsBlock: RecentDocumentsBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
58 - recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });  
59 - expect(state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "identifier" });  
60 - done();  
61 - });  
62 - });  
63 -  
64 - it("it uses default limit 5 if not defined on block", done => {  
65 - settingsObj = null;  
66 - mockedArticleService = jasmine.createSpyObj("mockedArticleService", ["getByProfile"]);  
67 - (<any>mockedArticleService).mocked = true;  
68 - let thenMocked = jasmine.createSpy("then");  
69 - mockedArticleService.getByProfile = jasmine.createSpy("getByProfile").and.returnValue({then: thenMocked});  
70 - let getByProfileFunct = mockedArticleService.getByProfile;  
71 - tcb.createAsync(getComponent()).then(fixture => {  
72 - let recentDocumentsBlock: RecentDocumentsBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
73 - recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });  
74 - expect(getByProfileFunct).toHaveBeenCalledWith(profile, { content_type: 'TinyMceArticle', per_page: 5 });  
75 - done();  
76 - });  
77 - });  
78 -  
79 - });  
80 -});  
81 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/recent-documents/recent-documents.component.ts
@@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
1 -import {Component, Inject, Input} from "ng-forward";  
2 -import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";  
3 -  
4 -@Component({  
5 - selector: "noosfero-recent-documents-block",  
6 - templateUrl: 'app/components/noosfero-blocks/recent-documents/recent-documents.html'  
7 -})  
8 -@Inject(ArticleService, "$state")  
9 -export class RecentDocumentsBlock {  
10 -  
11 - @Input() block: any;  
12 - @Input() owner: any;  
13 -  
14 - profile: any;  
15 - documents: any;  
16 -  
17 - documentsLoaded: boolean = false;  
18 -  
19 - constructor(private articleService: ArticleService, private $state: any) {  
20 - }  
21 -  
22 - ngOnInit() {  
23 - this.profile = this.owner;  
24 - this.documents = [];  
25 -  
26 - let limit = ((this.block && this.block.settings) ? this.block.settings.limit : null) || 5;  
27 - // FIXME get all text articles  
28 - // FIXME make the getByProfile a generic method where we tell the type passing a class TinyMceArticle  
29 - // and the promise should be of type TinyMceArticle[], per example  
30 - this.articleService.getByProfile(this.profile, { content_type: 'TinyMceArticle', per_page: limit })  
31 - .then((result: noosfero.RestResult<noosfero.Article[]>) => {  
32 - this.documents = <noosfero.Article[]>result.data;  
33 - this.documentsLoaded = true;  
34 - });  
35 - }  
36 -  
37 - openDocument(article: any) {  
38 - this.$state.go("main.profile.page", { page: article.path, profile: article.profile.identifier });  
39 - }  
40 -  
41 -}  
src/app/components/noosfero-blocks/recent-documents/recent-documents.html
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -<div deckgrid source="ctrl.documents" class="deckgrid">  
2 - <div class="a-card panel media" ng-click="mother.ctrl.openDocument(card);">  
3 - <div class="author media-left" ng-show="card.author.image">  
4 - <img ng-src="{{card.author.image.url}}" class="img-circle">  
5 - </div>  
6 - <div class="header media-body">  
7 - <h5 class="title media-heading" ng-bind="card.title"></h5>  
8 -  
9 - <div class="subheader">  
10 - <span class="time">  
11 - <i class="fa fa-clock-o"></i> <span am-time-ago="card.created_at | dateFormat"></span>  
12 - </span>  
13 - </div>  
14 - </div>  
15 - <img ng-show="card.image" ng-src="{{card.image.url}}" class="img-responsive article-image">  
16 - <div class="post-lead" ng-bind-html="card.body | stripTags | truncate: 100: '...': true"></div>  
17 - </div>  
18 -</div>  
src/app/components/noosfero-blocks/recent-documents/recent-documents.scss
@@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
1 -.block.recentdocumentsblock {  
2 - .deckgrid[deckgrid]::before {  
3 - font-size: 0; /* See https://github.com/akoenig/angular-deckgrid/issues/14#issuecomment-35728861 */  
4 - visibility: hidden;  
5 - }  
6 - .author {  
7 - img {  
8 - width: 30px;  
9 - height: 30px;  
10 - }  
11 - }  
12 - .header {  
13 - .subheader {  
14 - color: #C1C1C1;  
15 - font-size: 10px;  
16 - }  
17 - }  
18 - .post-lead {  
19 - color: #8E8E8E;  
20 - font-size: 14px;  
21 - }  
22 - .article-image {  
23 - margin: 10px 0;  
24 - }  
25 -}  
26 -  
27 -.col-md-2-5 {  
28 - .deckgrid[deckgrid]::before {  
29 - content: '1 .deck-column';  
30 - }  
31 -}  
32 -  
33 -.col-md-7 {  
34 - .block.recentdocumentsblock {  
35 - background-color: transparent;  
36 - border: 0;  
37 -  
38 - .deckgrid[deckgrid]::before {  
39 - content: '3 .deck-column';  
40 - }  
41 -  
42 - .panel-heading {  
43 - display: none;  
44 - }  
45 - .panel-body {  
46 - padding: 0;  
47 - }  
48 -  
49 - .deckgrid {  
50 - .column {  
51 - float: left;  
52 - }  
53 -  
54 - .deck-column {  
55 - @extend .col-md-4;  
56 - padding: 0;  
57 -  
58 - .a-card {  
59 - padding: 10px;  
60 - margin: 3px;  
61 - }  
62 - }  
63 - }  
64 - }  
65 -}  
src/app/components/noosfero-boxes/box.html
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div ng-class="{'col-md-2-5': box.position!=1, 'col-md-7': box.position==1}">  
2 - <div ng-repeat="block in box.blocks | orderBy: 'position'" class="panel panel-default block {{block.type | lowercase}}" >  
3 - <div class="panel-heading" ng-show="block.title">  
4 - <h3 class="panel-title">{{block.title}}</h3>  
5 - </div>  
6 - <div class="panel-body">  
7 - <noosfero-block [block]="block" [owner]="ctrl.owner"></noosfero-block>  
8 - </div>  
9 - </div>  
10 -</div>  
src/app/components/noosfero-boxes/boxes.component.spec.ts
@@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
1 -import {Component} from 'ng-forward';  
2 -  
3 -import {Boxes} from './boxes.component';  
4 -  
5 -import {  
6 - createComponentFromClass,  
7 - quickCreateComponent,  
8 - provideEmptyObjects,  
9 - createProviderToValue,  
10 - getAngularServiceFactory,  
11 - provideFilters  
12 -} from "../../../spec/helpers";  
13 -  
14 -// this htmlTemplate will be re-used between the container components in this spec file  
15 -const htmlTemplate: string = '<noosfero-boxes [boxes]="ctrl.boxes" [owner]="ctrl.profile"></noosfero-blog>';  
16 -  
17 -  
18 -describe("Boxes Component", () => {  
19 -  
20 - beforeEach(() => {  
21 - angular.mock.module("templates");  
22 - });  
23 -  
24 - @Component({  
25 - selector: 'test-container-component',  
26 - template: htmlTemplate,  
27 - directives: [Boxes],  
28 - providers: []  
29 - })  
30 - class BoxesContainerComponent {  
31 - boxes: noosfero.Box[] = [  
32 - { id: 1, position: 1 },  
33 - { id: 2, position: 2 }  
34 - ];  
35 -  
36 - owner: noosfero.Profile = <noosfero.Profile> {  
37 - id: 1,  
38 - identifier: 'profile-name',  
39 - type: 'Person'  
40 - };  
41 - }  
42 -  
43 - it("renders boxes into a container", (done: Function) => {  
44 - createComponentFromClass(BoxesContainerComponent).then((fixture) => {  
45 - let boxesHtml = fixture.debugElement;  
46 - expect(boxesHtml.query('div.col-md-7').length).toEqual(1);  
47 - expect(boxesHtml.query('div.col-md-2-5').length).toEqual(1);  
48 -  
49 - done();  
50 - });  
51 - });  
52 -  
53 - it("check the boxes order", (done: Function) => {  
54 - createComponentFromClass(BoxesContainerComponent).then((fixture) => {  
55 -  
56 - let boxesComponent: Boxes = fixture.debugElement.componentViewChildren[0].componentInstance;  
57 - let boxesContainer: BoxesContainerComponent = fixture.componentInstance;  
58 -  
59 - expect(boxesComponent.boxesOrder(boxesContainer.boxes[0])).toEqual(1);  
60 - expect(boxesComponent.boxesOrder(boxesContainer.boxes[1])).toEqual(0);  
61 -  
62 - done();  
63 - });  
64 - });  
65 -});  
src/app/components/noosfero-boxes/boxes.component.ts
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -import {Input, Inject, Component} from 'ng-forward';  
2 -  
3 -@Component({  
4 - selector: "noosfero-boxes",  
5 - templateUrl: "app/components/noosfero-boxes/boxes.html"  
6 -})  
7 -export class Boxes {  
8 -  
9 - @Input() boxes: noosfero.Box[];  
10 - @Input() owner: noosfero.Profile;  
11 -  
12 - boxesOrder(box: noosfero.Box) {  
13 - if (box.position === 2) return 0;  
14 - return box.position;  
15 - }  
16 -}  
src/app/components/noosfero-boxes/boxes.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<ng-include ng-repeat="box in ctrl.boxes | orderBy: ctrl.boxesOrder" src="'app/components/noosfero-boxes/box.html'"></ng-include>  
src/app/components/noosfero-boxes/boxes.scss
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -.col-md-2-5 {  
2 - @extend .col-md-3;  
3 - @media (min-width: 920px) {  
4 - width: 20.83%;  
5 - }  
6 -}  
src/app/components/noosfero-boxes/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./boxes.component";  
src/app/components/noosfero/date-format/date-format.filter.spec.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {quickCreateComponent} from "../../../../spec/helpers";  
2 -import {DateFormat} from './date-format.filter';  
3 -  
4 -describe("Filters", () => {  
5 - describe("Date Format Filter", () => {  
6 -  
7 - beforeEach(angular.mock.module("templates"));  
8 - beforeEach(angular.mock.module("angularMoment"));  
9 -  
10 - it("convert date from the format returned by noosfero api to an ISO format", done => {  
11 - let date = "2016/03/10 10:46:47";  
12 - let htmlTemplate = `{{ '${date}' | dateFormat }}`;  
13 - quickCreateComponent({ providers: [DateFormat], template: htmlTemplate }).then(fixture => {  
14 - expect(fixture.debugElement.text()).toEqual('2016-03-10T13:46:47.000Z');  
15 - done();  
16 - });  
17 - });  
18 -  
19 - });  
20 -});  
src/app/components/noosfero/date-format/date-format.filter.ts
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -import {Pipe, Inject} from "ng-forward";  
2 -  
3 -@Pipe("dateFormat")  
4 -@Inject("amParseFilter")  
5 -export class DateFormat {  
6 -  
7 - constructor(private amParseFilter: any) { }  
8 -  
9 - transform(date: string, options: any) {  
10 - return this.amParseFilter(date, "YYYY/MM/DD HH:mm:ss").toISOString();  
11 - }  
12 -  
13 -}  
src/app/components/noosfero/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero/noosfero-template.filter.spec.ts
@@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
1 -import {quickCreateComponent} from "../../../spec/helpers";  
2 -import {NoosferoTemplate} from './noosfero-template.filter';  
3 -  
4 -describe("Filters", () => {  
5 - describe("Noosfero Template Filter", () => {  
6 -  
7 - beforeEach(angular.mock.module("templates"));  
8 -  
9 - it("replace the options in text with the values passed on options", done => {  
10 - let text = 'profile: {profile}, other: {other}';  
11 - let htmlTemplate = `{{ '${text}' | noosferoTemplate: {profile: 'profile1', other: 'other value'} }}`;  
12 - quickCreateComponent({ providers: [NoosferoTemplate], template: htmlTemplate }).then(fixture => {  
13 - expect(fixture.debugElement.text()).toEqual("profile: profile1, other: other value");  
14 - done();  
15 - });  
16 - });  
17 -  
18 - });  
19 -});  
src/app/components/noosfero/noosfero-template.filter.ts
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -import {Pipe} from "ng-forward";  
2 -  
3 -@Pipe("noosferoTemplate")  
4 -export class NoosferoTemplate {  
5 -  
6 - transform(text: string, options: any) {  
7 - for (let option in options) {  
8 - text = text.replace('{' + option + '}', options[option]);  
9 - }  
10 - return text;  
11 - }  
12 -  
13 -}  
src/app/components/noosfero/profile-image/index.ts
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -/**  
2 - * Module for the image component in the Noosfero Angular Theme  
3 - * @namespace components.noosfero.profile-image  
4 - */  
5 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero/profile-image/profile-image.component.spec.ts
@@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
1 -/**  
2 - * @ngdoc overview  
3 - * @name components.noosfero.profile-image.ProfileImageSpec  
4 - * @description  
5 - * This file contains the tests for the {@link components.noosfero.profile-image.ProfileImage} component.  
6 - */  
7 -  
8 -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
9 -import {Pipe, Input, provide, Component} from 'ng-forward';  
10 -  
11 -import * as helpers from "./../../../../spec/helpers";  
12 -  
13 -import {ProfileImage} from "./profile-image.component";  
14 -  
15 -const tcb = new TestComponentBuilder();  
16 -  
17 -describe("Components", () => {  
18 -  
19 - describe("Profile Image Component", () => {  
20 -  
21 - beforeEach(angular.mock.module("templates"));  
22 -  
23 - it("show community users image if profile is not Person", done => {  
24 - helpers.tcb.createAsync(ProfileImage).then(fixture => {  
25 - let profileImageComponent: ProfileImage = fixture.componentInstance;  
26 - let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Community" };  
27 - profileImageComponent.profile = profile;  
28 - profileImageComponent.ngOnInit();  
29 -  
30 - // Check the attribute  
31 - expect(profileImageComponent.defaultIcon).toBe("fa-users", "The default icon should be community users");  
32 - // var elProfile = fixture.debugElement.componentViewChildren[0];  
33 - // expect(elProfile.query('div.profile-image-block').length).toEqual(1);  
34 - done();  
35 - });  
36 - });  
37 -  
38 - it("show Person image if profile is Person", done => {  
39 - tcb.createAsync(ProfileImage).then(fixture => {  
40 - let profileImageComponent: ProfileImage = fixture.componentInstance;  
41 - let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Person" };  
42 - profileImageComponent.profile = profile;  
43 - profileImageComponent.ngOnInit();  
44 - // Check the attribute  
45 - expect(profileImageComponent.defaultIcon).toEqual("fa-user", "The default icon should be person user");  
46 - done();  
47 - });  
48 - });  
49 -  
50 - });  
51 -});  
52 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero/profile-image/profile-image.component.ts
@@ -1,47 +0,0 @@ @@ -1,47 +0,0 @@
1 -import {Inject, Input, Component} from "ng-forward";  
2 -  
3 -  
4 -/**  
5 - * @ngdoc controller  
6 - * @name components.noosfero.profile-image.ProfileImage  
7 - * @description The component responsible for rendering the profile image  
8 - * @exports ProfileImage  
9 - */  
10 -@Component({  
11 - selector: "noosfero-profile-image",  
12 - templateUrl: 'app/components/noosfero/profile-image/profile-image.html',  
13 -})  
14 -export class ProfileImage {  
15 -  
16 - /**  
17 - * @ngdoc property  
18 - * @name profile  
19 - * @propertyOf components.noosfero.profile-image.ProfileImage  
20 - * @description  
21 - * The Noosfero {@link models.Profile} holding the image.  
22 - */  
23 - @Input() profile: noosfero.Profile;  
24 - /**  
25 - * @ngdoc property  
26 - * @name defaultIcon  
27 - * @propertyOf components.noosfero.profile-image.ProfileImage  
28 - * @descritpion  
29 - * The default icon used by this profile  
30 - */  
31 - defaultIcon: string;  
32 -  
33 - /**  
34 - * @ngdoc method  
35 - * @name ngOnInit  
36 - * @methodOf components.noosfero.profile-image.ProfileImage  
37 - * @description  
38 - * Initializes the icon names to their corresponding values depending on the profile type passed to the controller  
39 - */  
40 - ngOnInit() {  
41 - this.defaultIcon = 'fa-users';  
42 - if (this.profile && this.profile.type === 'Person') {  
43 - this.defaultIcon = 'fa-user';  
44 - }  
45 - }  
46 -}  
47 -  
src/app/components/noosfero/profile-image/profile-image.html
@@ -1,4 +0,0 @@ @@ -1,4 +0,0 @@
1 -<span title="{{ctrl.profile.name}}">  
2 - <img ng-if="ctrl.profile.image" ng-src="{{ctrl.profile.image.url}}" class="img-responsive profile-image">  
3 - <i ng-if="!ctrl.profile.image" class="fa {{ctrl.defaultIcon}} fa-5x profile-image"></i>  
4 -</span>  
src/app/components/noosfero/profile-image/profile-image.scss
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -i.profile-image {  
2 - color: rgb(44, 62, 80);  
3 -}  
src/app/components/notification/notification.component.spec.ts
@@ -1,80 +0,0 @@ @@ -1,80 +0,0 @@
1 -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -  
4 -import * as helpers from "../../../spec/helpers";  
5 -  
6 -import {Notification} from "./notification.component";  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -describe("Components", () => {  
11 -  
12 - describe("Profile Image Component", () => {  
13 -  
14 - beforeEach(angular.mock.module("templates"));  
15 -  
16 - it("display an error message when notify an error", done => {  
17 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
18 - sweetAlert.swal = jasmine.createSpy("swal");  
19 -  
20 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
21 - component.error("message", "title");  
22 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
23 - text: "message",  
24 - title: "title",  
25 - type: "error"  
26 - }));  
27 - done();  
28 - });  
29 -  
30 - it("use the default message when call notification component without a message", done => {  
31 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
32 - sweetAlert.swal = jasmine.createSpy("swal");  
33 -  
34 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
35 - component.error();  
36 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
37 - text: Notification.DEFAULT_ERROR_MESSAGE,  
38 - type: "error"  
39 - }));  
40 - done();  
41 - });  
42 -  
43 - it("display a success message when call notification success", done => {  
44 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
45 - sweetAlert.swal = jasmine.createSpy("swal");  
46 -  
47 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
48 - component.success("title", "message", 1000);  
49 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
50 - type: "success"  
51 - }));  
52 - done();  
53 - });  
54 -  
55 - it("display a message relative to the http error code", done => {  
56 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
57 - sweetAlert.swal = jasmine.createSpy("swal");  
58 -  
59 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
60 - component.httpError(500, {});  
61 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
62 - text: "notification.http_error.500.message"  
63 - }));  
64 - done();  
65 - });  
66 -  
67 - it("set the default timer in success messages", done => {  
68 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
69 - sweetAlert.swal = jasmine.createSpy("swal");  
70 -  
71 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
72 - component.success("title", "message");  
73 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
74 - type: "success",  
75 - timer: Notification.DEFAULT_SUCCESS_TIMER  
76 - }));  
77 - done();  
78 - });  
79 - });  
80 -});  
src/app/components/notification/notification.component.ts
@@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -import {TranslatorService} from "../translator/translator.service";  
3 -  
4 -@Injectable()  
5 -@Inject("$log", "SweetAlert", TranslatorService)  
6 -export class Notification {  
7 -  
8 - constructor(  
9 - private $log: ng.ILogService,  
10 - private SweetAlert: any,  
11 - private translatorService: TranslatorService  
12 - ) { }  
13 -  
14 - public static DEFAULT_ERROR_TITLE = "notification.error.default.title";  
15 - public static DEFAULT_ERROR_MESSAGE = "notification.error.default.message";  
16 - public static DEFAULT_SUCCESS_TIMER = 1000;  
17 -  
18 - error(message: string = Notification.DEFAULT_ERROR_MESSAGE, title: string = Notification.DEFAULT_ERROR_TITLE) {  
19 - this.$log.debug("Notification error:", title, message, this.translatorService.currentLanguage());  
20 - this.SweetAlert.swal({  
21 - title: this.translatorService.translate(title),  
22 - text: this.translatorService.translate(message),  
23 - type: "error"  
24 - });  
25 - }  
26 -  
27 - httpError(status: number, data: any): boolean {  
28 - this.error(`notification.http_error.${status}.message`);  
29 - return true; // return true to indicate that the error was already handled  
30 - }  
31 -  
32 - success(title: string, text: string, timer: number = Notification.DEFAULT_SUCCESS_TIMER) {  
33 - this.SweetAlert.swal({  
34 - title: title,  
35 - text: text,  
36 - type: "success",  
37 - timer: timer  
38 - });  
39 - }  
40 -  
41 -}  
src/app/components/translator/translator.service.spec.ts
@@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
1 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {provide} from 'ng-forward';  
3 -  
4 -import {TranslatorService} from './translator.service';  
5 -  
6 -import * as helpers from "../../../spec/helpers";  
7 -  
8 -describe("Services", () => {  
9 -  
10 - describe("Translator Service", () => {  
11 -  
12 - let $rootScope: ng.IScope;  
13 - let $q: ng.IQService;  
14 -  
15 - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {  
16 - $rootScope = _$rootScope_;  
17 - $q = _$q_;  
18 - }));  
19 -  
20 - function createComponent() {  
21 - return new TranslatorService(  
22 - <any>helpers.mocks.$translate,  
23 - <any>helpers.mocks.tmhDynamicLocale,  
24 - <any>helpers.mocks.amMoment,  
25 - <any>helpers.mocks.angularLoad,  
26 - $rootScope  
27 - );  
28 - }  
29 -  
30 - it("set available languages when change language", (done) => {  
31 - let component: TranslatorService = createComponent();  
32 - component.availableLanguages = null;  
33 - expect(component.availableLanguages).toBeNull();  
34 - $rootScope.$emit("$translateChangeSuccess");  
35 - expect(component.availableLanguages).not.toBeNull();  
36 - done();  
37 - });  
38 -  
39 - it("change the language", (done) => {  
40 - let component: TranslatorService = createComponent();  
41 - let loadScripPromise = $q.defer();  
42 - loadScripPromise.resolve();  
43 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);  
44 - component["tmhDynamicLocale"].set = jasmine.createSpy("set");  
45 - component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");  
46 - component["$translate"].use = jasmine.createSpy("use");  
47 -  
48 - component.changeLanguage('pt');  
49 - $rootScope.$digest();  
50 -  
51 - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");  
52 - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");  
53 - expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");  
54 - expect(component["$translate"].use).toHaveBeenCalledWith("pt");  
55 - done();  
56 - });  
57 -  
58 - it("do not load moment locale when change the language to english", (done) => {  
59 - let component: TranslatorService = createComponent();  
60 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue($q.defer().promise);  
61 - component.changeLanguage('en');  
62 - expect(component["angularLoad"].loadScript).not.toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");  
63 - done();  
64 - });  
65 -  
66 - it("do nothing when call change language with null", (done) => {  
67 - let component: TranslatorService = createComponent();  
68 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript");  
69 - component["tmhDynamicLocale"].set = jasmine.createSpy("set");  
70 - component["$translate"].use = jasmine.createSpy("use");  
71 -  
72 - component.changeLanguage(null);  
73 -  
74 - expect(component["angularLoad"].loadScript).not.toHaveBeenCalled();  
75 - expect(component["tmhDynamicLocale"].set).not.toHaveBeenCalled();  
76 - expect(component["$translate"].use).not.toHaveBeenCalled();  
77 - done();  
78 - });  
79 -  
80 - it("return the current language used by the translator", (done) => {  
81 - let component: TranslatorService = createComponent();  
82 - component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");  
83 - expect(component.currentLanguage()).toEqual("en");  
84 - expect(component["$translate"].use).toHaveBeenCalled();  
85 - done();  
86 - });  
87 -  
88 - it("call translate service when translate a text", (done) => {  
89 - let component: TranslatorService = createComponent();  
90 - component["$translate"].instant = jasmine.createSpy("instant");  
91 - component.translate("text");  
92 - expect(component["$translate"].instant).toHaveBeenCalledWith("text");  
93 - done();  
94 - });  
95 -  
96 - it("change the language when receive an event", (done) => {  
97 - let component: TranslatorService = createComponent();  
98 - component.changeLanguage = jasmine.createSpy("changeLanguage");  
99 - $rootScope.$emit("$localeChangeSuccess");  
100 - expect(component.changeLanguage).toHaveBeenCalled();  
101 - done();  
102 - });  
103 -  
104 - it("use the translate language when receive a change language event and there is no language previously selected", (done) => {  
105 - let component: TranslatorService = createComponent();  
106 - component.changeLanguage = jasmine.createSpy("changeLanguage");  
107 - component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue(null);  
108 - component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");  
109 -  
110 - $rootScope.$emit("$localeChangeSuccess");  
111 - expect(component["$translate"].use).toHaveBeenCalled();  
112 - expect(component.changeLanguage).toHaveBeenCalledWith("en");  
113 - done();  
114 - });  
115 - });  
116 -});  
src/app/components/translator/translator.service.ts
@@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -  
3 -@Injectable()  
4 -@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad", "$rootScope")  
5 -export class TranslatorService {  
6 -  
7 - availableLanguages: any;  
8 -  
9 - constructor(private $translate: angular.translate.ITranslateService,  
10 - private tmhDynamicLocale: angular.dynamicLocale.tmhDynamicLocaleService,  
11 - private amMoment: any,  
12 - private angularLoad: any,  
13 - private $rootScope: any) {  
14 -  
15 - this.$rootScope.$on("$localeChangeSuccess", () => {  
16 - this.changeLanguage(tmhDynamicLocale.get() || $translate.use());  
17 - });  
18 - this.$rootScope.$on("$translateChangeSuccess", () => {  
19 - this.configAvailableLanguages();  
20 - });  
21 - }  
22 -  
23 - currentLanguage() {  
24 - return this.$translate.use();  
25 - }  
26 -  
27 - changeLanguage(language: string) {  
28 - if (!language) {  
29 - console.log("WARN: language undefined");  
30 - return;  
31 - }  
32 - this.changeMomentLocale(language);  
33 - this.tmhDynamicLocale.set(language);  
34 - this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {  
35 - return this.$translate.use(language);  
36 - });  
37 - }  
38 -  
39 - translate(text: string) {  
40 - return this.$translate.instant(text);  
41 - }  
42 -  
43 - private configAvailableLanguages() {  
44 - this.availableLanguages = {  
45 - "en": this.$translate.instant("language.en"),  
46 - "pt": this.$translate.instant("language.pt")  
47 - };  
48 - }  
49 -  
50 - private changeMomentLocale(language: string) {  
51 - let localePromise = Promise.resolve();  
52 - if (language !== "en") {  
53 - localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);  
54 - }  
55 - localePromise.then(() => {  
56 - this.amMoment.changeLocale(language);  
57 - });  
58 - }  
59 -}  
src/app/content-viewer/content-viewer-actions.component.spec.ts
@@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
1 -import {providers} from 'ng-forward/cjs/testing/providers';  
2 -  
3 -import {Input, Component, provide} from 'ng-forward';  
4 -  
5 -import * as helpers from "../../spec/helpers";  
6 -  
7 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
8 -import {ContentViewerActions} from './content-viewer-actions.component';  
9 -  
10 -// this htmlTemplate will be re-used between the container components in this spec file  
11 -const htmlTemplate: string = '<content-viewer-actions [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer-actions>';  
12 -  
13 -describe('Content Viewer Actions Component', () => {  
14 -  
15 - beforeEach(() => {  
16 -  
17 - angular.mock.module("templates");  
18 -  
19 - providers((provide: any) => {  
20 - return <any>[  
21 - provide('ProfileService', {  
22 - useValue: helpers.mocks.profileService  
23 - })  
24 - ];  
25 - });  
26 - });  
27 -  
28 - let buildComponent = (): Promise<ComponentFixture> => {  
29 - return helpers.quickCreateComponent({  
30 - providers: [  
31 - helpers.provideEmptyObjects('Restangular'),  
32 - helpers.provideFilters('translateFilter')  
33 - ],  
34 - directives: [ContentViewerActions],  
35 - template: htmlTemplate  
36 - });  
37 - };  
38 -  
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);  
42 -  
43 - done();  
44 - });  
45 - });  
46 -  
47 - it('check if profile was loaded', (done: Function) => {  
48 - let profile: any = {  
49 - id: 1,  
50 - identifier: 'the-profile-test',  
51 - type: 'Person'  
52 - };  
53 -  
54 - helpers.mocks.profileService.getCurrentProfile = () => {  
55 - return helpers.mocks.promiseResultTemplate(profile);  
56 - };  
57 -  
58 - buildComponent().then((fixture: ComponentFixture) => {  
59 - let contentViewerComp: ContentViewerActions = fixture.debugElement.componentViewChildren[0].componentInstance;  
60 -  
61 - expect(contentViewerComp.profile).toEqual(jasmine.objectContaining(profile));  
62 -  
63 - done();  
64 - });  
65 - });  
66 -  
67 -});  
src/app/content-viewer/content-viewer-actions.component.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {Component, Inject, provide} from "ng-forward";  
2 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
3 -  
4 -@Component({  
5 - selector: "content-viewer-actions",  
6 - templateUrl: "app/content-viewer/navbar-actions.html",  
7 - providers: [provide('profileService', { useClass: ProfileService })]  
8 -})  
9 -@Inject(ProfileService)  
10 -export class ContentViewerActions {  
11 -  
12 - article: noosfero.Article;  
13 - profile: noosfero.Profile;  
14 -  
15 - constructor(profileService: ProfileService) {  
16 - profileService.getCurrentProfile().then((profile: noosfero.Profile) => {  
17 - this.profile = profile;  
18 - });  
19 - }  
20 -}  
src/app/content-viewer/content-viewer.component.spec.ts
@@ -1,88 +0,0 @@ @@ -1,88 +0,0 @@
1 -import {providers} from 'ng-forward/cjs/testing/providers';  
2 -  
3 -import {Input, Component, provide} from 'ng-forward';  
4 -  
5 -import * as helpers from "../../spec/helpers";  
6 -  
7 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
8 -import {ContentViewer} from './content-viewer.component';  
9 -  
10 -// this htmlTemplate will be re-used between the container components in this spec file  
11 -const htmlTemplate: string = '<content-viewer [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer>';  
12 -  
13 -describe('Content Viewer Component', () => {  
14 -  
15 - let stateParamsService: any;  
16 -  
17 - // loading the templates  
18 - beforeEach(() => {  
19 - angular.mock.module("templates");  
20 -  
21 - stateParamsService = { page: 1 };  
22 -  
23 - providers((provide: any) => {  
24 - return <any>[  
25 - provide('ArticleService', {  
26 - useValue: helpers.mocks.articleService  
27 - }),  
28 - provide('ProfileService', {  
29 - useValue: helpers.mocks.profileService  
30 - }),  
31 - // TODO: Como criar um mock do atributo "page" de stateParams  
32 - provide('$stateParams', {  
33 - useValue: stateParamsService  
34 - })  
35 - ];  
36 - });  
37 - });  
38 -  
39 - let buildComponent = (): Promise<ComponentFixture> => {  
40 - return helpers.quickCreateComponent({  
41 - providers: [  
42 - helpers.provideEmptyObjects('Restangular')  
43 - ],  
44 - directives: [ContentViewer],  
45 - template: htmlTemplate  
46 - });  
47 - };  
48 -  
49 - it('renders content viewer directive', (done: Function) => {  
50 - buildComponent().then((fixture: ComponentFixture) => {  
51 - expect(fixture.debugElement.query('content-viewer').length).toEqual(1);  
52 -  
53 - done();  
54 - });  
55 - });  
56 -  
57 - it('check if article was loaded', (done: Function) => {  
58 - let article: any = {  
59 - id: 1,  
60 - title: 'The article test'  
61 - };  
62 - let profile: any = {  
63 - id: 1,  
64 - identifier: 'the-profile-test',  
65 - type: 'Person'  
66 - };  
67 -  
68 - helpers.mocks.profileService.getCurrentProfile = () => {  
69 - return helpers.mocks.promiseResultTemplate(profile);  
70 - };  
71 -  
72 - helpers.mocks.articleService.getArticleByProfileAndPath = (profile: noosfero.Profile, path: string) => {  
73 - return helpers.mocks.promiseResultTemplate({  
74 - data: article  
75 - });  
76 - };  
77 -  
78 -  
79 - buildComponent().then((fixture: ComponentFixture) => {  
80 - let contentViewerComp: ContentViewer = fixture.debugElement.componentViewChildren[0].componentInstance;  
81 -  
82 - expect(contentViewerComp.profile).toEqual(profile);  
83 - expect(contentViewerComp.article).toEqual(article);  
84 -  
85 - done();  
86 - });  
87 - });  
88 -});  
src/app/content-viewer/content-viewer.component.ts
@@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
1 -import {ArticleView} from "../components/noosfero-articles/article/article_view";  
2 -import {Input, Component, StateConfig, Inject, provide} from "ng-forward";  
3 -  
4 -import {ArticleBlog} from "./../components/noosfero-articles/blog/blog.component";  
5 -import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service";  
6 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
7 -  
8 -@Component({  
9 - selector: "content-viewer",  
10 - templateUrl: "app/content-viewer/page.html",  
11 - directives: [ArticleBlog, ArticleView],  
12 - providers: [  
13 - provide('articleService', { useClass: ArticleService }),  
14 - provide('profileService', { useClass: ProfileService })  
15 - ]  
16 -})  
17 -@Inject(ArticleService, ProfileService, "$log", "$stateParams")  
18 -export class ContentViewer {  
19 -  
20 - @Input()  
21 - article: noosfero.Article = null;  
22 -  
23 - @Input()  
24 - profile: noosfero.Profile = null;  
25 -  
26 - constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) {  
27 - this.activate();  
28 - }  
29 -  
30 - activate() {  
31 - this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {  
32 - this.profile = profile;  
33 - return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]);  
34 - }).then((result: noosfero.RestResult<any>) => {  
35 - this.article = <noosfero.Article>result.data;  
36 - });  
37 - }  
38 -}  
src/app/content-viewer/index.ts
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./content-viewer-actions.component";  
3 -export * from "./content-viewer.component";  
src/app/content-viewer/navbar-actions.html
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -<ul class="nav navbar-nav">  
2 - <li ng-show="vm.profile">  
3 - <a href="#" role="button" ui-sref="main.profile.cms({profile: vm.profile.identifier})">  
4 - <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}}  
5 - </a>  
6 - </li>  
7 -</ul>  
src/app/content-viewer/page.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<noosfero-article ng-if="vm.article" [article]="vm.article" [profile]="vm.profile"></noosfero-article>  
src/app/index.run.ts
1 -import {Session} from "./components/auth/session";  
2 -import {Notification} from "./components/notification/notification.component"; 1 +import {SessionService} from "./login";
  2 +import {NotificationService} from "./shared/services/notification.service";
3 3
4 /** @ngInject */ 4 /** @ngInject */
5 export function noosferoAngularRunBlock( 5 export function noosferoAngularRunBlock(
6 $log: ng.ILogService, 6 $log: ng.ILogService,
7 Restangular: restangular.IService, 7 Restangular: restangular.IService,
8 - Session: Session,  
9 - Notification: Notification 8 + SessionService: SessionService,
  9 + NotificationService: NotificationService
10 ) { 10 ) {
11 11
12 Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => { 12 Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => {
13 - if (Session.currentUser()) {  
14 - (<any>headers)["Private-Token"] = Session.currentUser().private_token; 13 + if (SessionService.currentUser()) {
  14 + (<any>headers)["Private-Token"] = SessionService.currentUser().private_token;
15 } 15 }
16 return <any>{ headers: <any>headers }; 16 return <any>{ headers: <any>headers };
17 }); 17 });
18 Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => { 18 Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => {
19 // return false to break the promise chain and don't call catch 19 // return false to break the promise chain and don't call catch
20 - return !Notification.httpError(response.status, response.data); 20 + return !NotificationService.httpError(response.status, response.data);
21 }); 21 });
22 } 22 }
src/app/index.ts
@@ -5,10 +5,10 @@ import {noosferoAngularRunBlock} from &quot;./index.run&quot;; @@ -5,10 +5,10 @@ import {noosferoAngularRunBlock} from &quot;./index.run&quot;;
5 import {Main} from "./main/main.component"; 5 import {Main} from "./main/main.component";
6 import {bootstrap, bundle} from "ng-forward"; 6 import {bootstrap, bundle} from "ng-forward";
7 7
8 -import {AUTH_EVENTS} from "./components/auth/auth_events";  
9 -import {AuthController} from "./components/auth/auth_controller"; 8 +import {AUTH_EVENTS} from "./login/auth-events";
  9 +import {AuthController} from "./login/auth.controller";
10 10
11 -import {Navbar} from "./components/navbar/navbar"; 11 +import {Navbar} from "./layout/navbar/navbar";
12 12
13 declare var moment: any; 13 declare var moment: any;
14 14
src/app/layout/blocks/block.component.spec.ts 0 → 100644
@@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {BlockComponent} from './block.component';
  5 +
  6 +const tcb = new TestComponentBuilder();
  7 +
  8 +const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-block>';
  9 +
  10 +describe("Components", () => {
  11 + describe("Block Component", () => {
  12 +
  13 + // the karma preprocessor html2js transform the templates html into js files which put
  14 + // the templates to the templateCache into the module templates
  15 + // we need to load the module templates here as the template for the
  16 + // component Block will be load on our tests
  17 + beforeEach(angular.mock.module("templates"));
  18 +
  19 + it("receives the block and the owner as inputs", done => {
  20 +
  21 + // Creating a container component (BlockContainerComponent) to include
  22 + // the component under test (Block)
  23 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent] })
  24 + class BlockContainerComponent {
  25 + block = { type: 'Block' };
  26 + owner = { name: 'profile-name' };
  27 + constructor() {
  28 + }
  29 + }
  30 +
  31 + // uses the TestComponentBuilder instance to initialize the component
  32 + tcb
  33 + .createAsync(BlockContainerComponent).then(fixture => {
  34 + // and here we can inspect and run the test assertions
  35 + let myComponent: BlockComponent = fixture.componentInstance;
  36 +
  37 + // assure the block object inside the Block matches
  38 + // the provided through the parent component
  39 + expect(myComponent.block.type).toEqual("Block");
  40 + expect(myComponent.owner.name).toEqual("profile-name");
  41 + done();
  42 + });
  43 + });
  44 +
  45 +
  46 + it("renders a component which matches to the block type", done => {
  47 + // CustomBlock component created to check if it will be used
  48 + // when a block with type 'CustomBlock' is provided to the noosfero-block (Block)
  49 + // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider
  50 + @Component({ selector: 'noosfero-custom-block', template: "<h1>My Custom Block</h1>" })
  51 + class CustomBlock {
  52 + @Input() block: any;
  53 + @Input() owner: any;
  54 + }
  55 +
  56 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent, CustomBlock] })
  57 + class CustomBlockType {
  58 + block = { type: 'CustomBlock' };
  59 + owner = { name: 'profile-name' };
  60 + constructor() {
  61 + }
  62 + }
  63 + tcb
  64 + .createAsync(CustomBlockType).then(fixture => {
  65 + let myComponent: CustomBlockType = fixture.componentInstance;
  66 + expect(myComponent.block.type).toEqual("CustomBlock");
  67 + expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("My Custom Block");
  68 + done();
  69 + });
  70 + });
  71 +
  72 +
  73 + it("renders the default block when hasn't defined a block type", done => {
  74 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent] })
  75 + class CustomBlockType {
  76 + block: any = { type: null };
  77 + owner: any = { name: 'profile-name' };
  78 + constructor() {
  79 + }
  80 + }
  81 + tcb
  82 + .createAsync(CustomBlockType).then(fixture => {
  83 + let myComponent: CustomBlockType = fixture.componentInstance;
  84 + expect(myComponent.block.type).toBeNull();
  85 + expect(!!fixture.debugElement.nativeElement.querySelector("noosfero-default-block")).toBeTruthy();
  86 + done();
  87 + });
  88 + });
  89 +
  90 + });
  91 +});
0 \ No newline at end of file 92 \ No newline at end of file
src/app/layout/blocks/block.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import { Input, Inject, Component } from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: 'noosfero-block',
  5 + template: '<div></div>'
  6 +})
  7 +@Inject("$element", "$scope", "$injector", "$compile")
  8 +export class BlockComponent {
  9 +
  10 + @Input() block: any;
  11 + @Input() owner: any;
  12 +
  13 + ngOnInit() {
  14 + let blockName = (this.block && this.block.type) ? this.block.type.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : "default-block";
  15 + this.$element.replaceWith(this.$compile('<noosfero-' + blockName + ' [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-' + blockName + '>')(this.$scope));
  16 + }
  17 +
  18 + constructor(private $element: any, private $scope: ng.IScope, private $injector: ng.auto.IInjectorService, private $compile: ng.ICompileService) {
  19 + }
  20 +}
src/app/layout/blocks/block.scss 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +.block {
  2 + .panel-title {
  3 + font-size: 15px;
  4 + font-weight: bold;
  5 + }
  6 + .panel-heading {
  7 + background-color: transparent;
  8 + border: 0;
  9 + }
  10 +}
src/app/layout/blocks/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./block.component";
src/app/layout/blocks/link-list/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./link-list.component";
src/app/layout/blocks/link-list/link-list.component.spec.ts 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +
  5 +import {LinkListBlockComponent} from './link-list.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-link-list-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-link-list-block>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Link List Block Component", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + it("receives the block and the owner as inputs", done => {
  19 +
  20 + // Creating a container component (BlockContainerComponent) to include
  21 + // the component under test (Block)
  22 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [LinkListBlockComponent] })
  23 + class BlockContainerComponent {
  24 + block = { type: 'Block' };
  25 + owner = { name: 'profile-name' };
  26 + constructor() {
  27 + }
  28 + }
  29 +
  30 + // uses the TestComponentBuilder instance to initialize the component
  31 + // .overrideView(LinkListBlock, { template: 'asdasdasd', pipes: [NoosferoTemplate] })
  32 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  33 + // and here we can inspect and run the test assertions
  34 + let myComponent: LinkListBlockComponent = fixture.componentInstance;
  35 +
  36 + // assure the block object inside the Block matches
  37 + // the provided through the parent component
  38 + expect(myComponent.block.type).toEqual("Block");
  39 + expect(myComponent.owner.name).toEqual("profile-name");
  40 + done();
  41 + });
  42 + });
  43 +
  44 +
  45 + it("display links stored in block settings", done => {
  46 +
  47 + @Component({
  48 + selector: 'test-container-component',
  49 + template: htmlTemplate,
  50 + directives: [LinkListBlockComponent],
  51 + providers: provideFilters("noosferoTemplateFilter")
  52 + })
  53 + class CustomBlockType {
  54 + block: any = { settings: { links: [{ name: 'link1', address: 'address1' }, { name: 'link2', address: 'address2' }] } };
  55 + owner: any = { name: 'profile-name' };
  56 + }
  57 + tcb.createAsync(CustomBlockType).then(fixture => {
  58 + expect(fixture.debugElement.queryAll(".link-list-block a").length).toEqual(2);
  59 + done();
  60 + });
  61 + });
  62 +
  63 + });
  64 +
  65 +});
0 \ No newline at end of file 66 \ No newline at end of file
src/app/layout/blocks/link-list/link-list.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-link-list-block",
  5 + templateUrl: "app/layout/blocks/link-list/link-list.html"
  6 +})
  7 +export class LinkListBlockComponent {
  8 +
  9 + @Input() block: any;
  10 + @Input() owner: any;
  11 +
  12 + links: any;
  13 +
  14 + ngOnInit() {
  15 + if (this.block && this.block.settings) {
  16 + this.links = this.block.settings.links;
  17 + }
  18 + }
  19 +
  20 +}
src/app/layout/blocks/link-list/link-list.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<div class="link-list-block">
  2 + <div ng-repeat="link in ctrl.links">
  3 + <a ng-href="{{link.address | noosferoTemplate:{profile: ctrl.owner.identifier} }}">
  4 + <i class="fa fa-fw icon-{{link.icon}}"></i> <span>{{link.name}}</span>
  5 + </a>
  6 + </div>
  7 +</div>
src/app/layout/blocks/link-list/link-list.scss 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +.icon-event {
  2 + @extend .fa-calendar;
  3 +}
  4 +.icon-photos {
  5 + @extend .fa-photo;
  6 +}
  7 +.icon-edit {
  8 + @extend .fa-edit;
  9 +}
  10 +.icon-ok {
  11 + @extend .fa-check;
  12 +}
  13 +.icon-send {
  14 + @extend .fa-send-o;
  15 +}
  16 +.icon-menu-people {
  17 + @extend .fa-user;
  18 +}
  19 +.icon-forum {
  20 + @extend .fa-users;
  21 +}
  22 +.icon-new {
  23 + @extend .fa-file-o;
  24 +}
  25 +.icon-save {
  26 + @extend .fa-save;
  27 +}
  28 +
  29 +.link-list-block {
  30 + a i {
  31 + line-height: 25px;
  32 + color: #949494;
  33 + }
  34 +}
src/app/layout/blocks/main-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./main-block.component";
src/app/layout/blocks/main-block/main-block.component.spec.ts 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Input, provide, Component, StateConfig} from 'ng-forward';
  3 +
  4 +import {MainBlockComponent} from './main-block.component';
  5 +import {NoosferoApp} from '../../../index.module';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-main-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-main-block>';
  10 +
  11 +describe("Components", () => {
  12 + describe("Main Block Component", () => {
  13 +
  14 + // the karma preprocessor html2js transform the templates html into js files which put
  15 + // the templates to the templateCache into the module templates
  16 + // we need to load the module templates here as the template for the
  17 + // component Block will be load on our tests
  18 + beforeEach(angular.mock.module("templates"));
  19 +
  20 + it("check if the main block has a tag with ui-view attribute", done => {
  21 +
  22 + // Creating a container component (BlockContainerComponent) to include
  23 + // the component under test (Block)
  24 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MainBlockComponent] })
  25 + class BlockContainerComponent {
  26 + }
  27 +
  28 + // uses the TestComponentBuilder instance to initialize the component
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + // and here we can inspect and run the test assertions
  31 + // let myComponent: MainBlockComponent = fixture.componentInstance;
  32 +
  33 + // assure the block object inside the Block matches
  34 + // the provided through the parent component
  35 + expect(fixture.debugElement.queryAll('[ui-view="mainBlockContent"]').length).toEqual(1);
  36 + done();
  37 + });
  38 + });
  39 + });
  40 +});
0 \ No newline at end of file 41 \ No newline at end of file
src/app/layout/blocks/main-block/main-block.component.ts 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +import {Component, Input} from 'ng-forward';
  2 +import {BlockComponent} from '../block.component';
  3 +
  4 +@Component({
  5 + selector: 'noosfero-main-block',
  6 + templateUrl: 'app/layout/blocks/main-block/main-block.html'
  7 +})
  8 +export class MainBlockComponent {
  9 +
  10 +}
src/app/layout/blocks/main-block/main-block.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<div ui-view="mainBlockContent" autoscroll></div>
src/app/layout/blocks/members-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./members-block.component";
src/app/layout/blocks/members-block/members-block.component.spec.ts 0 → 100644
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Provider, Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {MembersBlockComponent} from './members-block.component';
  5 +
  6 +const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>';
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 + describe("Members Block Component", () => {
  12 +
  13 + beforeEach(angular.mock.module("templates"));
  14 +
  15 + let state = jasmine.createSpyObj("state", ["go"]);
  16 + let providers = [
  17 + new Provider('truncateFilter', { useValue: () => { } }),
  18 + new Provider('stripTagsFilter', { useValue: () => { } }),
  19 + new Provider('$state', { useValue: state }),
  20 + new Provider('ProfileService', {
  21 + useValue: {
  22 + getProfileMembers: (profileId: number, filters: any): any => {
  23 + return Promise.resolve({ data: { people: [{ identifier: "person1" }] } });
  24 + }
  25 + }
  26 + }),
  27 + ];
  28 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MembersBlockComponent], providers: providers })
  29 + class BlockContainerComponent {
  30 + block = { type: 'Block', settings: {} };
  31 + owner = { name: 'profile-name' };
  32 + constructor() {
  33 + }
  34 + }
  35 +
  36 + it("get members of the block owner", done => {
  37 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  38 + let block: MembersBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  39 + expect(block.members).toEqual([{ identifier: "person1" }]);
  40 + done();
  41 + });
  42 + });
  43 +
  44 + it("render the profile image for each member", done => {
  45 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  46 + fixture.debugElement.getLocal("$rootScope").$apply();
  47 + expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);
  48 + done();
  49 + });
  50 + });
  51 +
  52 + });
  53 +});
0 \ No newline at end of file 54 \ No newline at end of file
src/app/layout/blocks/members-block/members-block.component.ts 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +import {Input, Inject, Component} from "ng-forward";
  2 +import {ProfileService} from "../../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: "noosfero-members-block",
  6 + templateUrl: 'app/layout/blocks/members-block/members-block.html',
  7 +})
  8 +@Inject(ProfileService)
  9 +export class MembersBlockComponent {
  10 +
  11 + @Input() block: noosfero.Block;
  12 + @Input() owner: noosfero.Profile;
  13 +
  14 + members: any = [];
  15 +
  16 + constructor(private profileService: ProfileService) {
  17 +
  18 + }
  19 +
  20 + ngOnInit() {
  21 + this.profileService.getProfileMembers(this.owner.id, { per_page: 6 }).then((response: any) => {
  22 + this.members = response.data.people;
  23 + });
  24 + }
  25 +}
src/app/layout/blocks/members-block/members-block.html 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<div class="members-block">
  2 + <a ng-repeat="member in ctrl.members" ui-sref="main.profile.home({profile: member.identifier})" class="member">
  3 + <noosfero-profile-image [profile]="member"></noosfero-profile-image>
  4 + </a>
  5 +</div>
src/app/layout/blocks/members-block/members-block.scss 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +.members-block {
  2 + .member {
  3 + img, i.profile-image {
  4 + width: 60px;
  5 + }
  6 + img {
  7 + display: inline-block;
  8 + vertical-align: top;
  9 + }
  10 + i.profile-image {
  11 + text-align: center;
  12 + background-color: #889DB1;
  13 + color: #F1F1F1;
  14 + font-size: 4.5em;
  15 + }
  16 + }
  17 +}
src/app/layout/blocks/profile-image-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./profile-image-block.component";
src/app/layout/blocks/profile-image-block/profile-image-block.component.spec.ts 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {ProfileImageBlockComponent} from './profile-image-block.component';
  5 +
  6 +import * as helpers from "./../../../../spec/helpers";
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +const htmlTemplate: string = '<noosfero-profile-image-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-profile-image-block>';
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Profile Image Block Component", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ProfileImageBlockComponent],
  22 + providers: helpers.provideFilters("translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + block = { type: 'Block' };
  26 + owner = { name: 'profile-name' };
  27 + constructor() {
  28 + }
  29 + }
  30 +
  31 + it("show image if present", () => {
  32 + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {
  33 + let elProfile = fixture.debugElement.componentViewChildren[0];
  34 + expect(elProfile.query('div.profile-image-block').length).toEqual(1);
  35 + });
  36 + });
  37 +
  38 + it("has link to the profile", () => {
  39 + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {
  40 + let elProfile = fixture.debugElement.componentViewChildren[0];
  41 + expect(elProfile.query('a.settings-link').length).toEqual(1);
  42 + });
  43 + });
  44 +
  45 + });
  46 +});
src/app/layout/blocks/profile-image-block/profile-image-block.component.ts 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +import {Inject, Input, Component} from "ng-forward";
  2 +import {ProfileImageComponent} from "./../../../profile/image/image.component";
  3 +
  4 +@Component({
  5 + selector: "noosfero-profile-image-block",
  6 + templateUrl: 'app/layout/blocks/profile-image-block/profile-image-block.html',
  7 + directives: [ProfileImageComponent]
  8 +})
  9 +export class ProfileImageBlockComponent {
  10 +
  11 + @Input() block: noosfero.Block;
  12 + @Input() owner: noosfero.Profile;
  13 +
  14 +}
src/app/layout/blocks/profile-image-block/profile-image-block.html 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<div class="center-block text-center profile-image-block">
  2 + <a ui-sref="main.profile.info({profile: ctrl.owner.identifier})">
  3 + <noosfero-profile-image [profile]="ctrl.owner"></noosfero-profile-image>
  4 + </a>
  5 + <a class="settings-link" target="_self" ui-sref="main.profile.settings({profile: ctrl.owner.identifier})">{{"blocks.profile_image.control_panel" | translate}}</a>
  6 +</div>
src/app/layout/blocks/profile-image-block/profile-image-block.scss 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +.profile-image-block {
  2 + .settings-link {
  3 + display: block;
  4 + }
  5 +}
src/app/layout/blocks/raw-html/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./raw-html.component";
src/app/layout/blocks/raw-html/raw-html.component.spec.ts 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Component} from 'ng-forward';
  3 +
  4 +import {RawHTMLBlockComponent} from './raw-html.component';
  5 +
  6 +const tcb = new TestComponentBuilder();
  7 +
  8 +const htmlTemplate: string = '<noosfero-raw-htmlblock [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-raw-htmlblock>';
  9 +
  10 +describe("Components", () => {
  11 +
  12 + describe("Raw Html Block Component", () => {
  13 +
  14 + beforeEach(angular.mock.module("templates"));
  15 + beforeEach(angular.mock.module("ngSanitize"));
  16 +
  17 + it("display html stored in block settings", done => {
  18 +
  19 + @Component({
  20 + selector: 'test-container-component',
  21 + template: htmlTemplate,
  22 + directives: [RawHTMLBlockComponent],
  23 + })
  24 + class CustomBlockType {
  25 + block: any = { settings: { html: '<em>block content</em>' } };
  26 + owner: any = { name: 'profile-name' };
  27 + }
  28 + tcb.createAsync(CustomBlockType).then(fixture => {
  29 + expect(fixture.debugElement.query(".raw-html-block em").text().trim()).toEqual('block content');
  30 + done();
  31 + });
  32 + });
  33 +
  34 + });
  35 +
  36 +});
src/app/layout/blocks/raw-html/raw-html.component.ts 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-raw-htmlblock",
  5 + templateUrl: 'app/layout/blocks/raw-html/raw-html.html'
  6 +})
  7 +
  8 +export class RawHTMLBlockComponent {
  9 +
  10 + @Input() block: any;
  11 + @Input() owner: any;
  12 +
  13 + html: string;
  14 +
  15 + ngOnInit() {
  16 + this.html = this.block.settings.html;
  17 + }
  18 +}
src/app/layout/blocks/raw-html/raw-html.html 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +<div class="raw-html-block" ng-bind-html="ctrl.html">
  2 +</div>
src/app/layout/blocks/recent-documents/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./recent-documents.component";
src/app/layout/blocks/recent-documents/recent-documents.component.spec.ts 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Provider, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +import {RecentDocumentsBlockComponent} from './recent-documents.component';
  5 +
  6 +const htmlTemplate: string = '<noosfero-recent-documents-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-recent-documents-block>';
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 + describe("Recent Documents Block Component", () => {
  12 +
  13 + let settingsObj = {};
  14 + let mockedArticleService = {
  15 + getByProfile: (profile: noosfero.Profile, filters: any): any => {
  16 + return Promise.resolve({ data: [{ name: "article1" }], headers: (name: string) => { return name; } });
  17 + }
  18 + };
  19 + let profile = { name: 'profile-name' };
  20 + beforeEach(angular.mock.module("templates"));
  21 +
  22 + let state = jasmine.createSpyObj("state", ["go"]);
  23 +
  24 +
  25 + function getProviders() {
  26 + return [
  27 + new Provider('$state', { useValue: state }),
  28 + new Provider('ArticleService', {
  29 + useValue: mockedArticleService
  30 + }),
  31 + ].concat(provideFilters("truncateFilter", "stripTagsFilter"));
  32 + }
  33 + let componentClass: any = null;
  34 +
  35 + function getComponent() {
  36 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [RecentDocumentsBlockComponent], providers: getProviders() })
  37 + class BlockContainerComponent {
  38 + block = { type: 'Block', settings: settingsObj };
  39 + owner = profile;
  40 + constructor() {
  41 + }
  42 + }
  43 + return BlockContainerComponent;
  44 + }
  45 +
  46 +
  47 + it("get recent documents from the article service", done => {
  48 + tcb.createAsync(getComponent()).then(fixture => {
  49 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  50 + expect(recentDocumentsBlock.documents).toEqual([{ name: "article1" }]);
  51 + done();
  52 + });
  53 + });
  54 +
  55 + it("go to article page when open a document", done => {
  56 + tcb.createAsync(getComponent()).then(fixture => {
  57 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  58 + recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });
  59 + expect(state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "identifier" });
  60 + done();
  61 + });
  62 + });
  63 +
  64 + it("it uses default limit 5 if not defined on block", done => {
  65 + settingsObj = null;
  66 + mockedArticleService = jasmine.createSpyObj("mockedArticleService", ["getByProfile"]);
  67 + (<any>mockedArticleService).mocked = true;
  68 + let thenMocked = jasmine.createSpy("then");
  69 + mockedArticleService.getByProfile = jasmine.createSpy("getByProfile").and.returnValue({then: thenMocked});
  70 + let getByProfileFunct = mockedArticleService.getByProfile;
  71 + tcb.createAsync(getComponent()).then(fixture => {
  72 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  73 + recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });
  74 + expect(getByProfileFunct).toHaveBeenCalledWith(profile, { content_type: 'TinyMceArticle', per_page: 5 });
  75 + done();
  76 + });
  77 + });
  78 +
  79 + });
  80 +});
0 \ No newline at end of file 81 \ No newline at end of file
src/app/layout/blocks/recent-documents/recent-documents.component.ts 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +import {Component, Inject, Input} from "ng-forward";
  2 +import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";
  3 +
  4 +@Component({
  5 + selector: "noosfero-recent-documents-block",
  6 + templateUrl: 'app/layout/blocks/recent-documents/recent-documents.html'
  7 +})
  8 +@Inject(ArticleService, "$state")
  9 +export class RecentDocumentsBlockComponent {
  10 +
  11 + @Input() block: any;
  12 + @Input() owner: any;
  13 +
  14 + profile: any;
  15 + documents: any;
  16 +
  17 + documentsLoaded: boolean = false;
  18 +
  19 + constructor(private articleService: ArticleService, private $state: any) {
  20 + }
  21 +
  22 + ngOnInit() {
  23 + this.profile = this.owner;
  24 + this.documents = [];
  25 +
  26 + let limit = ((this.block && this.block.settings) ? this.block.settings.limit : null) || 5;
  27 + // FIXME get all text articles
  28 + // FIXME make the getByProfile a generic method where we tell the type passing a class TinyMceArticle
  29 + // and the promise should be of type TinyMceArticle[], per example
  30 + this.articleService.getByProfile(this.profile, { content_type: 'TinyMceArticle', per_page: limit })
  31 + .then((result: noosfero.RestResult<noosfero.Article[]>) => {
  32 + this.documents = <noosfero.Article[]>result.data;
  33 + this.documentsLoaded = true;
  34 + });
  35 + }
  36 +
  37 + openDocument(article: any) {
  38 + this.$state.go("main.profile.page", { page: article.path, profile: article.profile.identifier });
  39 + }
  40 +
  41 +}
src/app/layout/blocks/recent-documents/recent-documents.html 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<div deckgrid source="ctrl.documents" class="deckgrid">
  2 + <div class="a-card panel media" ng-click="mother.ctrl.openDocument(card);">
  3 + <div class="author media-left" ng-show="card.author.image">
  4 + <img ng-src="{{card.author.image.url}}" class="img-circle">
  5 + </div>
  6 + <div class="header media-body">
  7 + <h5 class="title media-heading" ng-bind="card.title"></h5>
  8 +
  9 + <div class="subheader">
  10 + <span class="time">
  11 + <i class="fa fa-clock-o"></i> <span am-time-ago="card.created_at | dateFormat"></span>
  12 + </span>
  13 + </div>
  14 + </div>
  15 + <img ng-show="card.image" ng-src="{{card.image.url}}" class="img-responsive article-image">
  16 + <div class="post-lead" ng-bind-html="card.body | stripTags | truncate: 100: '...': true"></div>
  17 + </div>
  18 +</div>
src/app/layout/blocks/recent-documents/recent-documents.scss 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +.block.recentdocumentsblock {
  2 + .deckgrid[deckgrid]::before {
  3 + font-size: 0; /* See https://github.com/akoenig/angular-deckgrid/issues/14#issuecomment-35728861 */
  4 + visibility: hidden;
  5 + }
  6 + .author {
  7 + img {
  8 + width: 30px;
  9 + height: 30px;
  10 + }
  11 + }
  12 + .header {
  13 + .subheader {
  14 + color: #C1C1C1;
  15 + font-size: 10px;
  16 + }
  17 + }
  18 + .post-lead {
  19 + color: #8E8E8E;
  20 + font-size: 14px;
  21 + }
  22 + .article-image {
  23 + margin: 10px 0;
  24 + }
  25 +}
  26 +
  27 +.col-md-2-5 {
  28 + .deckgrid[deckgrid]::before {
  29 + content: '1 .deck-column';
  30 + }
  31 +}
  32 +
  33 +.col-md-7 {
  34 + .block.recentdocumentsblock {
  35 + background-color: transparent;
  36 + border: 0;
  37 +
  38 + .deckgrid[deckgrid]::before {
  39 + content: '3 .deck-column';
  40 + }
  41 +
  42 + .panel-heading {
  43 + display: none;
  44 + }
  45 + .panel-body {
  46 + padding: 0;
  47 + }
  48 +
  49 + .deckgrid {
  50 + .column {
  51 + float: left;
  52 + }
  53 +
  54 + .deck-column {
  55 + @extend .col-md-4;
  56 + padding: 0;
  57 +
  58 + .a-card {
  59 + padding: 10px;
  60 + margin: 3px;
  61 + }
  62 + }
  63 + }
  64 + }
  65 +}
src/app/layout/boxes/box.html 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<div ng-class="{'col-md-2-5': box.position!=1, 'col-md-7': box.position==1}">
  2 + <div ng-repeat="block in box.blocks | orderBy: 'position'" class="panel panel-default block {{block.type | lowercase}}" >
  3 + <div class="panel-heading" ng-show="block.title">
  4 + <h3 class="panel-title">{{block.title}}</h3>
  5 + </div>
  6 + <div class="panel-body">
  7 + <noosfero-block [block]="block" [owner]="ctrl.owner"></noosfero-block>
  8 + </div>
  9 + </div>
  10 +</div>
src/app/layout/boxes/boxes.component.spec.ts 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +import {Component} from 'ng-forward';
  2 +
  3 +import {BoxesComponent} from './boxes.component';
  4 +
  5 +import {
  6 + createComponentFromClass,
  7 + quickCreateComponent,
  8 + provideEmptyObjects,
  9 + createProviderToValue,
  10 + getAngularServiceFactory,
  11 + provideFilters
  12 +} from "../../../spec/helpers";
  13 +
  14 +// this htmlTemplate will be re-used between the container components in this spec file
  15 +const htmlTemplate: string = '<noosfero-boxes [boxes]="ctrl.boxes" [owner]="ctrl.profile"></noosfero-blog>';
  16 +
  17 +
  18 +describe("Boxes Component", () => {
  19 +
  20 + beforeEach(() => {
  21 + angular.mock.module("templates");
  22 + });
  23 +
  24 + @Component({
  25 + selector: 'test-container-component',
  26 + template: htmlTemplate,
  27 + directives: [BoxesComponent],
  28 + providers: []
  29 + })
  30 + class BoxesContainerComponent {
  31 + boxes: noosfero.Box[] = [
  32 + { id: 1, position: 1 },
  33 + { id: 2, position: 2 }
  34 + ];
  35 +
  36 + owner: noosfero.Profile = <noosfero.Profile> {
  37 + id: 1,
  38 + identifier: 'profile-name',
  39 + type: 'Person'
  40 + };
  41 + }
  42 +
  43 + it("renders boxes into a container", (done: Function) => {
  44 + createComponentFromClass(BoxesContainerComponent).then((fixture) => {
  45 + let boxesHtml = fixture.debugElement;
  46 + expect(boxesHtml.query('div.col-md-7').length).toEqual(1);
  47 + expect(boxesHtml.query('div.col-md-2-5').length).toEqual(1);
  48 +
  49 + done();
  50 + });
  51 + });
  52 +
  53 + it("check the boxes order", (done: Function) => {
  54 + createComponentFromClass(BoxesContainerComponent).then((fixture) => {
  55 +
  56 + let boxesComponent: BoxesComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  57 + let boxesContainer: BoxesContainerComponent = fixture.componentInstance;
  58 +
  59 + expect(boxesComponent.boxesOrder(boxesContainer.boxes[0])).toEqual(1);
  60 + expect(boxesComponent.boxesOrder(boxesContainer.boxes[1])).toEqual(0);
  61 +
  62 + done();
  63 + });
  64 + });
  65 +});
src/app/layout/boxes/boxes.component.ts 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +import {Input, Inject, Component} from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: "noosfero-boxes",
  5 + templateUrl: "app/layout/boxes/boxes.html"
  6 +})
  7 +export class BoxesComponent {
  8 +
  9 + @Input() boxes: noosfero.Box[];
  10 + @Input() owner: noosfero.Profile;
  11 +
  12 + boxesOrder(box: noosfero.Box) {
  13 + if (box.position === 2) return 0;
  14 + return box.position;
  15 + }
  16 +}
src/app/layout/boxes/boxes.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<ng-include ng-repeat="box in ctrl.boxes | orderBy: ctrl.boxesOrder" src="'app/layout/boxes/box.html'"></ng-include>
src/app/layout/boxes/boxes.scss 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +.col-md-2-5 {
  2 + @extend .col-md-3;
  3 + @media (min-width: 920px) {
  4 + width: 20.83%;
  5 + }
  6 +}
src/app/layout/boxes/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./boxes.component";
src/app/layout/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/layout/language-selector/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./language-selector.component";
src/app/layout/language-selector/language-selector.component.spec.ts 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {provide} from 'ng-forward';
  3 +
  4 +import {LanguageSelectorService} from './language-selector.component';
  5 +
  6 +import * as helpers from "../../../spec/helpers";
  7 +
  8 +describe("Components", () => {
  9 +
  10 + describe("Language Selector Component", () => {
  11 +
  12 + beforeEach(angular.mock.module("templates"));
  13 +
  14 + let translatorService: any;
  15 +
  16 + let buildComponent = (): Promise<ComponentFixture> => {
  17 + translatorService = jasmine.createSpyObj("translatorService", ["availableLanguages", "currentLanguage"]);
  18 + return helpers.quickCreateComponent({
  19 + template: "<language-selector></language-selector>",
  20 + directives: [LanguageSelectorService],
  21 + providers: [
  22 + provide('TranslatorService', {
  23 + useValue: translatorService
  24 + })
  25 + ].concat(helpers.provideFilters("translateFilter"))
  26 + });
  27 + };
  28 +
  29 + it("display language options", (done) => {
  30 + buildComponent().then(fixture => {
  31 + fixture.debugElement.getLocal("$rootScope").$apply();
  32 + expect(fixture.debugElement.queryAll('li.language').length).toEqual(2);
  33 + done();
  34 + });
  35 + });
  36 +
  37 + it("call the translator service when change the language", (done) => {
  38 + let translatorService = jasmine.createSpyObj("translatorService", ["changeLanguage"]);
  39 + let languageSelector = new LanguageSelectorService(<any>translatorService);
  40 + languageSelector.changeLanguage("en");
  41 + expect(translatorService.changeLanguage).toHaveBeenCalledWith("en");
  42 + done();
  43 + });
  44 +
  45 + });
  46 +});
src/app/layout/language-selector/language-selector.component.ts 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +import {Component, Inject} from "ng-forward";
  2 +import {TranslatorService} from "../../shared/services/translator.service";
  3 +
  4 +@Component({
  5 + selector: "language-selector",
  6 + templateUrl: "app/layout/language-selector/language-selector.html"
  7 +})
  8 +@Inject(TranslatorService)
  9 +export class LanguageSelectorService {
  10 +
  11 + constructor(private translatorService: TranslatorService) { }
  12 +
  13 + currentLanguage() {
  14 + return this.translatorService.currentLanguage();
  15 + }
  16 +
  17 + changeLanguage(language: string) {
  18 + this.translatorService.changeLanguage(language);
  19 + }
  20 +
  21 + availableLanguages() {
  22 + return this.translatorService.availableLanguages;
  23 + }
  24 +}
src/app/layout/language-selector/language-selector.html 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<li class="dropdown profile-menu" dropdown>
  2 + <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>
  3 + <span>{{"language.selector" | translate}}</span> <b class="caret"></b>
  4 + </a>
  5 + <ul class="dropdown-menu" dropdown-menu>
  6 + <li ng-repeat="(language, description) in ctrl.availableLanguages()"
  7 + class="language language-{{language}}" ng-class="{'active': language==ctrl.currentLanguage()}">
  8 + <a href="#" ng-click="ctrl.changeLanguage(language)">
  9 + {{description}}
  10 + </a>
  11 + </li>
  12 + </ul>
  13 +</li>
src/app/layout/navbar/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./navbar";
src/app/layout/navbar/navbar.directive.spec.js 0 → 100644
@@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('directive navbar', function() {
  5 + var vm;
  6 + var el;
  7 + var AUTH_EVENTS;
  8 + var $state;
  9 +
  10 + beforeEach(module('angular'));
  11 + beforeEach(inject(function($compile, $rootScope, $httpBackend, _AUTH_EVENTS_, _$state_) {
  12 + $state = _$state_;
  13 + AUTH_EVENTS = _AUTH_EVENTS_;
  14 + $httpBackend.when('POST','/api/v1/login_from_cookie').respond({});
  15 +
  16 + el = angular.element('<acme-navbar></acme-navbar>');
  17 +
  18 + $compile(el)($rootScope.$new());
  19 + $rootScope.$digest();
  20 + vm = el.isolateScope().vm;
  21 + }));
  22 +
  23 + it('should be compiled', function() {
  24 + expect(el.html()).not.toEqual(null);
  25 + });
  26 +
  27 + it('should have isolate scope object with instanciate members', function() {
  28 + expect(vm).toEqual(jasmine.any(Object));
  29 + expect(vm.currentUser).toEqual(undefined);
  30 + });
  31 +
  32 + it('should reload current state after login', function() {
  33 + spyOn($state, 'go');
  34 + el.isolateScope().$broadcast(AUTH_EVENTS.loginSuccess, {});
  35 + expect($state.go).toHaveBeenCalled();
  36 + });
  37 +
  38 + it('should open login when not logged in', function() {
  39 + spyOn(vm, 'openLogin');
  40 + vm.activate();
  41 + expect(vm.openLogin).toHaveBeenCalled();
  42 + });
  43 +
  44 + });
  45 +})();
src/app/layout/navbar/navbar.html 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +<nav class="navbar navbar-static-top navbar-inverse">
  2 + <div class="container-fluid">
  3 + <div class="navbar-header">
  4 + <button type="button" class="navbar-toggle collapsed" ng-click="isCollapsed = !isCollapsed">
  5 + <span class="sr-only">{{"navbar.toggle_menu" | translate}}</span>
  6 + <span class="icon-bar"></span>
  7 + <span class="icon-bar"></span>
  8 + <span class="icon-bar"></span>
  9 + </button>
  10 + <a class="navbar-brand" ui-sref="main">
  11 + <span class="noosfero-logo"><img src="assets/images/logo-noosfero.png"></span> {{"noosfero.name" | translate}}
  12 + </a>
  13 + </div>
  14 +
  15 + <div class="collapse navbar-collapse" id="navbar-collapse" collapse="isCollapsed">
  16 + <ul class="nav navbar-nav">
  17 + </ul>
  18 +
  19 + <ul class="nav navbar-nav navbar-right">
  20 + <li ng-show="!ctrl.currentUser">
  21 + <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>
  22 + </li>
  23 +
  24 + <li class="dropdown profile-menu" ng-show="ctrl.currentUser" dropdown>
  25 + <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>
  26 + <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image>
  27 + <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b>
  28 + </a>
  29 + <ul class="dropdown-menu" dropdown-menu>
  30 + <li>
  31 + <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>
  32 + </li>
  33 + <li>
  34 + <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>
  35 + </li>
  36 + <li class="divider"></li>
  37 + <li>
  38 + <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>
  39 + </li>
  40 + </ul>
  41 + </li>
  42 + </ul>
  43 + <ul class="nav navbar-nav navbar-right">
  44 + <language-selector class="nav navbar-nav navbar-right"></language-selector>
  45 + </ul>
  46 + <div ui-view="actions"></div>
  47 + </div>
  48 + </div>
  49 +</nav>
src/app/layout/navbar/navbar.scss 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +.navbar {
  2 +
  3 + .container-fluid {
  4 + padding-right: 12%;
  5 + padding-left: 12%;
  6 + @media (max-width: 978px) {
  7 + padding-right: 2%;
  8 + padding-left: 2%;
  9 + }
  10 +
  11 + .navbar-brand {
  12 + .noosfero-logo img {
  13 + height: 35px;
  14 + }
  15 + }
  16 +
  17 + .navbar-nav {
  18 + .profile-menu .profile-image {
  19 + img {
  20 + height: 30px;
  21 + width: 30px;
  22 + display: inline-block;
  23 + @extend .img-circle;
  24 + }
  25 + i {
  26 + font-size: 1.7em;
  27 + }
  28 + }
  29 + }
  30 + }
  31 +}
src/app/layout/navbar/navbar.spec.ts 0 → 100644
@@ -0,0 +1,187 @@ @@ -0,0 +1,187 @@
  1 +import * as helpers from "./../../../spec/helpers";
  2 +import {Navbar} from "./navbar";
  3 +
  4 +import {Injectable, Provider, provide} from "ng-forward";
  5 +
  6 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  7 +
  8 +import {SessionService, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../../login";
  9 +
  10 +
  11 +describe("Components", () => {
  12 +
  13 + describe("Navbar Component", () => {
  14 +
  15 + let user: noosfero.User = null;
  16 + let scope: any;
  17 + let $rootScope: ng.IRootScopeService;
  18 +
  19 + let modalInstance: any;
  20 + let $modal: any;
  21 + let authService: any;
  22 + let stateService: any;
  23 + let sessionService: SessionService;
  24 +
  25 + let provideFunc = provide;
  26 +
  27 + // before Each -> loading mocks on locals variables
  28 + beforeEach(() => {
  29 + user = <noosfero.User>{
  30 + id: 1,
  31 + login: "user"
  32 + };
  33 + scope = helpers.mocks.scopeWithEvents;
  34 + modalInstance = helpers.mocks.modalInstance;
  35 + $modal = helpers.mocks.$modal;
  36 + authService = helpers.mocks.authService;
  37 + stateService = jasmine.createSpyObj("$state", ["go"]);
  38 + sessionService = <any>helpers.mocks.sessionWithCurrentUser(user);
  39 + });
  40 +
  41 +
  42 + // loading the templates
  43 + beforeEach(angular.mock.module("templates"));
  44 +
  45 +
  46 + // this function allow build the fixture of the container component
  47 + // and is reused in each test
  48 + // The main idea behing not prebuild it on a general beforeEach block is
  49 + // to allow tests configure the mock services accordilly their own needs
  50 + let buildComponent = (): Promise<ComponentFixture> => {
  51 + return helpers.quickCreateComponent({
  52 + providers: [
  53 + provide('$modal', {
  54 + useValue: $modal
  55 + }),
  56 + provide('AuthService', {
  57 + useValue: authService
  58 + }),
  59 + helpers.provideEmptyObjects('moment'),
  60 + provide('$state', {
  61 + useValue: stateService
  62 + }),
  63 + provide("$scope", {
  64 + useValue: scope
  65 + }),
  66 + provide('SessionService', {
  67 + useValue: sessionService
  68 + }),
  69 + provide('AUTH_EVENTS', {
  70 + useValue: {
  71 + AUTH_EVENTS
  72 + }
  73 + }),
  74 + provide('TranslatorService', {
  75 + useValue: helpers.mocks.translatorService
  76 + })
  77 + ].concat(helpers.provideFilters("translateFilter")),
  78 + directives: [Navbar],
  79 + template: '<acme-navbar></acme-navbar>'
  80 + });
  81 + };
  82 +
  83 +
  84 + it('should get the loggedIn user', (done: Function) => {
  85 + buildComponent().then((fixture: ComponentFixture) => {
  86 + let navbarInstance: Navbar = fixture.debugElement.componentViewChildren[0].componentInstance;
  87 + expect(navbarInstance).toBeDefined();
  88 + expect(navbarInstance["currentUser"]).toEqual(user);
  89 + done();
  90 + });
  91 + });
  92 +
  93 + it('should open on click', (done: Function) => {
  94 + spyOn($modal, "open");
  95 + buildComponent().then((fixture: ComponentFixture) => {
  96 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  97 + navbarComp.openLogin();
  98 + expect($modal.open).toHaveBeenCalled();
  99 + expect($modal.open).toHaveBeenCalledWith({
  100 + templateUrl: 'app/components/auth/login.html',
  101 + controller: AuthController,
  102 + controllerAs: 'vm',
  103 + bindToController: true
  104 + });
  105 + done();
  106 + });
  107 + });
  108 +
  109 + it('should logout', (done: Function) => {
  110 + buildComponent().then((fixture: ComponentFixture) => {
  111 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  112 + spyOn(authService, "logout");
  113 + try {
  114 + navbarComp.logout();
  115 + expect(authService.logout).toHaveBeenCalled();
  116 + done();
  117 + } catch (e) {
  118 + console.error(e);
  119 + fail(e.message);
  120 + done();
  121 + }
  122 + });
  123 + });
  124 +
  125 +
  126 + it('should not activate user when logged in', (done: Function) => {
  127 + buildComponent().then((fixture: ComponentFixture) => {
  128 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  129 + spyOn(navbarComp, "openLogin");
  130 + navbarComp.activate();
  131 + expect((<any>navbarComp.openLogin).calls.count()).toBe(0);
  132 + done();
  133 + });
  134 + });
  135 +
  136 + it('should activate when user not logged in', (done: Function) => {
  137 + spyOn(sessionService, 'currentUser').and.returnValue(null);
  138 + buildComponent().then((fixture: ComponentFixture) => {
  139 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  140 + spyOn(navbarComp, "openLogin");
  141 + navbarComp.activate();
  142 + expect(navbarComp.openLogin).toHaveBeenCalled();
  143 + done();
  144 + });
  145 + });
  146 +
  147 +
  148 + it('closes the modal after login', (done: Function) => {
  149 + modalInstance = jasmine.createSpyObj("modalInstance", ["close"]);
  150 + modalInstance.close = jasmine.createSpy("close");
  151 +
  152 + $modal.open = () => {
  153 + return modalInstance;
  154 + };
  155 +
  156 + buildComponent().then((fixture: ComponentFixture) => {
  157 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  158 + let localScope: ng.IScope = navbarComp["$scope"];
  159 +
  160 + navbarComp.openLogin();
  161 + localScope.$emit(AUTH_EVENTS.loginSuccess);
  162 + expect(modalInstance.close).toHaveBeenCalled();
  163 + done();
  164 + });
  165 + });
  166 +
  167 + it('updates current user on logout', (done: Function) => {
  168 + buildComponent().then((fixture: ComponentFixture) => {
  169 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  170 + let localScope: ng.IScope = navbarComp["$scope"];
  171 +
  172 + // init navbar currentUser with some user
  173 + navbarComp["currentUser"] = user;
  174 +
  175 + // changes the current User to return null,
  176 + // and emmit the 'logoutSuccess' event
  177 + // just what happens when user logsout
  178 + sessionService.currentUser = () => { return null; };
  179 + localScope.$emit(AUTH_EVENTS.logoutSuccess);
  180 + expect(navbarComp["currentUser"]).toBeNull();
  181 + done();
  182 + });
  183 + });
  184 +
  185 +
  186 + });
  187 +});
src/app/layout/navbar/navbar.ts 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +import {Component, Inject} from "ng-forward";
  2 +import {LanguageSelectorService} from "../language-selector/language-selector.component";
  3 +
  4 +
  5 +import {SessionService, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../../login";
  6 +
  7 +@Component({
  8 + selector: "acme-navbar",
  9 + templateUrl: "app/layout/navbar/navbar.html",
  10 + directives: [LanguageSelectorService],
  11 + providers: [AuthService, SessionService]
  12 +})
  13 +@Inject("$modal", AuthService, "SessionService", "$scope", "$state")
  14 +export class Navbar {
  15 +
  16 + private currentUser: noosfero.User;
  17 + private modalInstance: any = null;
  18 + /**
  19 + *
  20 + */
  21 + constructor(
  22 + private $modal: any,
  23 + private authService: AuthService,
  24 + private session: SessionService,
  25 + private $scope: ng.IScope,
  26 + private $state: ng.ui.IStateService
  27 + ) {
  28 + this.currentUser = this.session.currentUser();
  29 +
  30 + this.$scope.$on(AUTH_EVENTS.loginSuccess, () => {
  31 + if (this.modalInstance) {
  32 + this.modalInstance.close();
  33 + this.modalInstance = null;
  34 + }
  35 +
  36 + this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth
  37 + });
  38 +
  39 + this.$scope.$on(AUTH_EVENTS.logoutSuccess, () => {
  40 + this.currentUser = this.session.currentUser();
  41 + });
  42 + }
  43 +
  44 + openLogin() {
  45 + this.modalInstance = this.$modal.open({
  46 + templateUrl: 'app/components/auth/login.html',
  47 + controller: AuthController,
  48 + controllerAs: 'vm',
  49 + bindToController: true
  50 + });
  51 + };
  52 +
  53 + logout() {
  54 + this.authService.logout();
  55 + this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth
  56 + };
  57 +
  58 +
  59 +
  60 + activate() {
  61 + if (!this.currentUser) {
  62 + this.openLogin();
  63 + }
  64 + }
  65 +
  66 +}
src/app/login/auth-events.ts 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +export interface IAuthEvents {
  2 + loginSuccess: string;
  3 + loginFailed: string;
  4 + logoutSuccess: string;
  5 +}
  6 +
  7 +export const AUTH_EVENTS: IAuthEvents = {
  8 + loginSuccess: "auth-login-success",
  9 + loginFailed: "auth-login-failed",
  10 + logoutSuccess: "auth-logout-success"
  11 +};
0 \ No newline at end of file 12 \ No newline at end of file
src/app/login/auth.controller.spec.ts 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +import {AuthController} from "./auth.controller";
  2 +import {AuthService} from "./auth.service";
  3 +
  4 +describe("Controllers", () => {
  5 +
  6 +
  7 + describe("AuthController", () => {
  8 +
  9 + it("calls authenticate on AuthService when login called", () => {
  10 +
  11 + // creating a Mock AuthService
  12 + let AuthServiceMock: AuthService = jasmine.createSpyObj("AuthService", ["login"]);
  13 +
  14 + // pass AuthServiceMock into the constructor
  15 + let authController = new AuthController(null, null, AuthServiceMock);
  16 +
  17 + // setup of authController -> set the credentials instance property
  18 + let credentials = { username: "username", password: "password" };
  19 +
  20 + authController.credentials = credentials;
  21 +
  22 + // calls the authController login method
  23 + authController.login();
  24 +
  25 + // checks if the method login of the injected AuthService has been called
  26 + expect(AuthServiceMock.login).toHaveBeenCalledWith(credentials);
  27 +
  28 + });
  29 +
  30 +
  31 +
  32 + });
  33 +});
src/app/login/auth.controller.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {AuthService} from "./auth.service";
  2 +
  3 +export class AuthController {
  4 +
  5 + static $inject = ["$log", "$stateParams", "AuthService"];
  6 +
  7 + constructor(
  8 + private $log: ng.ILogService,
  9 + private $stateParams: any,
  10 + private AuthService: AuthService
  11 + ) {
  12 +
  13 + }
  14 +
  15 + credentials: noosfero.Credentials;
  16 +
  17 + login() {
  18 + this.AuthService.login(this.credentials);
  19 + }
  20 +}
src/app/login/auth.service.spec.ts 0 → 100644
@@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
  1 +
  2 +
  3 +import {AuthService, AUTH_EVENTS} from "./";
  4 +
  5 +describe("Services", () => {
  6 +
  7 +
  8 + describe("Auth Service", () => {
  9 +
  10 + let $httpBackend: ng.IHttpBackendService;
  11 + let authService: AuthService;
  12 + let credentials: noosfero.Credentials;
  13 + let $rootScope: ng.IRootScopeService;
  14 + let user: noosfero.User;
  15 +
  16 + beforeEach(angular.mock.module("noosferoApp", ($translateProvider: angular.translate.ITranslateProvider) => {
  17 + $translateProvider.translations('en', {});
  18 + }));
  19 +
  20 + beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _$rootScope_: ng.IRootScopeService, _AuthService_: AuthService) => {
  21 + $httpBackend = _$httpBackend_;
  22 + authService = _AuthService_;
  23 + $rootScope = _$rootScope_;
  24 +
  25 + user = <noosfero.User>{
  26 + id: 1,
  27 + login: "user"
  28 + };
  29 + }));
  30 +
  31 +
  32 + describe("Succesffull login", () => {
  33 +
  34 + beforeEach(() => {
  35 + credentials = { username: "user", password: "password" };
  36 +
  37 + $httpBackend.expectPOST("/api/v1/login", "login=user&password=password").respond(200, { user: user });
  38 + });
  39 +
  40 + it("should return loggedUser", (done) => {
  41 + authService.login(credentials).then((loggedUser) => {
  42 + expect(loggedUser).toBeDefined();
  43 + done();
  44 + });
  45 + $httpBackend.flush();
  46 + expect($httpBackend.verifyNoOutstandingRequest());
  47 + });
  48 +
  49 +
  50 + it("should emit event loggin successful with user logged data", () => {
  51 +
  52 + authService.login(credentials);
  53 +
  54 + let eventEmmited: boolean = false;
  55 + $rootScope.$on(AUTH_EVENTS.loginSuccess, (event: ng.IAngularEvent, userThroughEvent: noosfero.User) => {
  56 + eventEmmited = true;
  57 + expect(userThroughEvent).toEqual(user);
  58 + });
  59 +
  60 + $httpBackend.flush();
  61 +
  62 + expect(eventEmmited).toBeTruthy(AUTH_EVENTS.loginSuccess + " was not emmited!");
  63 + });
  64 +
  65 + it("should return the current logged in user", () => {
  66 + authService.login(credentials);
  67 + $httpBackend.flush();
  68 + let actual: noosfero.User = authService.currentUser();
  69 + expect(actual).toEqual(user, "The returned user must be present");
  70 + });
  71 +
  72 + it("should not return the current user after logout", () => {
  73 + authService.logout();
  74 + let actual: any = authService.currentUser();
  75 + expect(actual).toEqual(undefined, "The returned user must not be defined");
  76 + });
  77 + });
  78 +
  79 +
  80 + });
  81 +});
src/app/login/auth.service.ts 0 → 100644
@@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +
  3 +import {NoosferoRootScope, UserResponse} from "./../shared/models/interfaces";
  4 +import {SessionService} from "./session.service";
  5 +
  6 +import {AUTH_EVENTS, IAuthEvents} from "./auth-events";
  7 +
  8 +@Injectable()
  9 +@Inject("$q", "$http", "$rootScope", "SessionService", "$log", "AUTH_EVENTS")
  10 +export class AuthService {
  11 +
  12 + constructor(private $q: ng.IQService,
  13 + private $http: ng.IHttpService,
  14 + private $rootScope: NoosferoRootScope,
  15 + private sessionService: SessionService,
  16 + private $log: ng.ILogService,
  17 + private auth_events: IAuthEvents) {
  18 +
  19 + }
  20 +
  21 + loginFromCookie() {
  22 + let url: string = '/api/v1/login_from_cookie';
  23 + return this.$http.post(url, null).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));
  24 + }
  25 +
  26 +
  27 + private loginSuccessCallback(response: ng.IHttpPromiseCallbackArg<UserResponse>) {
  28 + this.$log.debug('AuthService.login [SUCCESS] response', response);
  29 + let currentUser: noosfero.User = this.sessionService.create(response.data);
  30 + this.$rootScope.currentUser = currentUser;
  31 + this.$rootScope.$broadcast(this.auth_events.loginSuccess, currentUser);
  32 + return currentUser;
  33 + }
  34 +
  35 + login(credentials: noosfero.Credentials): ng.IPromise<noosfero.User> {
  36 + let url = '/api/v1/login';
  37 + let encodedData = 'login=' + credentials.username + '&password=' + credentials.password;
  38 + return this.$http.post(url, encodedData).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));
  39 + }
  40 +
  41 + private loginFailedCallback(response: ng.IHttpPromiseCallbackArg<any>): any {
  42 + this.$log.debug('AuthService.login [FAIL] response', response);
  43 + this.$rootScope.$broadcast(this.auth_events.loginFailed);
  44 + // return $q.reject(response);
  45 + return null;
  46 + }
  47 +
  48 + public logout() {
  49 + this.sessionService.destroy();
  50 + this.$rootScope.currentUser = undefined;
  51 + this.$rootScope.$broadcast(this.auth_events.logoutSuccess);
  52 + this.$http.jsonp('/account/logout'); // FIXME logout from noosfero to sync login state
  53 + }
  54 +
  55 + public isAuthenticated() {
  56 + return !!this.sessionService.currentUser();
  57 + }
  58 +
  59 + public currentUser(): noosfero.User {
  60 + return this.sessionService.currentUser();
  61 + }
  62 +
  63 + public isAuthorized(authorizedRoles: string | string[]) {
  64 + if (!angular.isArray(authorizedRoles)) {
  65 + authorizedRoles = [<string>authorizedRoles];
  66 + }
  67 + return (this.isAuthenticated() && authorizedRoles.indexOf(this.sessionService.currentUser().userRole) !== -1);
  68 + }
  69 +}
0 \ No newline at end of file 70 \ No newline at end of file
src/app/login/index.ts 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./auth-events";
  3 +export * from "./auth.controller";
  4 +export * from "./auth.service";
  5 +export * from "./session.service";
src/app/login/login.html 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +<div class="modal-header">
  2 + <h3 class="modal-title">{{"auth.title" | translate}}</h3>
  3 +</div>
  4 +<div class="modal-body">
  5 + <form>
  6 + <div class="form-group">
  7 + <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>
  8 + <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="vm.credentials.username">
  9 + </div>
  10 + <div class="form-group">
  11 + <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>
  12 + <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="vm.credentials.password">
  13 + </div>
  14 + <button type="submit" class="btn btn-default" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>
  15 + </form>
  16 +</div>
src/app/login/session.service.spec.ts 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +import {Component} from "ng-forward";
  2 +import {SessionService} from "./session.service";
  3 +import {fixtures, createComponentFromClass, createProviderToValue} from "./../../spec/helpers";
  4 +import {UserResponse, INoosferoLocalStorage} from "./../shared/models/interfaces";
  5 +
  6 +
  7 +describe("Services", () => {
  8 +
  9 +
  10 + describe("Session Service", () => {
  11 +
  12 + let $localStorage: INoosferoLocalStorage = null;
  13 + let $log: any;
  14 +
  15 + beforeEach(() => {
  16 + $localStorage = <INoosferoLocalStorage>{ currentUser: null };
  17 + $log = jasmine.createSpyObj('$log', ['debug']);
  18 + });
  19 +
  20 + it("method 'create()' saves the current user on $localstorage service", () => {
  21 + let session = new SessionService($localStorage, $log);
  22 + let userResponse = <UserResponse>{
  23 + user: fixtures.user
  24 + };
  25 + session.create(userResponse);
  26 + expect($localStorage.currentUser).toEqual(userResponse.user);
  27 + });
  28 +
  29 + it("method 'destroy()' clean the currentUser on $localstorage", () => {
  30 + let session = new SessionService($localStorage, $log);
  31 + let userResponse = <UserResponse>{
  32 + user: fixtures.user
  33 + };
  34 + $localStorage.currentUser = fixtures.user;
  35 + session.destroy();
  36 + expect($localStorage.currentUser).toBeUndefined();
  37 + });
  38 +
  39 + it("method 'currentUser()' returns the user recorded on $localstorage service", () => {
  40 + let session = new SessionService($localStorage, $log);
  41 + let userResponse = <UserResponse>{
  42 + user: fixtures.user
  43 + };
  44 + $localStorage.currentUser = fixtures.user;
  45 + expect(session.currentUser()).toEqual($localStorage.currentUser);
  46 + });
  47 + });
  48 +
  49 +});
0 \ No newline at end of file 50 \ No newline at end of file
src/app/login/session.service.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +import {UserResponse, INoosferoLocalStorage} from "./../shared/models/interfaces";
  3 +
  4 +@Injectable()
  5 +@Inject("$localStorage", "$log")
  6 +export class SessionService {
  7 +
  8 + constructor(private $localStorage: INoosferoLocalStorage, private $log: ng.ILogService) {
  9 +
  10 + }
  11 +
  12 + create(data: UserResponse): noosfero.User {
  13 + this.$localStorage.currentUser = data.user;
  14 + this.$log.debug('User session created.', this.$localStorage.currentUser);
  15 + return this.$localStorage.currentUser;
  16 + };
  17 +
  18 + destroy() {
  19 + delete this.$localStorage.currentUser;
  20 + this.$log.debug('User session destroyed.');
  21 + };
  22 +
  23 + currentUser(): noosfero.User {
  24 + return this.$localStorage.currentUser;
  25 + };
  26 +
  27 +}
0 \ No newline at end of file 28 \ No newline at end of file
src/app/main/main.component.ts
1 import {bundle, Component, StateConfig} from "ng-forward"; 1 import {bundle, Component, StateConfig} from "ng-forward";
2 -import {ArticleBlog} from "./../components/noosfero-articles/blog/blog.component"; 2 +import {ArticleBlogComponent} from "./../article/types/blog/blog.component";
3 3
4 -import {ArticleView} from "../components/noosfero-articles/article/article_view"; 4 +import {ArticleViewComponent} from "./../article/article-default-view.component";
5 5
6 -import {Profile} from "../profile/profile.component";  
7 -import {Boxes} from "../components/noosfero-boxes/boxes.component";  
8 -import {Block} from "../components/noosfero-blocks/block.component";  
9 -import {LinkListBlock} from "../components/noosfero-blocks/link-list/link-list.component";  
10 -import {RecentDocumentsBlock} from "../components/noosfero-blocks/recent-documents/recent-documents.component";  
11 -import {ProfileImageBlock} from "../components/noosfero-blocks/profile-image-block/profile-image-block.component";  
12 -import {RawHTMLBlock} from "../components/noosfero-blocks/raw-html/raw-html.component"; 6 +import {ProfileComponent} from "../profile/profile.component";
  7 +import {BoxesComponent} from "../layout/boxes/boxes.component";
  8 +import {BlockComponent} from "../layout/blocks/block.component";
  9 +import {LinkListBlockComponent} from "./../layout/blocks/link-list/link-list.component";
  10 +import {RecentDocumentsBlockComponent} from "../layout/blocks/recent-documents/recent-documents.component";
  11 +import {ProfileImageBlockComponent} from "../layout/blocks/profile-image-block/profile-image-block.component";
  12 +import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html.component";
13 13
14 -import {MembersBlock} from "../components/noosfero-blocks/members-block/members-block.component";  
15 -import {NoosferoTemplate} from "../components/noosfero/noosfero-template.filter";  
16 -import {DateFormat} from "../components/noosfero/date-format/date-format.filter"; 14 +import {MembersBlockComponent} from "./../layout/blocks/members-block/members-block.component";
  15 +import {NoosferoTemplate} from "../shared/pipes/noosfero-template.filter";
  16 +import {DateFormat} from "../shared/pipes/date-format.filter";
17 17
18 -import {AuthService} from "./../components/auth/auth_service";  
19 -import {Session} from "./../components/auth/session";  
20 -import {Notification} from "./../components/notification/notification.component"; 18 +import {AuthService} from "../login/auth.service";
  19 +import {SessionService} from "../login/session.service";
21 20
  21 +import {NotificationService} from "../shared/services/notification.service";
22 22
23 -import {Navbar} from "../components/navbar/navbar";  
24 23
25 -import {MainBlock} from "../components/noosfero-blocks/main-block/main-block.component"; 24 +import {Navbar} from "../layout/navbar/navbar";
  25 +
  26 +import {MainBlockComponent} from "../layout/blocks/main-block/main-block.component";
26 27
27 28
28 /** 29 /**
@@ -38,7 +39,7 @@ import {MainBlock} from &quot;../components/noosfero-blocks/main-block/main-block.com @@ -38,7 +39,7 @@ import {MainBlock} from &quot;../components/noosfero-blocks/main-block/main-block.com
38 @Component({ 39 @Component({
39 selector: 'main-content', 40 selector: 'main-content',
40 templateUrl: "app/main/main.html", 41 templateUrl: "app/main/main.html",
41 - providers: [AuthService, Session] 42 + providers: [AuthService, SessionService]
42 }) 43 })
43 export class MainContent { 44 export class MainContent {
44 45
@@ -62,11 +63,11 @@ export class MainContent { @@ -62,11 +63,11 @@ export class MainContent {
62 selector: 'main', 63 selector: 'main',
63 template: '<div ng-view></div>', 64 template: '<div ng-view></div>',
64 directives: [ 65 directives: [
65 - ArticleBlog, ArticleView, Boxes, Block, LinkListBlock,  
66 - MainBlock, RecentDocumentsBlock, Navbar, ProfileImageBlock,  
67 - MembersBlock, NoosferoTemplate, DateFormat, RawHTMLBlock 66 + ArticleBlogComponent, ArticleViewComponent, BoxesComponent, BlockComponent, LinkListBlockComponent,
  67 + MainBlockComponent, RecentDocumentsBlockComponent, Navbar, ProfileImageBlockComponent,
  68 + MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent
68 ], 69 ],
69 - providers: [AuthService, Session, Notification] 70 + providers: [AuthService, SessionService, NotificationService]
70 }) 71 })
71 @StateConfig([ 72 @StateConfig([
72 { 73 {
@@ -77,12 +78,12 @@ export class MainContent { @@ -77,12 +78,12 @@ export class MainContent {
77 { 78 {
78 url: "^/:profile", 79 url: "^/:profile",
79 abstract: true, 80 abstract: true,
80 - component: Profile, 81 + component: ProfileComponent,
81 name: 'main.profile', 82 name: 'main.profile',
82 views: { 83 views: {
83 "content": { 84 "content": {
84 templateUrl: "app/profile/profile.html", 85 templateUrl: "app/profile/profile.html",
85 - controller: Profile, 86 + controller: ProfileComponent,
86 controllerAs: "vm" 87 controllerAs: "vm"
87 } 88 }
88 } 89 }
src/app/models/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./interfaces";  
src/app/models/interfaces.ts
@@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
1 -export interface NoosferoRootScope extends ng.IScope {  
2 - currentUser: noosfero.User;  
3 -}  
4 -  
5 -export interface UserResponse {  
6 - user: noosfero.User;  
7 -}  
8 -  
9 -  
10 -export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {  
11 - currentUser: noosfero.User;  
12 -}  
src/app/profile-info/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./profile-info.component";  
src/app/profile-info/profile-info.component.spec.ts
@@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
1 -import {quickCreateComponent} from "../../spec/helpers";  
2 -import {ProfileInfo} from "./profile-info.component";  
3 -  
4 -describe("Components", () => {  
5 - describe("Profile Info Component", () => {  
6 -  
7 - let $rootScope: ng.IRootScopeService;  
8 - let $q: ng.IQService;  
9 - let profileServiceMock: any;  
10 - let $stateParams: any;  
11 -  
12 - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {  
13 - $rootScope = _$rootScope_;  
14 - $q = _$q_;  
15 - }));  
16 -  
17 - beforeEach(() => {  
18 - $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]);  
19 - profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile", "getActivities"]);  
20 -  
21 - let getCurrentProfileResponse = $q.defer();  
22 - getCurrentProfileResponse.resolve({ id: 1 });  
23 -  
24 - let getActivitiesResponse = $q.defer();  
25 - getActivitiesResponse.resolve({ data: { activities: [{ id: 1 }, { id: 2 }] } });  
26 -  
27 - profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);  
28 - profileServiceMock.getActivities = jasmine.createSpy("getActivities").and.returnValue(getActivitiesResponse.promise);  
29 - });  
30 -  
31 - it("get the profile activities", done => {  
32 - let component: ProfileInfo = new ProfileInfo(profileServiceMock);  
33 - $rootScope.$apply();  
34 - expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();  
35 - expect(profileServiceMock.getActivities).toHaveBeenCalled();  
36 - expect(component.activities).toEqual([{ id: 1 }, { id: 2 }]);  
37 - done();  
38 - });  
39 - });  
40 -});  
src/app/profile-info/profile-info.component.ts
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -import {StateConfig, Component, Inject, provide} from 'ng-forward';  
2 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
3 -  
4 -@Component({  
5 - selector: 'profile',  
6 - templateUrl: "app/profile-info/profile-info.html",  
7 - providers: [provide('profileService', { useClass: ProfileService })]  
8 -})  
9 -@Inject(ProfileService)  
10 -export class ProfileInfo {  
11 -  
12 - activities: any;  
13 - profile: noosfero.Profile;  
14 -  
15 - constructor(private profileService: ProfileService) {  
16 - this.activate();  
17 - }  
18 -  
19 - activate() {  
20 - this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {  
21 - this.profile = profile;  
22 - return this.profileService.getActivities(<number>this.profile.id);  
23 - }).then((response: restangular.IResponse) => {  
24 - this.activities = response.data.activities;  
25 - });  
26 - }  
27 -}  
src/app/profile-info/profile-info.html
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -<h3>{{vm.profile.name}}</h3>  
2 -  
3 -<div class="profile-wall">  
4 - <h4>{{"profile.wall" | translate}}</h4>  
5 - <noosfero-activities [activities]="vm.activities"></noosfero-activities>  
6 -</div>  
src/app/profile/activities/activities.component.spec.ts 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../spec/helpers';
  4 +
  5 +import {ActivitiesComponent} from './activities.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-activities [activities]="ctrl.activities"></noosfero-activities>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Noosfero Activities", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ActivitiesComponent],
  22 + providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + activities = [{ name: "activity1", verb: "create_article" }, { name: "activity2", verb: "create_article" }];
  26 + }
  27 +
  28 + it("render a noosfero activity tag for each activity", done => {
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + expect(fixture.debugElement.queryAll("noosfero-activity").length).toEqual(2);
  31 + done();
  32 + });
  33 + });
  34 + });
  35 +
  36 +});
src/app/profile/activities/activities.component.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {Component, Input} from "ng-forward";
  2 +import {ActivityComponent} from "./activity/activity.component";
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name NoosferoActivities
  7 + * @description
  8 + * The controller responsible to retreive profile activities.
  9 + */
  10 +
  11 +@Component({
  12 + selector: "noosfero-activities",
  13 + templateUrl: 'app/profile/activities/activities.html',
  14 + directives: [ActivityComponent]
  15 +})
  16 +export class ActivitiesComponent {
  17 +
  18 + /**
  19 + * @ngdoc property
  20 + * @propertyOf NoosferoActivities
  21 + * @name activities
  22 + * @returns {Activity[]} An array of {@link Activity}.
  23 + */
  24 + @Input() activities: noosfero.Activity[];
  25 +
  26 +
  27 +}
src/app/profile/activities/activities.html 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<timeline>
  2 + <timeline-event ng-repeat="activity in ctrl.activities | orderBy: 'created_at':true">
  3 + <noosfero-activity [activity]="activity"></noosfero-activity>
  4 + </timeline-event>
  5 +</timeline>
src/app/profile/activities/activities.scss 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +.comma-separated {
  2 + .separated-item {
  3 + &:after {
  4 + content: ", ";
  5 + margin-left: -3px;
  6 + }
  7 + &:last-child:after {
  8 + content: "";
  9 + }
  10 + }
  11 +}
src/app/profile/activities/activity/activity.component.spec.ts 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +
  5 +import {ActivityComponent} from './activity.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-activity [activity]="ctrl.activity"></noosfero-activity>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Noosfero Activity", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ActivityComponent],
  22 + providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + activity = { name: "activity1", verb: "create_article" };
  26 + }
  27 +
  28 + it("render the specific template for an activity verb", done => {
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + let component: ActivityComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  31 + expect(component.getActivityTemplate()).toEqual('app/profile/activities/activity/create_article.html');
  32 + expect(fixture.debugElement.queryAll(".activity.create_article").length).toEqual(1);
  33 + done();
  34 + });
  35 + });
  36 + });
  37 +
  38 +});
src/app/profile/activities/activity/activity.component.ts 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-activity",
  5 + templateUrl: 'app/profile/activities/activity/activity.html'
  6 +})
  7 +export class ActivityComponent {
  8 +
  9 + @Input() activity: noosfero.Activity;
  10 +
  11 + getActivityTemplate() {
  12 + return 'app/profile/activities/activity/' + this.activity.verb + '.html';
  13 + }
  14 +
  15 +}
src/app/profile/activities/activity/activity.html 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<div class="activity {{ctrl.activity.verb}}">
  2 + <ng-include src="ctrl.getActivityTemplate()"></ng-include>
  3 +</div>
src/app/profile/activities/activity/add_member_in_community.html 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<timeline-badge class="info">
  2 + <i class="fa fa-user-plus"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  6 + <h4 class="timeline-title">
  7 + <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>
  8 + <span> {{"activities.add_member_in_community.description" | translate}}</span>
  9 + </h4>
  10 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  11 + </timeline-heading>
  12 + <div class="timeline-body"></div>
  13 +</timeline-panel>
src/app/profile/activities/activity/create_article.html 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +<timeline-badge class="success">
  2 + <i class="fa fa-file-text"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  6 + <h4 class="timeline-title">
  7 + <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>
  8 + <span> {{"activities.create_article.description" | translate}} </span>
  9 + <a ui-sref="main.profile.info({profile: ctrl.activity.target.article.profile.identifier})">
  10 + <strong ng-bind="ctrl.activity.target.article.profile.name"></strong></span>
  11 + </a>
  12 + </h4>
  13 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  14 + </timeline-heading>
  15 + <div class="timeline-body">
  16 + <div class="article">
  17 + <div class="title">
  18 + <a ui-sref="main.profile.page({profile: ctrl.activity.target.article.profile.identifier, page: ctrl.activity.target.article.path})"
  19 + ng-bind="ctrl.activity.target.article.title"></a>
  20 + </div>
  21 + <div class="lead small">
  22 + <div ng-bind-html="ctrl.activity.target.article.body | stripTags | truncate: 100 : '...': true"></div>
  23 + </div>
  24 + </div>
  25 + </div>
  26 +</timeline-panel>
src/app/profile/activities/activity/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./activity.component";
src/app/profile/activities/activity/new_friendship.html 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<timeline-badge class="info">
  2 + <i class="fa fa-user-plus"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  6 + <h4 class="timeline-title">
  7 + <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a>
  8 + <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length}:"messageformat" }} </span>
  9 + <span class="comma-separated">
  10 + <a class="separated-item" ui-sref="main.profile.info({profile: ctrl.activity.params.friend_url[$index].profile})" ng-repeat="friend in ctrl.activity.params.friend_name">
  11 + <strong ng-bind="friend"></strong>
  12 + </a>
  13 + </span>
  14 + </h4>
  15 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  16 + </timeline-heading>
  17 + <div class="timeline-body"></div>
  18 +</timeline-panel>
src/app/profile/activities/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./activities.component";
src/app/profile/image/image.component.spec.ts 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +/**
  2 + * @ngdoc overview
  3 + * @name components.noosfero.profile-image.ProfileImageSpec
  4 + * @description
  5 + * This file contains the tests for the {@link components.noosfero.profile-image.ProfileImage} component.
  6 + */
  7 +
  8 +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  9 +import {Pipe, Input, provide, Component} from 'ng-forward';
  10 +
  11 +import * as helpers from "../../../spec/helpers";
  12 +
  13 +import {ProfileImageComponent} from "./image.component";
  14 +
  15 +const tcb = new TestComponentBuilder();
  16 +
  17 +describe("Components", () => {
  18 +
  19 + describe("Profile Image Component", () => {
  20 +
  21 + beforeEach(angular.mock.module("templates"));
  22 +
  23 + it("show community users image if profile is not Person", done => {
  24 + helpers.tcb.createAsync(ProfileImageComponent).then(fixture => {
  25 + let profileImageComponent: ProfileImageComponent = fixture.componentInstance;
  26 + let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Community" };
  27 + profileImageComponent.profile = profile;
  28 + profileImageComponent.ngOnInit();
  29 +
  30 + // Check the attribute
  31 + expect(profileImageComponent.defaultIcon).toBe("fa-users", "The default icon should be community users");
  32 + // var elProfile = fixture.debugElement.componentViewChildren[0];
  33 + // expect(elProfile.query('div.profile-image-block').length).toEqual(1);
  34 + done();
  35 + });
  36 + });
  37 +
  38 + it("show Person image if profile is Person", done => {
  39 + tcb.createAsync(ProfileImageComponent).then(fixture => {
  40 + let profileImageComponent: ProfileImageComponent = fixture.componentInstance;
  41 + let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Person" };
  42 + profileImageComponent.profile = profile;
  43 + profileImageComponent.ngOnInit();
  44 + // Check the attribute
  45 + expect(profileImageComponent.defaultIcon).toEqual("fa-user", "The default icon should be person user");
  46 + done();
  47 + });
  48 + });
  49 +
  50 + });
  51 +});
0 \ No newline at end of file 52 \ No newline at end of file
src/app/profile/image/image.component.ts 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +import {Inject, Input, Component} from "ng-forward";
  2 +
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name components.noosfero.profile-image.ProfileImage
  7 + * @description The component responsible for rendering the profile image
  8 + * @exports ProfileImage
  9 + */
  10 +@Component({
  11 + selector: "noosfero-profile-image",
  12 + templateUrl: 'app/profile/image/image.html',
  13 +})
  14 +export class ProfileImageComponent {
  15 +
  16 + /**
  17 + * @ngdoc property
  18 + * @name profile
  19 + * @propertyOf components.noosfero.profile-image.ProfileImage
  20 + * @description
  21 + * The Noosfero {@link models.Profile} holding the image.
  22 + */
  23 + @Input() profile: noosfero.Profile;
  24 + /**
  25 + * @ngdoc property
  26 + * @name defaultIcon
  27 + * @propertyOf components.noosfero.profile-image.ProfileImage
  28 + * @descritpion
  29 + * The default icon used by this profile
  30 + */
  31 + defaultIcon: string;
  32 +
  33 + /**
  34 + * @ngdoc method
  35 + * @name ngOnInit
  36 + * @methodOf components.noosfero.profile-image.ProfileImage
  37 + * @description
  38 + * Initializes the icon names to their corresponding values depending on the profile type passed to the controller
  39 + */
  40 + ngOnInit() {
  41 + this.defaultIcon = 'fa-users';
  42 + if (this.profile && this.profile.type === 'Person') {
  43 + this.defaultIcon = 'fa-user';
  44 + }
  45 + }
  46 +}
  47 +
src/app/profile/image/image.html 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<span title="{{ctrl.profile.name}}">
  2 + <img ng-if="ctrl.profile.image" ng-src="{{ctrl.profile.image.url}}" class="img-responsive profile-image">
  3 + <i ng-if="!ctrl.profile.image" class="fa {{ctrl.defaultIcon}} fa-5x profile-image"></i>
  4 +</span>
src/app/profile/image/image.scss 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +i.profile-image {
  2 + color: rgb(44, 62, 80);
  3 +}
src/app/profile/image/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./image.component";
src/app/profile/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 "./myprofile.component";
2 export * from "./profile-home.component"; 3 export * from "./profile-home.component";
3 export * from "./profile.component"; 4 export * from "./profile.component";
src/app/profile/info/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./profile-info.component";
src/app/profile/info/profile-info.component.spec.ts 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {ProfileInfoComponent} from "./profile-info.component";
  3 +
  4 +describe("Components", () => {
  5 + describe("Profile Info Component", () => {
  6 +
  7 + let $rootScope: ng.IRootScopeService;
  8 + let $q: ng.IQService;
  9 + let profileServiceMock: any;
  10 + let $stateParams: any;
  11 +
  12 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  13 + $rootScope = _$rootScope_;
  14 + $q = _$q_;
  15 + }));
  16 +
  17 + beforeEach(() => {
  18 + $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]);
  19 + profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile", "getActivities"]);
  20 +
  21 + let getCurrentProfileResponse = $q.defer();
  22 + getCurrentProfileResponse.resolve({ id: 1 });
  23 +
  24 + let getActivitiesResponse = $q.defer();
  25 + getActivitiesResponse.resolve({ data: { activities: [{ id: 1 }, { id: 2 }] } });
  26 +
  27 + profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);
  28 + profileServiceMock.getActivities = jasmine.createSpy("getActivities").and.returnValue(getActivitiesResponse.promise);
  29 + });
  30 +
  31 + it("get the profile activities", done => {
  32 + let component: ProfileInfoComponent = new ProfileInfoComponent(profileServiceMock);
  33 + $rootScope.$apply();
  34 + expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();
  35 + expect(profileServiceMock.getActivities).toHaveBeenCalled();
  36 + expect(component.activities).toEqual([{ id: 1 }, { id: 2 }]);
  37 + done();
  38 + });
  39 + });
  40 +});
src/app/profile/info/profile-info.component.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {StateConfig, Component, Inject, provide} from 'ng-forward';
  2 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: 'profile',
  6 + templateUrl: "app/profile-info/profile-info.html",
  7 + providers: [provide('profileService', { useClass: ProfileService })]
  8 +})
  9 +@Inject(ProfileService)
  10 +export class ProfileInfoComponent {
  11 +
  12 + activities: any;
  13 + profile: noosfero.Profile;
  14 +
  15 + constructor(private profileService: ProfileService) {
  16 + this.activate();
  17 + }
  18 +
  19 + activate() {
  20 + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  21 + this.profile = profile;
  22 + return this.profileService.getActivities(<number>this.profile.id);
  23 + }).then((response: restangular.IResponse) => {
  24 + this.activities = response.data.activities;
  25 + });
  26 + }
  27 +}
src/app/profile/info/profile-info.html 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<h3>{{vm.profile.name}}</h3>
  2 +
  3 +<div class="profile-wall">
  4 + <h4>{{"profile.wall" | translate}}</h4>
  5 + <noosfero-activities [activities]="vm.activities"></noosfero-activities>
  6 +</div>
src/app/profile/profile.component.spec.ts
1 import {quickCreateComponent} from "../../spec/helpers"; 1 import {quickCreateComponent} from "../../spec/helpers";
2 -import {Profile} from "./profile.component"; 2 +import {ProfileComponent} from "./profile.component";
3 3
4 describe("Components", () => { 4 describe("Components", () => {
5 describe("Profile Component", () => { 5 describe("Profile Component", () => {
@@ -30,7 +30,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -30,7 +30,7 @@ describe(&quot;Components&quot;, () =&gt; {
30 }); 30 });
31 31
32 it("get the profile and store in profile service", done => { 32 it("get the profile and store in profile service", done => {
33 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 33 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
34 $rootScope.$apply(); 34 $rootScope.$apply();
35 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); 35 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
36 expect(component.profile).toEqual({ id: 1 }); 36 expect(component.profile).toEqual({ id: 1 });
@@ -38,7 +38,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -38,7 +38,7 @@ describe(&quot;Components&quot;, () =&gt; {
38 }); 38 });
39 39
40 it("get the profile boxes", done => { 40 it("get the profile boxes", done => {
41 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 41 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
42 $rootScope.$apply(); 42 $rootScope.$apply();
43 expect(profileServiceMock.getBoxes).toHaveBeenCalled(); 43 expect(profileServiceMock.getBoxes).toHaveBeenCalled();
44 expect(component.boxes).toEqual([{ id: 2 }]); 44 expect(component.boxes).toEqual([{ id: 2 }]);
@@ -50,7 +50,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -50,7 +50,7 @@ describe(&quot;Components&quot;, () =&gt; {
50 profileResponse.reject(); 50 profileResponse.reject();
51 profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(profileResponse.promise); 51 profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(profileResponse.promise);
52 52
53 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 53 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
54 $rootScope.$apply(); 54 $rootScope.$apply();
55 55
56 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); 56 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
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 {ProfileInfo} from '../profile-info/profile-info.component';  
3 -import {ProfileHome} from '../profile/profile-home.component';  
4 -import {Cms} from '../cms/cms.component';  
5 -import {ContentViewer} from "../content-viewer/content-viewer.component";  
6 -import {ContentViewerActions} from "../content-viewer/content-viewer-actions.component";  
7 -import {NoosferoActivities} from "../components/noosfero-activities/activities.component"; 2 +import {ProfileInfoComponent} from './info/profile-info.component';
  3 +import {ProfileHome} from './profile-home.component';
  4 +import {BasicEditorComponent} from '../article/basic-editor.component';
  5 +import {ContentViewerComponent} from "../article/content-viewer/content-viewer.component";
  6 +import {ContentViewerActions} from "../article/content-viewer/content-viewer-actions.component";
  7 +import {ActivitiesComponent} from "./activities/activities.component";
8 import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; 8 import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";
9 -import {Notification} from "../components/notification/notification.component"; 9 +import {NotificationService} from "../shared/services/notification.service";
10 import {MyProfile} from "./myprofile.component"; 10 import {MyProfile} from "./myprofile.component";
11 11
12 12
@@ -20,21 +20,21 @@ import {MyProfile} from &quot;./myprofile.component&quot;; @@ -20,21 +20,21 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
20 @Component({ 20 @Component({
21 selector: 'profile', 21 selector: 'profile',
22 templateUrl: "app/profile/profile.html", 22 templateUrl: "app/profile/profile.html",
23 - directives: [NoosferoActivities], 23 + directives: [ActivitiesComponent],
24 providers: [ 24 providers: [
25 provide('profileService', { useClass: ProfileService }), 25 provide('profileService', { useClass: ProfileService }),
26 - provide('notification', { useClass: Notification }) 26 + provide('notificationService', { useClass: NotificationService })
27 ] 27 ]
28 }) 28 })
29 @StateConfig([ 29 @StateConfig([
30 { 30 {
31 name: 'main.profile.info', 31 name: 'main.profile.info',
32 url: "^/profile/:profile", 32 url: "^/profile/:profile",
33 - component: ProfileInfo, 33 + component: ProfileInfoComponent,
34 views: { 34 views: {
35 "mainBlockContent": { 35 "mainBlockContent": {
36 templateUrl: "app/profile-info/profile-info.html", 36 templateUrl: "app/profile-info/profile-info.html",
37 - controller: ProfileInfo, 37 + controller: ProfileInfoComponent,
38 controllerAs: "vm" 38 controllerAs: "vm"
39 } 39 }
40 } 40 }
@@ -47,11 +47,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;; @@ -47,11 +47,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
47 { 47 {
48 name: 'main.profile.cms', 48 name: 'main.profile.cms',
49 url: "^/myprofile/:profile/cms", 49 url: "^/myprofile/:profile/cms",
50 - component: Cms, 50 + component: BasicEditorComponent,
51 views: { 51 views: {
52 "mainBlockContent": { 52 "mainBlockContent": {
53 - templateUrl: "app/cms/cms.html",  
54 - controller: Cms, 53 + templateUrl: "app/article/basic-editor.html",
  54 + controller: BasicEditorComponent,
55 controllerAs: "vm" 55 controllerAs: "vm"
56 } 56 }
57 } 57 }
@@ -70,11 +70,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;; @@ -70,11 +70,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
70 { 70 {
71 name: 'main.profile.page', 71 name: 'main.profile.page',
72 url: "/{page:any}", 72 url: "/{page:any}",
73 - component: ContentViewer, 73 + component: ContentViewerComponent,
74 views: { 74 views: {
75 "mainBlockContent": { 75 "mainBlockContent": {
76 templateUrl: "app/content-viewer/page.html", 76 templateUrl: "app/content-viewer/page.html",
77 - controller: ContentViewer, 77 + controller: ContentViewerComponent,
78 controllerAs: "vm" 78 controllerAs: "vm"
79 }, 79 },
80 "actions@main": { 80 "actions@main": {
@@ -86,19 +86,19 @@ import {MyProfile} from &quot;./myprofile.component&quot;; @@ -86,19 +86,19 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
86 } 86 }
87 ]) 87 ])
88 @Inject(ProfileService, "$stateParams") 88 @Inject(ProfileService, "$stateParams")
89 -export class Profile { 89 +export class ProfileComponent {
90 90
91 boxes: noosfero.Box[]; 91 boxes: noosfero.Box[];
92 profile: noosfero.Profile; 92 profile: noosfero.Profile;
93 93
94 - constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService, notification: Notification) { 94 + constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService, notificationService: NotificationService) {
95 profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosfero.Profile) => { 95 profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosfero.Profile) => {
96 this.profile = profile; 96 this.profile = profile;
97 return profileService.getBoxes(<number>this.profile.id); 97 return profileService.getBoxes(<number>this.profile.id);
98 }).then((response: restangular.IResponse) => { 98 }).then((response: restangular.IResponse) => {
99 this.boxes = response.data.boxes; 99 this.boxes = response.data.boxes;
100 }).catch(() => { 100 }).catch(() => {
101 - notification.error("notification.profile.not_found"); 101 + notificationService.error("notification.profile.not_found");
102 }); 102 });
103 } 103 }
104 } 104 }
src/app/profile/profile.scss
1 .profile-container { 1 .profile-container {
2 @extend .container-fluid; 2 @extend .container-fluid;
3 - padding: 0 12%; 3 + padding: 0 1%;
4 @media (max-width: 978px) { 4 @media (max-width: 978px) {
5 padding: 0 2%; 5 padding: 0 2%;
6 } 6 }
src/app/registration/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/components/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/models/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./interfaces";
src/app/shared/models/interfaces.ts 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +export interface NoosferoRootScope extends ng.IScope {
  2 + currentUser: noosfero.User;
  3 +}
  4 +
  5 +export interface UserResponse {
  6 + user: noosfero.User;
  7 +}
  8 +
  9 +
  10 +export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {
  11 + currentUser: noosfero.User;
  12 +}
src/app/shared/pipes/date-format.filter.spec.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {DateFormat} from './date-format.filter';
  3 +
  4 +describe("Filters", () => {
  5 + describe("Date Format Filter", () => {
  6 +
  7 + beforeEach(angular.mock.module("templates"));
  8 + beforeEach(angular.mock.module("angularMoment"));
  9 +
  10 + it("convert date from the format returned by noosfero api to an ISO format", done => {
  11 + let date = "2016/03/10 10:46:47";
  12 + let htmlTemplate = `{{ '${date}' | dateFormat }}`;
  13 + quickCreateComponent({ providers: [DateFormat], template: htmlTemplate }).then(fixture => {
  14 + expect(fixture.debugElement.text()).toEqual('2016-03-10T13:46:47.000Z');
  15 + done();
  16 + });
  17 + });
  18 +
  19 + });
  20 +});
src/app/shared/pipes/date-format.filter.ts 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +import {Pipe, Inject} from "ng-forward";
  2 +
  3 +@Pipe("dateFormat")
  4 +@Inject("amParseFilter")
  5 +export class DateFormat {
  6 +
  7 + constructor(private amParseFilter: any) { }
  8 +
  9 + transform(date: string, options: any) {
  10 + return this.amParseFilter(date, "YYYY/MM/DD HH:mm:ss").toISOString();
  11 + }
  12 +
  13 +}
src/app/shared/pipes/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./date-format.filter";
  3 +export * from "./noosfero-template.filter";
src/app/shared/pipes/noosfero-template.filter.spec.ts 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {NoosferoTemplate} from './noosfero-template.filter';
  3 +
  4 +describe("Filters", () => {
  5 + describe("Noosfero Template Filter", () => {
  6 +
  7 + beforeEach(angular.mock.module("templates"));
  8 +
  9 + it("replace the options in text with the values passed on options", done => {
  10 + let text = 'profile: {profile}, other: {other}';
  11 + let htmlTemplate = `{{ '${text}' | noosferoTemplate: {profile: 'profile1', other: 'other value'} }}`;
  12 + quickCreateComponent({ providers: [NoosferoTemplate], template: htmlTemplate }).then(fixture => {
  13 + expect(fixture.debugElement.text()).toEqual("profile: profile1, other: other value");
  14 + done();
  15 + });
  16 + });
  17 +
  18 + });
  19 +});
src/app/shared/pipes/noosfero-template.filter.ts 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +import {Pipe} from "ng-forward";
  2 +
  3 +@Pipe("noosferoTemplate")
  4 +export class NoosferoTemplate {
  5 +
  6 + transform(text: string, options: any) {
  7 + for (let option in options) {
  8 + text = text.replace('{' + option + '}', options[option]);
  9 + }
  10 + return text;
  11 + }
  12 +
  13 +}
src/app/shared/services/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./notification.service";
  3 +export * from "./translator.service";
src/app/shared/services/notification.service.spec.ts 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +
  4 +import * as helpers from "../../../spec/helpers";
  5 +
  6 +import {NotificationService} from "./notification.service";
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 +
  12 + describe("Profile Image Component", () => {
  13 +
  14 + beforeEach(angular.mock.module("templates"));
  15 +
  16 + it("display an error message when notify an error", done => {
  17 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  18 + sweetAlert.swal = jasmine.createSpy("swal");
  19 +
  20 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  21 + component.error("message", "title");
  22 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  23 + text: "message",
  24 + title: "title",
  25 + type: "error"
  26 + }));
  27 + done();
  28 + });
  29 +
  30 + it("use the default message when call notification component without a message", done => {
  31 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  32 + sweetAlert.swal = jasmine.createSpy("swal");
  33 +
  34 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  35 + component.error();
  36 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  37 + text: NotificationService.DEFAULT_ERROR_MESSAGE,
  38 + type: "error"
  39 + }));
  40 + done();
  41 + });
  42 +
  43 + it("display a success message when call notification success", done => {
  44 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  45 + sweetAlert.swal = jasmine.createSpy("swal");
  46 +
  47 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  48 + component.success("title", "message", 1000);
  49 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  50 + type: "success"
  51 + }));
  52 + done();
  53 + });
  54 +
  55 + it("display a message relative to the http error code", done => {
  56 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  57 + sweetAlert.swal = jasmine.createSpy("swal");
  58 +
  59 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  60 + component.httpError(500, {});
  61 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  62 + text: "notification.http_error.500.message"
  63 + }));
  64 + done();
  65 + });
  66 +
  67 + it("set the default timer in success messages", done => {
  68 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  69 + sweetAlert.swal = jasmine.createSpy("swal");
  70 +
  71 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  72 + component.success("title", "message");
  73 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  74 + type: "success",
  75 + timer: NotificationService.DEFAULT_SUCCESS_TIMER
  76 + }));
  77 + done();
  78 + });
  79 + });
  80 +});
src/app/shared/services/notification.service.ts 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +import {TranslatorService} from "./translator.service";
  3 +
  4 +@Injectable()
  5 +@Inject("$log", "SweetAlert", TranslatorService)
  6 +export class NotificationService {
  7 +
  8 + constructor(
  9 + private $log: ng.ILogService,
  10 + private SweetAlert: any,
  11 + private translatorService: TranslatorService
  12 + ) { }
  13 +
  14 + public static DEFAULT_ERROR_TITLE = "notification.error.default.title";
  15 + public static DEFAULT_ERROR_MESSAGE = "notification.error.default.message";
  16 + public static DEFAULT_SUCCESS_TIMER = 1000;
  17 +
  18 + error(message: string = NotificationService.DEFAULT_ERROR_MESSAGE, title: string = NotificationService.DEFAULT_ERROR_TITLE) {
  19 + this.$log.debug("Notification error:", title, message, this.translatorService.currentLanguage());
  20 + this.SweetAlert.swal({
  21 + title: this.translatorService.translate(title),
  22 + text: this.translatorService.translate(message),
  23 + type: "error"
  24 + });
  25 + }
  26 +
  27 + httpError(status: number, data: any): boolean {
  28 + this.error(`notification.http_error.${status}.message`);
  29 + return true; // return true to indicate that the error was already handled
  30 + }
  31 +
  32 + success(title: string, text: string, timer: number = NotificationService.DEFAULT_SUCCESS_TIMER) {
  33 + this.SweetAlert.swal({
  34 + title: title,
  35 + text: text,
  36 + type: "success",
  37 + timer: timer
  38 + });
  39 + }
  40 +
  41 +}
src/app/shared/services/translator.service.spec.ts 0 → 100644
@@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
  1 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {provide} from 'ng-forward';
  3 +
  4 +import {TranslatorService} from './translator.service';
  5 +
  6 +import * as helpers from "../../../spec/helpers";
  7 +
  8 +describe("Services", () => {
  9 +
  10 + describe("Translator Service", () => {
  11 +
  12 + let $rootScope: ng.IScope;
  13 + let $q: ng.IQService;
  14 +
  15 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  16 + $rootScope = _$rootScope_;
  17 + $q = _$q_;
  18 + }));
  19 +
  20 + function createComponent() {
  21 + return new TranslatorService(
  22 + <any>helpers.mocks.$translate,
  23 + <any>helpers.mocks.tmhDynamicLocale,
  24 + <any>helpers.mocks.amMoment,
  25 + <any>helpers.mocks.angularLoad,
  26 + $rootScope
  27 + );
  28 + }
  29 +
  30 + it("set available languages when change language", (done) => {
  31 + let component: TranslatorService = createComponent();
  32 + component.availableLanguages = null;
  33 + expect(component.availableLanguages).toBeNull();
  34 + $rootScope.$emit("$translateChangeSuccess");
  35 + expect(component.availableLanguages).not.toBeNull();
  36 + done();
  37 + });
  38 +
  39 + it("change the language", (done) => {
  40 + let component: TranslatorService = createComponent();
  41 + let loadScripPromise = $q.defer();
  42 + loadScripPromise.resolve();
  43 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);
  44 + component["tmhDynamicLocale"].set = jasmine.createSpy("set");
  45 + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");
  46 + component["$translate"].use = jasmine.createSpy("use");
  47 +
  48 + component.changeLanguage('pt');
  49 + $rootScope.$digest();
  50 +
  51 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
  52 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");
  53 + expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");
  54 + expect(component["$translate"].use).toHaveBeenCalledWith("pt");
  55 + done();
  56 + });
  57 +
  58 + it("do not load moment locale when change the language to english", (done) => {
  59 + let component: TranslatorService = createComponent();
  60 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue($q.defer().promise);
  61 + component.changeLanguage('en');
  62 + expect(component["angularLoad"].loadScript).not.toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
  63 + done();
  64 + });
  65 +
  66 + it("do nothing when call change language with null", (done) => {
  67 + let component: TranslatorService = createComponent();
  68 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript");
  69 + component["tmhDynamicLocale"].set = jasmine.createSpy("set");
  70 + component["$translate"].use = jasmine.createSpy("use");
  71 +
  72 + component.changeLanguage(null);
  73 +
  74 + expect(component["angularLoad"].loadScript).not.toHaveBeenCalled();
  75 + expect(component["tmhDynamicLocale"].set).not.toHaveBeenCalled();
  76 + expect(component["$translate"].use).not.toHaveBeenCalled();
  77 + done();
  78 + });
  79 +
  80 + it("return the current language used by the translator", (done) => {
  81 + let component: TranslatorService = createComponent();
  82 + component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");
  83 + expect(component.currentLanguage()).toEqual("en");
  84 + expect(component["$translate"].use).toHaveBeenCalled();
  85 + done();
  86 + });
  87 +
  88 + it("call translate service when translate a text", (done) => {
  89 + let component: TranslatorService = createComponent();
  90 + component["$translate"].instant = jasmine.createSpy("instant");
  91 + component.translate("text");
  92 + expect(component["$translate"].instant).toHaveBeenCalledWith("text");
  93 + done();
  94 + });
  95 +
  96 + it("change the language when receive an event", (done) => {
  97 + let component: TranslatorService = createComponent();
  98 + component.changeLanguage = jasmine.createSpy("changeLanguage");
  99 + $rootScope.$emit("$localeChangeSuccess");
  100 + expect(component.changeLanguage).toHaveBeenCalled();
  101 + done();
  102 + });
  103 +
  104 + it("use the translate language when receive a change language event and there is no language previously selected", (done) => {
  105 + let component: TranslatorService = createComponent();
  106 + component.changeLanguage = jasmine.createSpy("changeLanguage");
  107 + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue(null);
  108 + component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");
  109 +
  110 + $rootScope.$emit("$localeChangeSuccess");
  111 + expect(component["$translate"].use).toHaveBeenCalled();
  112 + expect(component.changeLanguage).toHaveBeenCalledWith("en");
  113 + done();
  114 + });
  115 + });
  116 +});
src/app/shared/services/translator.service.ts 0 → 100644
@@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +
  3 +@Injectable()
  4 +@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad", "$rootScope")
  5 +export class TranslatorService {
  6 +
  7 + availableLanguages: any;
  8 +
  9 + constructor(private $translate: angular.translate.ITranslateService,
  10 + private tmhDynamicLocale: angular.dynamicLocale.tmhDynamicLocaleService,
  11 + private amMoment: any,
  12 + private angularLoad: any,
  13 + private $rootScope: any) {
  14 +
  15 + this.$rootScope.$on("$localeChangeSuccess", () => {
  16 + this.changeLanguage(tmhDynamicLocale.get() || $translate.use());
  17 + });
  18 + this.$rootScope.$on("$translateChangeSuccess", () => {
  19 + this.configAvailableLanguages();
  20 + });
  21 + }
  22 +
  23 + currentLanguage() {
  24 + return this.$translate.use();
  25 + }
  26 +
  27 + changeLanguage(language: string) {
  28 + if (!language) {
  29 + console.log("WARN: language undefined");
  30 + return;
  31 + }
  32 + this.changeMomentLocale(language);
  33 + this.tmhDynamicLocale.set(language);
  34 + this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {
  35 + return this.$translate.use(language);
  36 + });
  37 + }
  38 +
  39 + translate(text: string) {
  40 + return this.$translate.instant(text);
  41 + }
  42 +
  43 + private configAvailableLanguages() {
  44 + this.availableLanguages = {
  45 + "en": this.$translate.instant("language.en"),
  46 + "pt": this.$translate.instant("language.pt")
  47 + };
  48 + }
  49 +
  50 + private changeMomentLocale(language: string) {
  51 + let localePromise = Promise.resolve();
  52 + if (language !== "en") {
  53 + localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);
  54 + }
  55 + localePromise.then(() => {
  56 + this.amMoment.changeLocale(language);
  57 + });
  58 + }
  59 +}