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 3 "files.exclude": {
4 4 "**/.git": true,
5 5 "**/.DS_Store": true,
6   - "src/app/*.js": false
  6 + "src/**/*.js": true,
  7 + "src/**/*.js.map": true,
  8 + "coverage": true
7 9 },
8 10 "editor.fontSize": 14,
9 11 "typescript.useCodeSnippetsOnMethodSuggest": true
... ...
src/app/admin/index.ts 0 → 100644
... ... @@ -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 @@
  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 109 \ No newline at end of file
... ...
src/app/article/article-default-view.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 130 \ No newline at end of file
... ...
src/app/article/types/blog/blog.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
... ...
src/app/cms/cms.component.spec.ts
... ... @@ -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   -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   -<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   -/* 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   -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   -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   -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 0 \ No newline at end of file
src/app/components/auth/auth_service.spec.ts
... ... @@ -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   -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 0 \ No newline at end of file
src/app/components/auth/index.ts
... ... @@ -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   -<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   -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 0 \ No newline at end of file
src/app/components/auth/session_spec.ts
... ... @@ -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 0 \ No newline at end of file
src/app/components/index.ts
... ... @@ -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   -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   -<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   -/* 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   -(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   -<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   -.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   -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   -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   -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   -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   -<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   -.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   -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   -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   -<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   -<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   -<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   -/* 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   -<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   -/* Module Index Entry - generated using the script npm run generate-index */
src/app/components/noosfero-articles/article/article.html
... ... @@ -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   -.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   -
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 0 \ No newline at end of file
src/app/components/noosfero-articles/article/article_view.ts
... ... @@ -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   -/* 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   -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 0 \ No newline at end of file
src/app/components/noosfero-articles/blog/blog.component.ts
... ... @@ -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   -<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   -.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   -/* 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   -/* 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   -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 0 \ No newline at end of file
src/app/components/noosfero-blocks/block.component.ts
... ... @@ -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   -.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   -/* 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   -/* 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   -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 0 \ No newline at end of file
src/app/components/noosfero-blocks/link-list/link-list.component.ts
... ... @@ -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   -<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   -.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   -/* 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   -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 0 \ No newline at end of file
src/app/components/noosfero-blocks/main-block/main-block.component.ts
... ... @@ -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   -<div ui-view="mainBlockContent" autoscroll></div>
src/app/components/noosfero-blocks/members-block/index.ts
... ... @@ -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   -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 0 \ No newline at end of file
src/app/components/noosfero-blocks/members-block/members-block.component.ts
... ... @@ -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   -<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   -.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   -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   -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   -<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   -.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   -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   -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   -<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   -/* 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   -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 0 \ No newline at end of file
src/app/components/noosfero-blocks/recent-documents/recent-documents.component.ts
... ... @@ -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   -<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   -.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   -<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   -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   -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   -<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   -.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   -/* 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   -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   -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   -/* 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   -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   -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   -/**
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   -/**
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 0 \ No newline at end of file
src/app/components/noosfero/profile-image/profile-image.component.ts
... ... @@ -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   -<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   -i.profile-image {
2   - color: rgb(44, 62, 80);
3   -}
src/app/components/notification/notification.component.spec.ts
... ... @@ -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   -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   -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   -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   -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   -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   -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   -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   -/* 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   -<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   -<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 4 /** @ngInject */
5 5 export function noosferoAngularRunBlock(
6 6 $log: ng.ILogService,
7 7 Restangular: restangular.IService,
8   - Session: Session,
9   - Notification: Notification
  8 + SessionService: SessionService,
  9 + NotificationService: NotificationService
10 10 ) {
11 11  
12 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 16 return <any>{ headers: <any>headers };
17 17 });
18 18 Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => {
19 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 5 import {Main} from "./main/main.component";
6 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 13 declare var moment: any;
14 14  
... ...
src/app/layout/blocks/block.component.spec.ts 0 → 100644
... ... @@ -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 92 \ No newline at end of file
... ...
src/app/layout/blocks/block.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 66 \ No newline at end of file
... ...
src/app/layout/blocks/link-list/link-list.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 41 \ No newline at end of file
... ...
src/app/layout/blocks/main-block/main-block.component.ts 0 → 100644
... ... @@ -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 @@
  1 +<div ui-view="mainBlockContent" autoscroll></div>
... ...
src/app/layout/blocks/members-block/index.ts 0 → 100644
... ... @@ -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 @@
  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 54 \ No newline at end of file
... ...
src/app/layout/blocks/members-block/members-block.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 81 \ No newline at end of file
... ...
src/app/layout/blocks/recent-documents/recent-documents.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 12 \ No newline at end of file
... ...
src/app/login/auth.controller.spec.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 70 \ No newline at end of file
... ...
src/app/login/index.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 50 \ No newline at end of file
... ...
src/app/login/session.service.ts 0 → 100644
... ... @@ -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 28 \ No newline at end of file
... ...
src/app/main/main.component.ts
1 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 39 @Component({
39 40 selector: 'main-content',
40 41 templateUrl: "app/main/main.html",
41   - providers: [AuthService, Session]
  42 + providers: [AuthService, SessionService]
42 43 })
43 44 export class MainContent {
44 45  
... ... @@ -62,11 +63,11 @@ export class MainContent {
62 63 selector: 'main',
63 64 template: '<div ng-view></div>',
64 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 72 @StateConfig([
72 73 {
... ... @@ -77,12 +78,12 @@ export class MainContent {
77 78 {
78 79 url: "^/:profile",
79 80 abstract: true,
80   - component: Profile,
  81 + component: ProfileComponent,
81 82 name: 'main.profile',
82 83 views: {
83 84 "content": {
84 85 templateUrl: "app/profile/profile.html",
85   - controller: Profile,
  86 + controller: ProfileComponent,
86 87 controllerAs: "vm"
87 88 }
88 89 }
... ...
src/app/models/index.ts
... ... @@ -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   -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   -/* 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   -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   -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   -<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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 52 \ No newline at end of file
... ...
src/app/profile/image/image.component.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  1 +i.profile-image {
  2 + color: rgb(44, 62, 80);
  3 +}
... ...
src/app/profile/image/index.ts 0 → 100644
... ... @@ -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 1 /* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./myprofile.component";
2 3 export * from "./profile-home.component";
3 4 export * from "./profile.component";
... ...
src/app/profile/info/index.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 1 import {quickCreateComponent} from "../../spec/helpers";
2   -import {Profile} from "./profile.component";
  2 +import {ProfileComponent} from "./profile.component";
3 3  
4 4 describe("Components", () => {
5 5 describe("Profile Component", () => {
... ... @@ -30,7 +30,7 @@ describe(&quot;Components&quot;, () =&gt; {
30 30 });
31 31  
32 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 34 $rootScope.$apply();
35 35 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
36 36 expect(component.profile).toEqual({ id: 1 });
... ... @@ -38,7 +38,7 @@ describe(&quot;Components&quot;, () =&gt; {
38 38 });
39 39  
40 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 42 $rootScope.$apply();
43 43 expect(profileServiceMock.getBoxes).toHaveBeenCalled();
44 44 expect(component.boxes).toEqual([{ id: 2 }]);
... ... @@ -50,7 +50,7 @@ describe(&quot;Components&quot;, () =&gt; {
50 50 profileResponse.reject();
51 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 54 $rootScope.$apply();
55 55  
56 56 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
... ...
src/app/profile/profile.component.ts
1 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 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 10 import {MyProfile} from "./myprofile.component";
11 11  
12 12  
... ... @@ -20,21 +20,21 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
20 20 @Component({
21 21 selector: 'profile',
22 22 templateUrl: "app/profile/profile.html",
23   - directives: [NoosferoActivities],
  23 + directives: [ActivitiesComponent],
24 24 providers: [
25 25 provide('profileService', { useClass: ProfileService }),
26   - provide('notification', { useClass: Notification })
  26 + provide('notificationService', { useClass: NotificationService })
27 27 ]
28 28 })
29 29 @StateConfig([
30 30 {
31 31 name: 'main.profile.info',
32 32 url: "^/profile/:profile",
33   - component: ProfileInfo,
  33 + component: ProfileInfoComponent,
34 34 views: {
35 35 "mainBlockContent": {
36 36 templateUrl: "app/profile-info/profile-info.html",
37   - controller: ProfileInfo,
  37 + controller: ProfileInfoComponent,
38 38 controllerAs: "vm"
39 39 }
40 40 }
... ... @@ -47,11 +47,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
47 47 {
48 48 name: 'main.profile.cms',
49 49 url: "^/myprofile/:profile/cms",
50   - component: Cms,
  50 + component: BasicEditorComponent,
51 51 views: {
52 52 "mainBlockContent": {
53   - templateUrl: "app/cms/cms.html",
54   - controller: Cms,
  53 + templateUrl: "app/article/basic-editor.html",
  54 + controller: BasicEditorComponent,
55 55 controllerAs: "vm"
56 56 }
57 57 }
... ... @@ -70,11 +70,11 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
70 70 {
71 71 name: 'main.profile.page',
72 72 url: "/{page:any}",
73   - component: ContentViewer,
  73 + component: ContentViewerComponent,
74 74 views: {
75 75 "mainBlockContent": {
76 76 templateUrl: "app/content-viewer/page.html",
77   - controller: ContentViewer,
  77 + controller: ContentViewerComponent,
78 78 controllerAs: "vm"
79 79 },
80 80 "actions@main": {
... ... @@ -86,19 +86,19 @@ import {MyProfile} from &quot;./myprofile.component&quot;;
86 86 }
87 87 ])
88 88 @Inject(ProfileService, "$stateParams")
89   -export class Profile {
  89 +export class ProfileComponent {
90 90  
91 91 boxes: noosfero.Box[];
92 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 95 profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosfero.Profile) => {
96 96 this.profile = profile;
97 97 return profileService.getBoxes(<number>this.profile.id);
98 98 }).then((response: restangular.IResponse) => {
99 99 this.boxes = response.data.boxes;
100 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 1 .profile-container {
2 2 @extend .container-fluid;
3   - padding: 0 12%;
  3 + padding: 0 1%;
4 4 @media (max-width: 978px) {
5 5 padding: 0 2%;
6 6 }
... ...
src/app/registration/index.ts 0 → 100644
... ... @@ -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 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
... ...
src/app/shared/index.ts 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 +}
... ...