Commit 9b3a27c9804db1b9a5d72e43ca85b6579815de3f
1 parent
da32e022
Exists in
master
and in
26 other branches
refactoring recent documents block
Showing
10 changed files
with
206 additions
and
206 deletions
Show diff stats
src/app/layout/blocks/recent-documents/index.ts
src/app/layout/blocks/recent-documents/recent-documents-block.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-block.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 | +}); | ... | ... |
src/app/layout/blocks/recent-documents/recent-documents-block.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-block.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-block.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-block.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/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 {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 | -}); | |
| 81 | 0 | \ No newline at end of file |
src/app/layout/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/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
| ... | ... | @@ -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/layout/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/main/main.component.ts
| ... | ... | @@ -11,7 +11,7 @@ import {EnvironmentComponent} from "../environment/environment.component"; |
| 11 | 11 | import {EnvironmentHomeComponent} from "../environment/environment-home.component"; |
| 12 | 12 | import {PeopleBlockComponent} from "../layout/blocks/people/people-block.component"; |
| 13 | 13 | import {LinkListBlockComponent} from "./../layout/blocks/link-list/link-list-block.component"; |
| 14 | -import {RecentDocumentsBlockComponent} from "../layout/blocks/recent-documents/recent-documents.component"; | |
| 14 | +import {RecentDocumentsBlockComponent} from "../layout/blocks/recent-documents/recent-documents-block.component"; | |
| 15 | 15 | import {ProfileImageBlockComponent} from "../layout/blocks/profile-image/profile-image-block.component"; |
| 16 | 16 | import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html-block.component"; |
| 17 | 17 | ... | ... |