Skip to content

Commit 7728029

Browse files
Andrea BarbassoFrancescoMolinaro
authored andcommitted
Merged in task/dspace-cris-2023_02_x/DSC-1667 (pull request DSpace#2532)
[DSC-1667] add html and longhtml rendering types Approved-by: Francesco Molinaro
2 parents 1c2f45e + 88b988b commit 7728029

10 files changed

Lines changed: 268 additions & 1 deletion

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div [class]="field.styleValue">
2+
<span [innerHTML]="processHtml(metadataValue.value)" class="text-value"></span>
3+
</div>

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/html/html.component.scss

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
3+
import { By } from '@angular/platform-browser';
4+
5+
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
6+
7+
import { HtmlComponent } from './html.component';
8+
import { Item } from '../../../../../../../core/shared/item.model';
9+
import { TranslateLoaderMock } from '../../../../../../../shared/mocks/translate-loader.mock';
10+
import { DsDatePipe } from '../../../../../../pipes/ds-date.pipe';
11+
import { LayoutField } from '../../../../../../../core/layout/models/box.model';
12+
import { MetadataValue } from '../../../../../../../core/shared/metadata.models';
13+
14+
describe('HtmlComponent', () => {
15+
let component: HtmlComponent;
16+
let fixture: ComponentFixture<HtmlComponent>;
17+
18+
const metadataValue = Object.assign(new MetadataValue(), {
19+
'value': 'test item title',
20+
'language': null,
21+
'authority': null,
22+
'confidence': -1,
23+
'place': 0
24+
});
25+
26+
const testItem = Object.assign(new Item(),
27+
{
28+
type: 'item',
29+
metadata: {
30+
'dc.title': [metadataValue]
31+
},
32+
uuid: 'test-item-uuid',
33+
}
34+
);
35+
36+
37+
const mockField: LayoutField = {
38+
'metadata': 'dc.title',
39+
'label': 'Title',
40+
'rendering': 'html',
41+
'fieldType': 'METADATA',
42+
'style': null,
43+
'styleLabel': 'test-style-label',
44+
'styleValue': 'test-style-value',
45+
'labelAsHeading': false,
46+
'valuesInline': true
47+
};
48+
49+
beforeEach(waitForAsync(() => {
50+
TestBed.configureTestingModule({
51+
imports: [TranslateModule.forRoot({
52+
loader: {
53+
provide: TranslateLoader,
54+
useClass: TranslateLoaderMock
55+
}
56+
}), BrowserAnimationsModule],
57+
providers: [
58+
{ provide: 'fieldProvider', useValue: mockField },
59+
{ provide: 'itemProvider', useValue: testItem },
60+
{ provide: 'metadataValueProvider', useValue: metadataValue },
61+
{ provide: 'renderingSubTypeProvider', useValue: '' },
62+
{ provide: 'tabNameProvider', useValue: '' },
63+
],
64+
declarations: [HtmlComponent, DsDatePipe]
65+
})
66+
.compileComponents();
67+
}));
68+
69+
beforeEach(() => {
70+
fixture = TestBed.createComponent(HtmlComponent);
71+
component = fixture.componentInstance;
72+
fixture.detectChanges();
73+
});
74+
75+
it('should create', () => {
76+
expect(component).toBeTruthy();
77+
});
78+
79+
it('check metadata rendering', (done) => {
80+
const spanValueFound = fixture.debugElement.queryAll(By.css('span.text-value'));
81+
expect(spanValueFound.length).toBe(1);
82+
expect(spanValueFound[0].nativeElement.textContent).toContain(metadataValue.value);
83+
done();
84+
});
85+
86+
it('check value style', (done) => {
87+
const spanValueFound = fixture.debugElement.queryAll(By.css('.test-style-value'));
88+
expect(spanValueFound.length).toBe(1);
89+
done();
90+
});
91+
92+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Component } from '@angular/core';
2+
3+
import { FieldRenderingType, MetadataBoxFieldRendering } from '../metadata-box.decorator';
4+
import { RenderingTypeValueModelComponent } from '../rendering-type-value.model';
5+
6+
/**
7+
* This component renders the text metadata fields
8+
*/
9+
@Component({
10+
// eslint-disable-next-line @angular-eslint/component-selector
11+
selector: 'span[ds-html]',
12+
templateUrl: './html.component.html',
13+
styleUrls: ['./html.component.scss']
14+
})
15+
@MetadataBoxFieldRendering(FieldRenderingType.HTML)
16+
export class HtmlComponent extends RenderingTypeValueModelComponent {
17+
18+
/**
19+
* If the metadata value does not contain HTML tags then replace newline character with <br>
20+
* @param text
21+
*/
22+
processHtml(text: string): string {
23+
const htmlTagRegex = /<.*?>/;
24+
return htmlTagRegex.test(text) ? text.replace(/\n/, '<br>') : text;
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div [class]="field.styleValue">
2+
<ds-truncatable [id]="truncatableId">
3+
<ds-truncatable-part [id]="truncatableId" [minLines]="8">
4+
<span [innerHTML]="processHtml(metadataValue.value)" class="text-value"></span>
5+
</ds-truncatable-part>
6+
</ds-truncatable>
7+
</div>

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/longhtml/longhtml.component.scss

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
3+
import { By } from '@angular/platform-browser';
4+
5+
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
6+
7+
import { LonghtmlComponent } from './longhtml.component';
8+
import { Item } from '../../../../../../../core/shared/item.model';
9+
import { TranslateLoaderMock } from '../../../../../../../shared/mocks/translate-loader.mock';
10+
import { DsDatePipe } from '../../../../../../pipes/ds-date.pipe';
11+
import { LayoutField } from '../../../../../../../core/layout/models/box.model';
12+
import { MetadataValue } from '../../../../../../../core/shared/metadata.models';
13+
14+
describe('LonghtmlComponent', () => {
15+
let component: LonghtmlComponent;
16+
let fixture: ComponentFixture<LonghtmlComponent>;
17+
18+
const metadataValue = Object.assign(new MetadataValue(), {
19+
'value': 'test item title',
20+
'language': null,
21+
'authority': null,
22+
'confidence': -1,
23+
'place': 0
24+
});
25+
26+
const testItem = Object.assign(new Item(),
27+
{
28+
type: 'item',
29+
metadata: {
30+
'dc.title': [metadataValue]
31+
},
32+
uuid: 'test-item-uuid',
33+
}
34+
);
35+
36+
37+
const mockField: LayoutField = {
38+
'metadata': 'dc.title',
39+
'label': 'Title',
40+
'rendering': 'html',
41+
'fieldType': 'METADATA',
42+
'style': null,
43+
'styleLabel': 'test-style-label',
44+
'styleValue': 'test-style-value',
45+
'labelAsHeading': false,
46+
'valuesInline': true
47+
};
48+
49+
beforeEach(waitForAsync(() => {
50+
TestBed.configureTestingModule({
51+
imports: [TranslateModule.forRoot({
52+
loader: {
53+
provide: TranslateLoader,
54+
useClass: TranslateLoaderMock
55+
}
56+
}), BrowserAnimationsModule],
57+
providers: [
58+
{ provide: 'fieldProvider', useValue: mockField },
59+
{ provide: 'itemProvider', useValue: testItem },
60+
{ provide: 'metadataValueProvider', useValue: metadataValue },
61+
{ provide: 'renderingSubTypeProvider', useValue: '' },
62+
{ provide: 'tabNameProvider', useValue: '' },
63+
],
64+
declarations: [LonghtmlComponent, DsDatePipe]
65+
})
66+
.compileComponents();
67+
}));
68+
69+
beforeEach(() => {
70+
fixture = TestBed.createComponent(LonghtmlComponent);
71+
component = fixture.componentInstance;
72+
fixture.detectChanges();
73+
});
74+
75+
it('should create', () => {
76+
expect(component).toBeTruthy();
77+
});
78+
79+
it('check metadata rendering', (done) => {
80+
const spanValueFound = fixture.debugElement.queryAll(By.css('span.text-value'));
81+
expect(spanValueFound.length).toBe(1);
82+
expect(spanValueFound[0].nativeElement.textContent).toContain(metadataValue.value);
83+
done();
84+
});
85+
86+
it('check value style', (done) => {
87+
const spanValueFound = fixture.debugElement.queryAll(By.css('.test-style-value'));
88+
expect(spanValueFound.length).toBe(1);
89+
done();
90+
});
91+
92+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Component, OnInit } from '@angular/core';
2+
3+
import { FieldRenderingType, MetadataBoxFieldRendering } from '../metadata-box.decorator';
4+
import { RenderingTypeValueModelComponent } from '../rendering-type-value.model';
5+
6+
/**
7+
* This component renders the text metadata fields with a show more button
8+
*/
9+
@Component({
10+
// eslint-disable-next-line @angular-eslint/component-selector
11+
selector: 'span[ds-longhtml]',
12+
templateUrl: './longhtml.component.html',
13+
styleUrls: ['./longhtml.component.scss']
14+
})
15+
@MetadataBoxFieldRendering(FieldRenderingType.LONGHTML)
16+
export class LonghtmlComponent extends RenderingTypeValueModelComponent implements OnInit {
17+
18+
/**
19+
* Id for truncatable component
20+
*/
21+
truncatableId: string;
22+
23+
ngOnInit(): void {
24+
this.truncatableId = `${this.item.id}_${this.field.metadata}_html`;
25+
}
26+
27+
/**
28+
* If the metadata value does not contain HTML tags then replace newline character with <br>
29+
* @param text
30+
*/
31+
processHtml(text: string): string {
32+
const htmlTagRegex = /<.*?>/;
33+
return htmlTagRegex.test(text) ? text.replace(/\n/, '<br>') : text;
34+
}
35+
36+
}

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/metadata-box.decorator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export enum FieldRenderingType {
1616
ORCID = 'ORCID',
1717
TAG = 'TAG',
1818
VALUEPAIR = 'VALUEPAIR',
19+
HTML = 'HTML',
20+
LONGHTML = 'LONGHTML',
1921
ADVANCEDATTACHMENT = 'ADVANCEDATTACHMENT',
2022
SIMPLEATTACHMENT = 'SIMPLEATTACHMENT',
2123
AUTHORITYLINK = 'AUTHORITYLINK',

src/app/cris-layout/cris-layout.module.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ import { CrisLayoutCollectionBoxComponent } from './cris-layout-matrix/cris-layo
114114
import {
115115
LinkAuthorityComponent
116116
} from './cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/link-authority/link-authority.component';
117+
import {
118+
HtmlComponent
119+
} from './cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/html/html.component';
120+
import {
121+
LonghtmlComponent
122+
} from './cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/longhtml/longhtml.component';
117123

118124
const ENTRY_COMPONENTS = [
119125
// put only entry components that use custom decorator
@@ -139,7 +145,9 @@ const ENTRY_COMPONENTS = [
139145
ValuepairComponent,
140146
TagComponent,
141147
AdvancedAttachmentComponent,
142-
LinkAuthorityComponent
148+
LinkAuthorityComponent,
149+
HtmlComponent,
150+
LonghtmlComponent,
143151
];
144152

145153
@NgModule({

0 commit comments

Comments
 (0)