mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-09-10 14:11:42 +00:00
AAE-37906 Extract rich text parsing service (#11164)
* AAE-37906 Extract rich text parsing service * AAE-37906 Add unit tests * AAE-37906 Remove unused import * AAE-37906 Fix units
This commit is contained in:
@@ -18,12 +18,14 @@
|
|||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { DisplayRichTextWidgetComponent } from './display-rich-text.widget';
|
import { DisplayRichTextWidgetComponent, RICH_TEXT_PARSER_TOKEN } from './display-rich-text.widget';
|
||||||
|
import { RichTextParserService } from '../../../services/rich-text-parser.service';
|
||||||
|
|
||||||
describe('DisplayRichTextWidgetComponent', () => {
|
describe('DisplayRichTextWidgetComponent', () => {
|
||||||
let widget: DisplayRichTextWidgetComponent;
|
let widget: DisplayRichTextWidgetComponent;
|
||||||
let fixture: ComponentFixture<DisplayRichTextWidgetComponent>;
|
let fixture: ComponentFixture<DisplayRichTextWidgetComponent>;
|
||||||
let debugEl: DebugElement;
|
let debugEl: DebugElement;
|
||||||
|
let mockRichTextParserService: jasmine.SpyObj<RichTextParserService>;
|
||||||
|
|
||||||
const cssSelector = {
|
const cssSelector = {
|
||||||
parsedHTML: '.adf-display-rich-text-widget-parsed-html'
|
parsedHTML: '.adf-display-rich-text-widget-parsed-html'
|
||||||
@@ -79,8 +81,14 @@ describe('DisplayRichTextWidgetComponent', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
mockRichTextParserService = jasmine.createSpyObj('RichTextParserService', ['parse']);
|
||||||
|
mockRichTextParserService.parse.and.returnValue(
|
||||||
|
'<h1>Editor.js</h1><p class="ce-tune-alignment--left">Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>'
|
||||||
|
);
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [DisplayRichTextWidgetComponent]
|
imports: [DisplayRichTextWidgetComponent],
|
||||||
|
providers: [{ provide: RICH_TEXT_PARSER_TOKEN, useValue: mockRichTextParserService }]
|
||||||
});
|
});
|
||||||
fixture = TestBed.createComponent(DisplayRichTextWidgetComponent);
|
fixture = TestBed.createComponent(DisplayRichTextWidgetComponent);
|
||||||
widget = fixture.componentInstance;
|
widget = fixture.componentInstance;
|
||||||
@@ -88,6 +96,13 @@ describe('DisplayRichTextWidgetComponent', () => {
|
|||||||
widget.field = fakeFormField;
|
widget.field = fakeFormField;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call RichTextParserService.parse() method', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(mockRichTextParserService.parse).toHaveBeenCalledWith(fakeFormField.value);
|
||||||
|
expect(mockRichTextParserService.parse).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('should parse editorjs data to html', async () => {
|
it('should parse editorjs data to html', async () => {
|
||||||
const expectedHtml =
|
const expectedHtml =
|
||||||
'<h1>Editor.js</h1><p class="ce-tune-alignment--left">Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>';
|
'<h1>Editor.js</h1><p class="ce-tune-alignment--left">Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>';
|
||||||
|
@@ -17,10 +17,14 @@
|
|||||||
|
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
import { Component, OnInit, SecurityContext, ViewEncapsulation } from '@angular/core';
|
import { Component, inject, InjectionToken, OnInit, SecurityContext, ViewEncapsulation } from '@angular/core';
|
||||||
import { WidgetComponent, FormService } from '@alfresco/adf-core';
|
import { WidgetComponent, FormService } from '@alfresco/adf-core';
|
||||||
import edjsHTML from 'editorjs-html';
|
|
||||||
import { DomSanitizer } from '@angular/platform-browser';
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
import { RichTextParserService } from '../../../services/rich-text-parser.service';
|
||||||
|
|
||||||
|
export const RICH_TEXT_PARSER_TOKEN = new InjectionToken<RichTextParserService>('RichTextParserService', {
|
||||||
|
factory: () => new RichTextParserService()
|
||||||
|
});
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'display-rich-text',
|
selector: 'display-rich-text',
|
||||||
@@ -40,39 +44,22 @@ import { DomSanitizer } from '@angular/platform-browser';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class DisplayRichTextWidgetComponent extends WidgetComponent implements OnInit {
|
export class DisplayRichTextWidgetComponent extends WidgetComponent implements OnInit {
|
||||||
parsedHTML: any;
|
parsedHTML: string | Error;
|
||||||
|
|
||||||
private static readonly CUSTOM_PARSER = {
|
private readonly richTextParserService = inject(RICH_TEXT_PARSER_TOKEN);
|
||||||
header: (block: any): string => {
|
private readonly sanitizer = inject(DomSanitizer);
|
||||||
const paragraphAlign = block.data.alignment || block.data.align || block.tunes?.anyTuneName?.alignment;
|
|
||||||
if (typeof paragraphAlign !== 'undefined' && ['left', 'right', 'center'].includes(paragraphAlign)) {
|
|
||||||
return `<h${block.data.level} class="ce-tune-alignment--${paragraphAlign}">${block.data.text}</h${block.data.level}>`;
|
|
||||||
} else {
|
|
||||||
return `<h${block.data.level}>${block.data.text}</h${block.data.level}>`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
paragraph: (block: any): string => {
|
|
||||||
const paragraphAlign = block.data.alignment || block.data.align || block.tunes?.anyTuneName?.alignment;
|
|
||||||
|
|
||||||
if (typeof paragraphAlign !== 'undefined' && ['left', 'right', 'center', 'justify'].includes(paragraphAlign)) {
|
constructor(formService: FormService) {
|
||||||
return `<p class="ce-tune-alignment--${paragraphAlign}">${block.data.text}</p>`;
|
|
||||||
} else {
|
|
||||||
return `<p>${block.data.text}</p>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(public formService: FormService, private readonly sanitizer: DomSanitizer) {
|
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.parsedHTML = edjsHTML(DisplayRichTextWidgetComponent.CUSTOM_PARSER, { strict: true }).parse(this.field.value);
|
this.parsedHTML = this.richTextParserService.parse(this.field.value);
|
||||||
|
|
||||||
if (!(this.parsedHTML instanceof Error)) {
|
if (this.parsedHTML instanceof Error) {
|
||||||
this.sanitizeHtmlContent();
|
|
||||||
} else {
|
|
||||||
throw this.parsedHTML;
|
throw this.parsedHTML;
|
||||||
|
} else {
|
||||||
|
this.sanitizeHtmlContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RichTextParserService } from './rich-text-parser.service';
|
||||||
|
|
||||||
|
describe('RichTextParserService', () => {
|
||||||
|
it('should test CUSTOM_PARSER.header method works correctly', () => {
|
||||||
|
const block = { data: { text: 'Test Header', level: 2, alignment: 'center' } };
|
||||||
|
const result = (RichTextParserService as any).CUSTOM_PARSER.header(block);
|
||||||
|
expect(result).toBe('<h2 class="ce-tune-alignment--center">Test Header</h2>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should test CUSTOM_PARSER.paragraph method works correctly', () => {
|
||||||
|
const block = { data: { text: 'Test paragraph text', alignment: 'justify' } };
|
||||||
|
const result = (RichTextParserService as any).CUSTOM_PARSER.paragraph(block);
|
||||||
|
expect(result).toBe('<p class="ce-tune-alignment--justify">Test paragraph text</p>');
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import edjsHTML from 'editorjs-html';
|
||||||
|
|
||||||
|
export interface OutputData {
|
||||||
|
version?: string;
|
||||||
|
time?: number;
|
||||||
|
blocks: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RichTextParserService {
|
||||||
|
private static readonly CUSTOM_PARSER = {
|
||||||
|
header: (block: any): string => {
|
||||||
|
if (!block.data || !block.data.text || !block.data.level) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const paragraphAlign = block.data.alignment || block.data.align || block.tunes?.anyTuneName?.alignment;
|
||||||
|
if (typeof paragraphAlign !== 'undefined' && ['left', 'right', 'center'].includes(paragraphAlign)) {
|
||||||
|
return `<h${block.data.level} class="ce-tune-alignment--${paragraphAlign}">${block.data.text}</h${block.data.level}>`;
|
||||||
|
} else {
|
||||||
|
return `<h${block.data.level}>${block.data.text}</h${block.data.level}>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paragraph: (block: any): string => {
|
||||||
|
if (!block.data || !block.data.text) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const paragraphAlign = block.data.alignment || block.data.align || block.tunes?.anyTuneName?.alignment;
|
||||||
|
|
||||||
|
if (typeof paragraphAlign !== 'undefined' && ['left', 'right', 'center', 'justify'].includes(paragraphAlign)) {
|
||||||
|
return `<p class="ce-tune-alignment--${paragraphAlign}">${block.data.text}</p>`;
|
||||||
|
} else {
|
||||||
|
return `<p>${block.data.text}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
parse(richText: OutputData): string | Error {
|
||||||
|
return edjsHTML(RichTextParserService.CUSTOM_PARSER, { strict: true }).parse(richText);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user