diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json
index 2a028b2ac2..0bad0ed130 100644
--- a/demo-shell/resources/i18n/en.json
+++ b/demo-shell/resources/i18n/en.json
@@ -111,7 +111,8 @@
"GROUPS_CLOUD": "Groups Cloud Component",
"CONFIRM-DIALOG": "Confirmation Dialog",
"COMMUNITY": "Community",
- "SERVICE_TASK_LIST": "Service Task List"
+ "SERVICE_TASK_LIST": "Service Task List",
+ "RICH_TEXT_EDITOR": "Rich Text Editor"
},
"TRASHCAN": {
"ACTIONS": {
diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts
index 2145690894..938eaf8711 100644
--- a/demo-shell/src/app/app.routes.ts
+++ b/demo-shell/src/app/app.routes.ts
@@ -321,6 +321,10 @@ export const appRoutes: Routes = [
path: 'datatable/dnd',
loadChildren: () => import('./components/datatable/drag-and-drop/datatable-dnd.module').then(m => m.AppDataTableDndModule)
},
+ {
+ path: 'rich-text-editor',
+ loadChildren: () => import('./components/rich-text-editor/rich-text-editor.module').then(m => m.AppRichTextEditorModule)
+ },
{
path: 'search',
component: SearchResultComponent,
diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts
index 6a029f246f..80fa8820f2 100644
--- a/demo-shell/src/app/components/app-layout/app-layout.component.ts
+++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts
@@ -74,6 +74,7 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
{ href: '/datatable/dnd', icon: 'view_module', title: 'Drag and Drop' },
{ href: '/copy-content', icon: 'view_module', title: 'Copy Content' }
]},
+ { href: '/rich-text-editor', icon: 'list_alt', title: 'APP_LAYOUT.RICH_TEXT_EDITOR' },
{ href: '/template-list', icon: 'list_alt', title: 'APP_LAYOUT.TEMPLATE' },
{ href: '/webscript', icon: 'extension', title: 'APP_LAYOUT.WEBSCRIPT' },
{ href: '/tag', icon: 'local_offer', title: 'APP_LAYOUT.TAG' },
diff --git a/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.html b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.html
new file mode 100644
index 0000000000..0a6c77e64a
--- /dev/null
+++ b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.html
@@ -0,0 +1,12 @@
+
+
+
+
+
Output Data
+
{{editorOutputData | json}}
+
+
+
diff --git a/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.scss b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.scss
new file mode 100644
index 0000000000..a4e4d2df94
--- /dev/null
+++ b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.scss
@@ -0,0 +1,19 @@
+.app-rich-text-editor-container {
+ .app-rich-text-editor-col {
+ padding: 20px;
+
+ &-rx {
+ border-left: 1px dashed var(--theme-primary-color);
+ border-spacing: 5px;
+ }
+
+ &-title {
+ text-align: center;
+ }
+ }
+
+ .app-rich-text-editor-output {
+ max-width: 30vw;
+ overflow-x: scroll;
+ }
+}
diff --git a/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.ts b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.ts
new file mode 100644
index 0000000000..8f9757dfe3
--- /dev/null
+++ b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.component.ts
@@ -0,0 +1,112 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { OutputData } from '@editorjs/editorjs';
+import { RichTextEditorComponent as AdfRichTextEditorComponent } from '@alfresco/adf-core';
+import { takeUntil } from 'rxjs/operators';
+import { Subject } from 'rxjs';
+
+@Component({
+ selector: 'app-rich-text-editor',
+ templateUrl: './rich-text-editor.component.html',
+ styleUrls: ['./rich-text-editor.component.scss']
+})
+export class RichTextEditorComponent implements OnInit, AfterViewInit, OnDestroy {
+
+ @ViewChild('textEditor')
+ textEditor: AdfRichTextEditorComponent;
+
+ onDestroy$ = new Subject();
+
+ editorOutputData: OutputData;
+
+ sampleData = {
+ time: 1656674370891,
+ blocks: [
+ {
+ id: '99jwc03ETP',
+ type: 'header',
+ data: {
+ text: 'Header',
+ level: 2
+ }
+ },
+ {
+ id: 'ffdulIdU1E',
+ type: 'paragraph',
+ data: {
+ text: `is simply dummy text of the printing and typesetting industry.
+ Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s,
+ when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries,
+ but also the leap into electronic typesetting, remaining essentially unchanged.
+ It was popularised in the 1960s with the release of sheets containing
+ Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem`,
+ alignment: 'left'
+ }
+ },
+ {
+ id: 'rTcF4u0pr3',
+ type: 'list',
+ data: {
+ style: 'unordered',
+ items: [
+ 'Unordered list example',
+ 'Unordered list example'
+ ]
+ }
+ },
+ {
+ id: 'Kg2e_K1nHU',
+ type: 'list',
+ data: {
+ style: 'ordered',
+ items: [
+ 'Ordered list example',
+ 'Ordered list example'
+ ]
+ }
+ },
+ {
+ id: 'xqqk0DEmqh',
+ type: 'code',
+ data: {
+ code: '// Amazing code example\n\ncatch(Exception ex){\n // Houston, we have a problem\n}'
+ }
+ }
+ ]
+ };
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+ ngAfterViewInit(): void {
+ this.textEditor.outputData$.pipe(
+ takeUntil(this.onDestroy$)
+ ).subscribe(outputData => {
+ this.editorOutputData = outputData;
+ });
+ }
+
+ ngOnDestroy(): void {
+ this.onDestroy$.next(true);
+ this.onDestroy$.complete();
+ }
+
+}
diff --git a/demo-shell/src/app/components/rich-text-editor/rich-text-editor.module.ts b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.module.ts
new file mode 100644
index 0000000000..b3020aad9f
--- /dev/null
+++ b/demo-shell/src/app/components/rich-text-editor/rich-text-editor.module.ts
@@ -0,0 +1,43 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RichTextEditorComponent } from './rich-text-editor.component';
+import { ContentModule } from '@alfresco/adf-content-services';
+import { CoreModule } from '@alfresco/adf-core';
+import { RouterModule, Routes } from '@angular/router';
+import { FlexLayoutModule } from '@angular/flex-layout';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: RichTextEditorComponent
+ }
+];
+
+@NgModule({
+ declarations: [RichTextEditorComponent],
+ imports: [
+ CommonModule,
+ CoreModule,
+ RouterModule.forChild(routes),
+ ContentModule.forChild(),
+ FlexLayoutModule
+ ]
+})
+export class AppRichTextEditorModule { }
diff --git a/docs/README.md b/docs/README.md
index e61a6275c7..44d61beb46 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -111,6 +111,7 @@ for more information about installing and using the source code.
| [Notification History component](core/components/notification-history.component.md)  | This component is in the current status just an experimental component. | |
| The main purpose of the Notification history component is list all the notification received in the current session. They will disappear from the list after the refresh. | [Source](../lib/core/notifications/components/notification-history.component.ts) | |
| [Pagination Component](core/components/pagination.component.md) | Adds pagination to the component it is used with. | [Source](../lib/core/pagination/pagination.component.ts) |
+| [Rich Text Editor Component](core/components/rich-text-editor.md) | Displays a rich text editor that allows users to add formatted text | [Source](../lib/core/rich-text-editor/rich-text-editor.component.ts) |
| [Search Text Input Component](core/components/search-text-input.component.md) | Displays a input text that supports autocompletion | [Source](../lib/core/search-text/search-text-input.component.ts) |
| [Sidebar action menu component](core/components/sidebar-action-menu.component.md) | Displays a sidebar-action menu information panel. | [Source](../lib/core/layout/components/sidebar-action/sidebar-action-menu.component.ts) |
| [Sidenav Layout component](core/components/sidenav-layout.component.md) | Displays the standard three-region ADF application layout. | [Source](../lib/core/layout/components/sidenav-layout/sidenav-layout.component.ts) |
diff --git a/docs/core/components/form-field.component.md b/docs/core/components/form-field.component.md
index bab9485563..dd57fc864d 100644
--- a/docs/core/components/form-field.component.md
+++ b/docs/core/components/form-field.component.md
@@ -57,5 +57,6 @@ Forms defined in APS have the following default mappings for the form fields:
| Attach File | upload | AttachWidgetComponent or [`UploadWidgetComponent`](../../../lib/core/form/components/widgets/upload/upload.widget.ts) (based on metadata) |
| Display value | readonly | [`TextWidgetComponent`](../../../lib/core/form/components/widgets/text/text.widget.ts) |
| Display text | readonly-text | [`DisplayTextWidgetComponent`](../../../lib/core/form/components/widgets/display-text/display-text.widget.ts) |
+| Display Rich text | display-rich-text | [`DisplayRichTextWidgetComponent`](../../../lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts) |
| N/A | container | [`ContainerWidgetComponent`](../../../lib/core/form/components/widgets/container/container.widget.ts) (layout component) |
| N/A | N/A | [`UnknownWidgetComponent`](../../../lib/core/form/components/widgets/unknown/unknown.widget.ts) |
diff --git a/docs/core/components/rich-text-editor.md b/docs/core/components/rich-text-editor.md
new file mode 100644
index 0000000000..a64b585b01
--- /dev/null
+++ b/docs/core/components/rich-text-editor.md
@@ -0,0 +1,78 @@
+---
+Title: Rich Text Editor component
+Added: v1.0.0
+Status: Active
+Last reviewed: 2020-07-20
+---
+
+# [Rich Text Editor component](../../../lib/core/rich-text-editor/rich-text-editor.component.ts "Defined in rich-text-editor.component.ts")
+
+Wrap [Editor.js](https://editorjs.io/) element to show a Rich Text editor allows to add formatted text.
+
+## Contents
+
+- [Basic usage](#basic-usage)
+- [Class members](#class-members)
+ - [Properties](#properties)
+
+## Basic usage
+
+**app.component.html**
+
+```html
+
+
+```
+
+**app.component.ts**
+
+```ts
+@Component({...})
+export class RichTextEditorDemo {
+
+ @ViewChild('editor')
+ editorRef;
+
+ data = {
+ time: 1658154611110,
+ blocks: [
+ {
+ id: '99jwc03ETP',
+ type: 'header',
+ data: {
+ text: 'Header',
+ level: 2
+ }
+ },
+ {
+ id: 'ffdulIdU1E',
+ type: 'paragraph',
+ data: {
+ text: 'Sample paragraph',
+ alignment: 'left'
+ }
+ },
+ ],
+ version: 1
+ };
+
+ async saveContent(){
+ try {
+ const editorContent = await this.editorRef.getEditorContent();
+ // do some stuff with editor content
+ } catch (error) {
+ // catch error
+ }
+ }
+
+}
+```
+
+## Class members
+
+### Properties
+
+| Name | Type | Default value | Description |
+| -------- | ------------ | ------------- | -------------------------------------------------------------------------------------------- |
+| data | `OutputData` | null | EditorJs data format (follow the [official documentation](https://editorjs.io/saving-data) ) |
+| readOnly | `boolean` | false | If true users won't have the ability to change the document content |
diff --git a/docs/core/services/form-rendering.service.md b/docs/core/services/form-rendering.service.md
index fbfb99aa2f..9560ecb14c 100644
--- a/docs/core/services/form-rendering.service.md
+++ b/docs/core/services/form-rendering.service.md
@@ -73,6 +73,7 @@ The [`Form`](../../../lib/process-services/src/lib/task-list/models/form.model.t
| Checkbox | "boolean" | [`CheckboxWidgetComponent`](../../../lib/core/form/components/widgets/checkbox/checkbox.widget.ts) |
| Date | "date" | [`DateWidgetComponent`](../../../lib/core/form/components/widgets/date/date.widget.ts) |
| Display text | "readonly-text" | [`DisplayTextWidgetComponentComponent`](../../../lib/core/form/components/widgets/display-text/display-text.widget.ts) |
+| Display Rich text | "display-rich-text" | [`DisplayRichTextWidgetComponent`](../../../lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts) |
| Display value | "readonly" | DisplayValueWidgetComponent |
| Dropdown | "dropdown" | [`DropdownWidgetComponent`](../../../lib/core/form/components/widgets/dropdown/dropdown.widget.ts) |
| Dynamic table | "dynamic-table" | [`DynamicTableWidgetComponent`](../../../lib/core/form/components/widgets/dynamic-table/dynamic-table.widget.ts) |
diff --git a/docs/user-guide/extensibility.md b/docs/user-guide/extensibility.md
index 3309f9860f..8d57aa0eee 100644
--- a/docs/user-guide/extensibility.md
+++ b/docs/user-guide/extensibility.md
@@ -90,6 +90,7 @@ formRenderingService.setComponentTypeResolver('text', customResolver, true);
| Hyperlink | hyperlink | [`HyperlinkWidgetComponent`](../../lib/core/form/components/widgets/hyperlink/hyperlink.widget.ts) |
| Display value | readonly | DisplayValueWidgetComponent |
| Display text | readonly-text | [`DisplayTextWidgetComponentComponent`](../../lib/core/form/components/widgets/display-text/display-text.widget.ts) |
+| Display Rich text | display-rich-text | [`DisplayRichTextWidgetComponent`](../../lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts) |
| Typeahead | typeahead | [`TypeaheadWidgetComponent`](../../lib/core/form/components/widgets/typeahead/typeahead.widget.ts) |
| People | people | [`PeopleWidgetComponent`](../../lib/core/form/components/widgets/people/people.widget.ts) |
| Group of people | functional-group | [`FunctionalGroupWidgetComponent`](../../lib/core/form/components/widgets/functional-group/functional-group.widget.ts) |
diff --git a/lib/core/core.module.ts b/lib/core/core.module.ts
index 19ba08c712..2b0367e5fe 100644
--- a/lib/core/core.module.ts
+++ b/lib/core/core.module.ts
@@ -62,6 +62,7 @@ import { versionCompatibilityFactory } from './services/version-compatibility-fa
import { VersionCompatibilityService } from './services/version-compatibility.service';
import { AlfrescoJsClientsModule } from '@alfresco/adf-core/api';
import { LegacyApiClientModule } from './api-factories/legacy-api-client.module';
+import { RichTextEditorModule } from './rich-text-editor/rich-text-editor.module';
@NgModule({
imports: [
@@ -99,7 +100,8 @@ import { LegacyApiClientModule } from './api-factories/legacy-api-client.module'
SearchTextModule,
BlankPageModule,
LegacyApiClientModule,
- AlfrescoJsClientsModule
+ AlfrescoJsClientsModule,
+ RichTextEditorModule
],
exports: [
AboutModule,
@@ -134,7 +136,8 @@ import { LegacyApiClientModule } from './api-factories/legacy-api-client.module'
IconModule,
NotificationHistoryModule,
SearchTextModule,
- BlankPageModule
+ BlankPageModule,
+ RichTextEditorModule
]
})
export class CoreModule {
diff --git a/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.html b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.html
new file mode 100644
index 0000000000..7ccb286968
--- /dev/null
+++ b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.html
@@ -0,0 +1,3 @@
+
diff --git a/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.scss b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.scss
new file mode 100644
index 0000000000..1880db3e82
--- /dev/null
+++ b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.scss
@@ -0,0 +1,22 @@
+.adf-display-rich-text-widget {
+ padding: 10px;
+
+ pre {
+ min-height: 100px;
+ font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
+ color: #41314e;
+ line-height: 1.6em;
+ font-size: 12px;
+ background: #f8f7fa;
+ border: 1px solid #f1f1f4;
+ box-shadow: none;
+ white-space: pre;
+ word-wrap: normal;
+ overflow-x: auto;
+ resize: vertical;
+ border-radius: 3px;
+ padding: 10px 12px;
+ outline: none;
+ width: 100%;
+ }
+}
diff --git a/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.spec.ts b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.spec.ts
new file mode 100644
index 0000000000..77e507e549
--- /dev/null
+++ b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.spec.ts
@@ -0,0 +1,73 @@
+import { DebugElement } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { CoreTestingModule, setupTestBed } from 'core/testing';
+
+import { DisplayRichTextWidgetComponent } from './display-rich-text.widget';
+
+describe('DisplayRichTextWidgetComponent', () => {
+ let widget: DisplayRichTextWidgetComponent;
+ let fixture: ComponentFixture;
+ let debugEl: DebugElement;
+
+ const cssSelector = {
+ parsedHTML: '.adf-display-rich-text-widget-parsed-html'
+ };
+
+ const fakeFormField: any = {
+ id: 'fake-form-field',
+ name: 'fake-label',
+ value: {
+ time: 1658154611110,
+ blocks: [
+ {
+ id: '1',
+ type: 'header',
+ data: {
+ text: 'Editor.js',
+ level: 1
+ }
+ }
+ ],
+ version: 1
+ },
+ required: false,
+ readOnly: false,
+ overrideId: false,
+ colspan: 1,
+ placeholder: null,
+ minLength: 0,
+ maxLength: 0,
+ params: {
+ existingColspan: 1,
+ maxColspan: 1
+ }
+ };
+
+ setupTestBed({
+ imports: [
+ CoreTestingModule
+ ]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DisplayRichTextWidgetComponent);
+ widget = fixture.componentInstance;
+ debugEl = fixture.debugElement;
+ widget.field = fakeFormField;
+ });
+
+ it('should create', () => {
+ fixture.detectChanges();
+ expect(widget).toBeTruthy();
+ });
+
+ it('should parse editorjs data to html', async () => {
+ const expectedHtml = 'Editor.js
';
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const parsedHtmlEl = debugEl.query(By.css(cssSelector.parsedHTML));
+ expect(parsedHtmlEl.nativeElement.innerHTML).toEqual(expectedHtml);
+ });
+
+});
diff --git a/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts
new file mode 100644
index 0000000000..8ea78ebc12
--- /dev/null
+++ b/lib/core/form/components/widgets/display-rich-text/display-rich-text.widget.ts
@@ -0,0 +1,55 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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.
+ */
+
+/* eslint-disable @angular-eslint/component-selector */
+
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { FormService } from '../../../services/form.service';
+import { WidgetComponent } from '../widget.component';
+/* cspell:disable-next-line */
+import * as edjsHTML from 'editorjs-html';
+@Component({
+ selector: 'display-rich-text',
+ templateUrl: './display-rich-text.widget.html',
+ styleUrls: ['./display-rich-text.widget.scss'],
+ host: {
+ '(click)': 'event($event)',
+ '(blur)': 'event($event)',
+ '(change)': 'event($event)',
+ '(focus)': 'event($event)',
+ '(focusin)': 'event($event)',
+ '(focusout)': 'event($event)',
+ '(input)': 'event($event)',
+ '(invalid)': 'event($event)',
+ '(select)': 'event($event)'
+ },
+ encapsulation: ViewEncapsulation.None
+})
+export class DisplayRichTextWidgetComponent extends WidgetComponent implements OnInit {
+
+ parsedHTML: any;
+
+ constructor(public formService: FormService) {
+ super(formService);
+ }
+
+ ngOnInit(): void {
+ /* cspell:disable-next-line */
+ this.parsedHTML = edjsHTML().parseStrict(this.field.value).join('\n');
+ }
+
+}
diff --git a/lib/core/form/components/widgets/index.ts b/lib/core/form/components/widgets/index.ts
index 451a20d161..c8a1ff4647 100644
--- a/lib/core/form/components/widgets/index.ts
+++ b/lib/core/form/components/widgets/index.ts
@@ -48,6 +48,7 @@ import { DateTimeWidgetComponent } from './date-time/date-time.widget';
import { JsonWidgetComponent } from './json/json.widget';
import { UploadFolderWidgetComponent } from './upload-folder/upload-folder.widget';
import { FileViewerWidgetComponent } from './file-viewer/file-viewer.widget';
+import { DisplayRichTextWidgetComponent } from './display-rich-text/display-rich-text.widget';
// core
export * from './widget.component';
@@ -80,6 +81,7 @@ export * from './date-time/date-time.widget';
export * from './json/json.widget';
export * from './upload-folder/upload-folder.widget';
export * from './file-viewer/file-viewer.widget';
+export * from './display-rich-text/display-rich-text.widget';
// editors (dynamic table)
export * from './dynamic-table/dynamic-table.widget.model';
@@ -123,7 +125,8 @@ export const WIDGET_DIRECTIVES: any[] = [
JsonWidgetComponent,
AmountEditorComponent,
UploadFolderWidgetComponent,
- FileViewerWidgetComponent
+ FileViewerWidgetComponent,
+ DisplayRichTextWidgetComponent
];
export const MASK_DIRECTIVE: any[] = [
diff --git a/lib/core/form/services/form-rendering.service.spec.ts b/lib/core/form/services/form-rendering.service.spec.ts
index 1dd2c64c49..5fcbffc7ec 100644
--- a/lib/core/form/services/form-rendering.service.spec.ts
+++ b/lib/core/form/services/form-rendering.service.spec.ts
@@ -22,7 +22,8 @@ import {
UnknownWidgetComponent,
UploadWidgetComponent,
TextWidgetComponent,
- JsonWidgetComponent
+ JsonWidgetComponent,
+ DisplayRichTextWidgetComponent
} from './../components/widgets/index';
import { FormRenderingService } from './form-rendering.service';
@@ -128,4 +129,10 @@ describe('FormRenderingService', () => {
const type = resolver(null);
expect(type).toBe(JsonWidgetComponent);
});
+
+ it('should resolve Display Rich Text widget for display-rich-text field type', () => {
+ const resolver = service.getComponentTypeResolver('display-rich-text');
+ const type = resolver(null);
+ expect(type).toBe(DisplayRichTextWidgetComponent);
+ });
});
diff --git a/lib/core/form/services/form-rendering.service.ts b/lib/core/form/services/form-rendering.service.ts
index 31b2e294e4..557d214ee7 100644
--- a/lib/core/form/services/form-rendering.service.ts
+++ b/lib/core/form/services/form-rendering.service.ts
@@ -49,6 +49,7 @@ export class FormRenderingService extends DynamicComponentMapper {
document: DynamicComponentResolver.fromType(widgets.DocumentWidgetComponent),
upload: DynamicComponentResolver.fromType(widgets.UploadWidgetComponent),
datetime: DynamicComponentResolver.fromType(widgets.DateTimeWidgetComponent),
- 'file-viewer': DynamicComponentResolver.fromType(widgets.FileViewerWidgetComponent)
+ 'file-viewer': DynamicComponentResolver.fromType(widgets.FileViewerWidgetComponent),
+ 'display-rich-text': DynamicComponentResolver.fromType(widgets.DisplayRichTextWidgetComponent)
};
}
diff --git a/lib/core/index.ts b/lib/core/index.ts
index 679146759a..32207a0065 100644
--- a/lib/core/index.ts
+++ b/lib/core/index.ts
@@ -26,6 +26,7 @@ export * from './language-menu/index';
export * from './info-drawer/index';
export * from './data-column/index';
export * from './datatable/index';
+export * from './rich-text-editor/index';
export * from './context-menu/index';
export * from './card-view/index';
export * from './app-config/index';
diff --git a/lib/core/mock/form/demo-form.mock.ts b/lib/core/mock/form/demo-form.mock.ts
index 870686f394..a117bbc6cf 100644
--- a/lib/core/mock/form/demo-form.mock.ts
+++ b/lib/core/mock/form/demo-form.mock.ts
@@ -1806,27 +1806,115 @@ export class DemoForm {
}
}
],
- 2: [{
- fieldType: 'AttachFileFieldRepresentation',
- id: 'attachfiletest',
- name: 'attachfiletest',
- type: 'upload',
- required: true,
- colspan: 2,
- placeholder: 'attachfile',
- params: {
- existingColspan: 2,
- maxColspan: 2,
- fileSource: {
- serviceId: 'local-file',
- name: 'Local File'
+ 2: [
+ {
+ fieldType: 'AttachFileFieldRepresentation',
+ id: 'attachfiletest',
+ name: 'attachfiletest',
+ type: 'upload',
+ required: true,
+ colspan: 2,
+ placeholder: 'attachfile',
+ params: {
+ existingColspan: 2,
+ maxColspan: 2,
+ fileSource: {
+ serviceId: 'local-file',
+ name: 'Local File'
+ },
+ multiple: true,
+ link: false,
+ displayableCMProperties: []
},
- multiple: true,
- link: false
- },
- visibilityCondition: {
+ visibilityCondition: {}
}
- }]
+ ]
+ }
+ },
+ {
+ id: 'c23bf7e8-d43c-48b6-86b9-56d174faec4f',
+ name: 'Label',
+ type: 'container',
+ tab: null,
+ numberOfColumns: 2,
+ fields: {
+ 1: [
+ {
+ id: 'DisplayRichtext06jsjb',
+ name: 'Display Rich text',
+ type: 'display-rich-text',
+ readOnly: false,
+ value: {
+ time: 1658423394276,
+ blocks: [
+ {
+ id: 'dry4RE17v_',
+ type: 'header',
+ data: {
+ text: 'Display Rich Text widget example',
+ level: 1
+ }
+ },
+ {
+ id: 'my1r7YmMOs',
+ type: 'paragraph',
+ data: {
+ text: `Is simply a redonly
+ dummy text
+ of the printing and typesetting industry.\n
+ Lorem Ipsum has been the industry\'s standard du
+ mmy text ever since the 1500s,\n when an unknown printer took a galley of type
+ and scrambled it to make a type specimen book.
+ It has survived not only five centuries,\n
+ but also the leap into electronic typesetting,
+ remaining essentially unchanged.\n
+ It was underline
+ in the 1960s with the release of sheets containing\n
+ Lorem Ipsum passages, and more recently with desktop
+ publishing software like Aldus PageMaker including versions of Lorem,
+ example of inline code
`
+ }
+ },
+ {
+ id: 'vgpY3obXS7',
+ type: 'list',
+ data: {
+ style: 'unordered',
+ items: [
+ 'Unordered list example',
+ 'Unordered list example'
+ ]
+ }
+ },
+ {
+ id: 'lWR9x3OF1M',
+ type: 'list',
+ data: {
+ style: 'ordered',
+ items: ['Ordered list example', 'Ordered list example']
+ }
+ },
+ {
+ id: 'aeZV7M8sU1',
+ type: 'code',
+ data: {
+ code: '// Code Block Example\ncatch(Exception ex){\n // Houston, we have a problem\n}'
+ }
+ }
+ ],
+ version: '2.25.0'
+ },
+ isCustomType: false,
+ colspan: 1,
+ rowspan: 1,
+ visibilityCondition: null,
+ params: {
+ existingColspan: 1,
+ maxColspan: 2
+ }
+ }
+ ],
+ 2: []
}
}
],
diff --git a/lib/core/rich-text-editor/editorjs-config.ts b/lib/core/rich-text-editor/editorjs-config.ts
new file mode 100644
index 0000000000..b73c04afe7
--- /dev/null
+++ b/lib/core/rich-text-editor/editorjs-config.ts
@@ -0,0 +1,72 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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.
+*/
+
+/** Plugin import */
+import CodeTool from '@editorjs/code';
+import Header from '@editorjs/header';
+import InlineCode from '@editorjs/inline-code';
+import List from '@editorjs/list';
+import Marker from '@editorjs/marker';
+import Underline from '@editorjs/underline';
+import * as ChangeFontSize from '@quanzo/change-font-size';
+import * as ColorPlugin from 'editorjs-text-color-plugin';
+
+export const editorJsConfig = {
+ autofocus: true,
+ logLevel: 'ERROR',
+ tools: {
+ underline: {
+ class: Underline,
+ shortcut: 'CMD+U'
+ },
+ header: {
+ class: Header,
+ inlineToolbar: true
+ },
+ list: {
+ class: List,
+ inlineToolbar: true,
+ config: {
+ defaultStyle: 'unordered'
+ }
+ },
+ Color: {
+ class: ColorPlugin,
+ config: {
+ customPicker: true,
+ colorCollections: ['#FF1300', '#ffa500', '#9C27B0', '#673AB7', '#3F51B5', '#0070FF', '#03A9F4', '#00BCD4', '#5f9ea0', '#4CAF50', '#8BC34A', '#CDDC39', '#FFF', '#000', '#c0c0c0', '#808080', '#800000'],
+ defaultColor: '#FF1300',
+ type: 'text'
+ }
+ },
+ Marker: {
+ class: Marker,
+ shortcut: 'CMD+M'
+ },
+ 'Increase/Decrease font size': {
+ class: ChangeFontSize,
+ config: {
+ cssClass: 'plus20pc'
+ }
+ },
+ inlineCode: {
+ class: InlineCode,
+ shortcut: 'CMD+SHIFT+M'
+ },
+ code: CodeTool
+ }
+};
diff --git a/lib/core/rich-text-editor/index.ts b/lib/core/rich-text-editor/index.ts
new file mode 100644
index 0000000000..a7e30cc675
--- /dev/null
+++ b/lib/core/rich-text-editor/index.ts
@@ -0,0 +1,18 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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.
+ */
+
+export * from './public-api';
diff --git a/lib/core/rich-text-editor/public-api.ts b/lib/core/rich-text-editor/public-api.ts
new file mode 100644
index 0000000000..e5066128c5
--- /dev/null
+++ b/lib/core/rich-text-editor/public-api.ts
@@ -0,0 +1,21 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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.
+ */
+
+
+export * from './rich-text-editor.component';
+
+export * from './rich-text-editor.module';
diff --git a/lib/core/rich-text-editor/rich-text-editor.component.html b/lib/core/rich-text-editor/rich-text-editor.component.html
new file mode 100644
index 0000000000..b6e940d312
--- /dev/null
+++ b/lib/core/rich-text-editor/rich-text-editor.component.html
@@ -0,0 +1,3 @@
+
diff --git a/lib/core/rich-text-editor/rich-text-editor.component.scss b/lib/core/rich-text-editor/rich-text-editor.component.scss
new file mode 100644
index 0000000000..2d88f3bc5b
--- /dev/null
+++ b/lib/core/rich-text-editor/rich-text-editor.component.scss
@@ -0,0 +1,10 @@
+/* stylelint-disable selector-class-pattern */
+.adf-rich-text-editor-container {
+ .editorjs {
+ &.readonly {
+ .codex-editor__redactor {
+ padding-bottom: 0 !important;
+ }
+ }
+ }
+}
diff --git a/lib/core/rich-text-editor/rich-text-editor.component.spec.ts b/lib/core/rich-text-editor/rich-text-editor.component.spec.ts
new file mode 100644
index 0000000000..f9b7db4b63
--- /dev/null
+++ b/lib/core/rich-text-editor/rich-text-editor.component.spec.ts
@@ -0,0 +1,130 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { DebugElement } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+
+import { RichTextEditorComponent } from './rich-text-editor.component';
+
+describe('RichTextEditorComponent', () => {
+ let component: RichTextEditorComponent;
+ let fixture: ComponentFixture;
+ let debugElement: DebugElement;
+
+ const cssSelectors = {
+ editorContent: '.codex-editor',
+ editorJsElement: '.editorjs'
+ };
+
+ const mockEditorData = {
+ time: 1658154611110,
+ blocks: [
+ {
+ id: '1',
+ type: 'header',
+ data: {
+ text: 'Editor.js',
+ level: 2
+ }
+ }
+ ],
+ version: 1
+ };
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [RichTextEditorComponent]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RichTextEditorComponent);
+ component = fixture.componentInstance;
+ debugElement = fixture.debugElement;
+ });
+
+ it('should create', () => {
+ fixture.detectChanges();
+ expect(component).toBeTruthy();
+ });
+
+ it('should render rich text editor', async () => {
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const editor = debugElement.query(By.css(cssSelectors.editorContent));
+ expect(editor).toBeTruthy();
+ });
+
+ it('should generate dynamic id', async () => {
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(component.dynamicId).toContain('editorjs');
+ });
+
+ it('should set dynamic id to editor js element', async () => {
+ spyOn(window.crypto, 'getRandomValues').and.returnValue('randomId');
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const editor = debugElement.query(By.css(cssSelectors.editorJsElement));
+ expect(editor.nativeElement.id).toEqual('editorjs-randomId');
+ });
+
+ it('should get editorjs data by calling getEditorContent', async () => {
+ fixture.detectChanges();
+ await fixture.whenStable();
+ spyOn(component.editorInstance, 'save').and.returnValue(Promise.resolve(mockEditorData));
+ const savedEditorData = await component.getEditorContent();
+ expect(savedEditorData).toEqual(mockEditorData);
+ });
+
+ it('should destroy editor instance on ngOnDestroy', async () => {
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const destroyEditorSpy = spyOn(component.editorInstance, 'destroy');
+ component.ngOnDestroy();
+ expect(destroyEditorSpy).toHaveBeenCalledTimes(1);
+ expect(destroyEditorSpy).toHaveBeenCalled();
+ });
+
+ it('should not destroy editor instance on ngOnDestroy if editor is not ready', async () => {
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const destroyEditorSpy = spyOn(component.editorInstance, 'destroy');
+ component.isReady = false;
+ component.ngOnDestroy();
+ expect(destroyEditorSpy).not.toHaveBeenCalled();
+ });
+
+ it('should add readonly class if readOnly is set to true', async () => {
+ component.readOnly = true;
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const editorEl = debugElement.query(By.css(cssSelectors.editorJsElement));
+ expect(editorEl.nativeElement.classList).toContain('readonly');
+ });
+
+ it('should not add readonly class if readOnly is set to false', async () => {
+ component.readOnly = false;
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const editorEl = debugElement.query(By.css(cssSelectors.editorJsElement));
+ expect(editorEl.nativeElement.classList).not.toContain('readonly');
+ });
+
+});
diff --git a/lib/core/rich-text-editor/rich-text-editor.component.ts b/lib/core/rich-text-editor/rich-text-editor.component.ts
new file mode 100644
index 0000000000..ef25b12dfd
--- /dev/null
+++ b/lib/core/rich-text-editor/rich-text-editor.component.ts
@@ -0,0 +1,91 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { AfterViewInit, Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
+
+import EditorJS, { OutputData } from '@editorjs/editorjs';
+import { Subject } from 'rxjs';
+import { editorJsConfig } from './editorjs-config';
+
+@Component({
+ selector: 'adf-rich-text-editor',
+ templateUrl: './rich-text-editor.component.html',
+ styleUrls: ['./rich-text-editor.component.scss'],
+ encapsulation: ViewEncapsulation.None
+})
+export class RichTextEditorComponent implements OnInit, OnDestroy, AfterViewInit {
+
+ @Input()
+ data: OutputData;
+
+ @Input()
+ readOnly = false;
+
+ private _outputData = new Subject();
+
+ outputData$ = this._outputData.asObservable();
+
+ editorInstance: EditorJS;
+ dynamicId: string;
+ isReady = false;
+
+ constructor() {
+ }
+
+ ngOnInit(): void {
+ this.dynamicId = `editorjs-${crypto.getRandomValues(new Uint32Array(1))}`;
+ }
+
+ ngAfterViewInit(): void {
+ this.editorInstance = new EditorJS({
+ holder: this.dynamicId,
+ ...editorJsConfig,
+ data: this.data,
+ readOnly: this.readOnly,
+ onChange: () => {
+ if (!this.readOnly) {
+ this.sendEditorOutputData();
+ }
+ },
+ onReady: () => {
+ this.isReady = true;
+ if (!this.readOnly) {
+ this.sendEditorOutputData();
+ }
+ }
+ } as any);
+ }
+
+ private sendEditorOutputData() {
+ this.editorInstance.save().then((outputData) => {
+ this._outputData.next(outputData);
+ }).catch((error) => {
+ console.log('Saving failed: ', error);
+ });
+ }
+
+ getEditorContent() {
+ return this.editorInstance.save();
+ }
+
+ ngOnDestroy(): void {
+ if (this.isReady) {
+ this.editorInstance.destroy();
+ }
+ }
+
+}
diff --git a/lib/core/rich-text-editor/rich-text-editor.module.ts b/lib/core/rich-text-editor/rich-text-editor.module.ts
new file mode 100644
index 0000000000..814902cbe0
--- /dev/null
+++ b/lib/core/rich-text-editor/rich-text-editor.module.ts
@@ -0,0 +1,30 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RichTextEditorComponent } from './rich-text-editor.component';
+
+
+@NgModule({
+ declarations: [RichTextEditorComponent],
+ imports: [
+ CommonModule
+ ],
+ exports: [RichTextEditorComponent]
+})
+export class RichTextEditorModule { }
diff --git a/package-lock.json b/package-lock.json
index b3597644c9..6c75e93c2d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4508,6 +4508,49 @@
"integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
"dev": true
},
+ "@editorjs/code": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@editorjs/code/-/code-2.7.0.tgz",
+ "integrity": "sha512-gXtTce915fHp3H9i4IqhTxEDbbkT2heFfYiW/bhFHsCmZDpyGzfZxi94kmrEqDmbxXjV49ZZ6GZbR26If13KJw==",
+ "dev": true
+ },
+ "@editorjs/editorjs": {
+ "version": "2.25.0",
+ "resolved": "https://registry.npmjs.org/@editorjs/editorjs/-/editorjs-2.25.0.tgz",
+ "integrity": "sha512-TEu7h7EPh6Lx2VGIM1jVn2dky23TbpVJBd3AGvXcam1lyHuJwZ1iydbsQGF9pFkHSCiaQptTfIjZ8Y24v47Wag==",
+ "requires": {
+ "codex-notifier": "^1.1.2",
+ "codex-tooltip": "^1.0.5",
+ "nanoid": "^3.1.22"
+ }
+ },
+ "@editorjs/header": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@editorjs/header/-/header-2.6.2.tgz",
+ "integrity": "sha512-U1dnT+KGjwFmpWneEEyR2Nqp42hn9iKwQDgRHWQM+y6qx82pg+eAyuIf0QWt2Mluu9uPD2CzNfvJ+pxIuwX8Lw=="
+ },
+ "@editorjs/inline-code": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@editorjs/inline-code/-/inline-code-1.3.1.tgz",
+ "integrity": "sha512-iY6DeRmJo2Jl6sB2S9QEA9OoSp+KCHBztoY2fjPeiBcKCOKX8we5H3JQJTLxT0L/N8uJqCUiiPKgG6xvqaCn+g==",
+ "dev": true
+ },
+ "@editorjs/list": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@editorjs/list/-/list-1.7.0.tgz",
+ "integrity": "sha512-0k0RKbQqfV32u24UYHHz5mrmSu4wr246qqXBT7xQiS533Bfd4hzki6UGzvy4f275ULzi+egbjI3BXLkpoTh9iQ=="
+ },
+ "@editorjs/marker": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@editorjs/marker/-/marker-1.2.2.tgz",
+ "integrity": "sha512-BN/IHbVKKahGnMAiBOV5U7XUjfF6JkIkTZ6qNLxtTr7PUPM8UsJV8G8pyll9CX+XRUYYZyokA2kEBHTS4vUyyw==",
+ "dev": true
+ },
+ "@editorjs/underline": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@editorjs/underline/-/underline-1.0.0.tgz",
+ "integrity": "sha512-2qbmr6/Y5ZIsfmJeAxLujCndc5wpIEQ2uxoPIdR3uHIUQhA6Q28U5HdoGpEZwsP1d7e/A/vBhN18Ugro0iA0MQ=="
+ },
"@emotion/cache": {
"version": "10.0.29",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
@@ -9494,6 +9537,12 @@
"integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ==",
"dev": true
},
+ "@quanzo/change-font-size": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@quanzo/change-font-size/-/change-font-size-1.0.0.tgz",
+ "integrity": "sha512-Gwp68CHT45mjszaELuTCOLsakWrUVmcrIEUJGOaGgPTr6VWqoqdFiyuHqtyGmO5/69eoo/HIzlYJ7z3NYgJ3Fg==",
+ "dev": true
+ },
"@reach/router": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz",
@@ -27732,6 +27781,16 @@
}
}
},
+ "codex-notifier": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/codex-notifier/-/codex-notifier-1.1.2.tgz",
+ "integrity": "sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg=="
+ },
+ "codex-tooltip": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/codex-tooltip/-/codex-tooltip-1.0.5.tgz",
+ "integrity": "sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag=="
+ },
"coffeescript": {
"version": "1.12.7",
"resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz",
@@ -30273,6 +30332,28 @@
"safer-buffer": "^2.1.0"
}
},
+ "editorjs-html": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/editorjs-html/-/editorjs-html-3.4.2.tgz",
+ "integrity": "sha512-Gy8FV4oHMvnPDXLsdpZYW0Dgjaagff9bPd28/WW9aFdy87FvktJxQz8H+NKpxiGcGoNY27MmjFffurK2yhXjEg=="
+ },
+ "editorjs-inline-font-size-tool": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/editorjs-inline-font-size-tool/-/editorjs-inline-font-size-tool-1.0.1.tgz",
+ "integrity": "sha512-ZuwRGaLrPBwPqW9KawMGjWuvyvPGO/tPUReWYBdyqAmFuOB5H5nw8TK1gAVIMFp7Q+vT0pQdscgHwnktj8pd5w==",
+ "dev": true
+ },
+ "editorjs-paragraph-with-alignment": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/editorjs-paragraph-with-alignment/-/editorjs-paragraph-with-alignment-3.0.0.tgz",
+ "integrity": "sha512-vSjjB/KUECEBxYqbj9yn1L799L14n0uoKrvk5qfaAokIHB8mYg5hZ8mOTtoS2cJu+xE3QZ/jmHY/Fh0EJeM8ZQ=="
+ },
+ "editorjs-text-color-plugin": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/editorjs-text-color-plugin/-/editorjs-text-color-plugin-1.13.1.tgz",
+ "integrity": "sha512-iCK274omDhoU7/zIFwV1fP5ydgfObYXSGV+q2zlFq3D4JDnvtn0KP+6NPM1A4dDlxTczpywPByRKIwmf7z4CIg==",
+ "dev": true
+ },
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -40289,8 +40370,7 @@
"nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
- "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
- "dev": true
+ "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
},
"nanomatch": {
"version": "1.2.13",
diff --git a/package.json b/package.json
index cae20b9f1e..e7a2260f41 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,10 @@
"@angular/platform-browser-dynamic": "^10.0.4",
"@angular/router": "^10.0.4",
"@apollo/client": "^3.5.6",
+ "@editorjs/editorjs": "2.25.0",
+ "@editorjs/header": "2.6.2",
+ "@editorjs/list": "1.7.0",
+ "@editorjs/underline": "1.0.0",
"@mat-datetimepicker/core": "^5.1.1",
"@mat-datetimepicker/moment": "^5.1.1",
"@ngx-translate/core": "^13.0.0",
@@ -94,6 +98,8 @@
"cropperjs": "1.5.12",
"custom-event-polyfill": "^1.0.7",
"dotenv-expand": "^5.1.0",
+ "editorjs-html": "3.4.2",
+ "editorjs-paragraph-with-alignment": "3.0.0",
"minimatch": "^3.0.4",
"minimatch-browser": "1.0.0",
"moment-es6": "^1.0.0",
@@ -116,11 +122,15 @@
"@angular-eslint/template-parser": "1.2.0",
"@angular/cli": "^10.2.2",
"@angular/compiler-cli": "^10.0.12",
+ "@editorjs/code": "2.7.0",
+ "@editorjs/inline-code": "1.3.1",
+ "@editorjs/marker": "1.2.2",
"@nrwl/schematics": "8.12.11",
"@nrwl/storybook": "^12.9.0",
"@nrwl/workspace": "^11.2.11",
"@paperist/types-remark": "0.1.3",
"@playwright/test": "^1.19.2",
+ "@quanzo/change-font-size": "1.0.0",
"@storybook/addon-essentials": "~6.3.0",
"@storybook/angular": "~6.3.0",
"@storybook/builder-webpack5": "~6.3.0",
@@ -141,6 +151,7 @@
"cspell": "^5.5.1",
"css-loader": "^5.2.6",
"dotenv": "^8.2.0",
+ "editorjs-text-color-plugin": "1.13.1",
"eslint": "^7.6.0",
"eslint-plugin-ban": "^1.6.0",
"eslint-plugin-import": "2.25.4",