diff --git a/projects/dsp-ui/src/lib/viewer/operations/add-value/add-value.component.html b/projects/dsp-ui/src/lib/viewer/operations/add-value/add-value.component.html index 38c6e253a..29151c4c7 100644 --- a/projects/dsp-ui/src/lib/viewer/operations/add-value/add-value.component.html +++ b/projects/dsp-ui/src/lib/viewer/operations/add-value/add-value.component.html @@ -3,6 +3,7 @@ + diff --git a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.html b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.html index d17e0fba9..40bd991cf 100644 --- a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.html +++ b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.html @@ -7,6 +7,7 @@ + diff --git a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts index 0416efcae..61a8f56ba 100644 --- a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts @@ -513,7 +513,7 @@ describe('DisplayEditComponent', () => { it('should return the type of a integer value as not readonly', () => { expect(valueTypeService.getValueTypeOrClass(testHostComponent.displayEditValueComponent.displayValue)).toEqual(Constants.IntValue); - expect(valueTypeService.isReadOnly(Constants.IntValue)).toBe(false); + expect(valueTypeService.isReadOnly(Constants.IntValue, testHostComponent.displayEditValueComponent.displayValue)).toBe(false); }); it('should return the class of a html text value as readonly', () => { @@ -523,18 +523,7 @@ describe('DisplayEditComponent', () => { expect(valueTypeService.getValueTypeOrClass(htmlTextVal)).toEqual('ReadTextValueAsHtml'); - expect(valueTypeService.isReadOnly('ReadTextValueAsHtml')).toBe(true); - - }); - - it('should return the class of an XML text value as readonly', () => { - - const xmlTextVal = new ReadTextValueAsXml(); - xmlTextVal.type = Constants.TextValue; - - expect(valueTypeService.getValueTypeOrClass(xmlTextVal)).toEqual('ReadTextValueAsXml'); - - expect(valueTypeService.isReadOnly('ReadTextValueAsXml')).toBe(true); + expect(valueTypeService.isReadOnly('ReadTextValueAsHtml', htmlTextVal)).toBe(true); }); @@ -545,7 +534,7 @@ describe('DisplayEditComponent', () => { expect(valueTypeService.getValueTypeOrClass(plainTextVal)).toEqual('ReadTextValueAsString'); - expect(valueTypeService.isReadOnly('ReadTextValueAsString')).toBe(false); + expect(valueTypeService.isReadOnly('ReadTextValueAsString', plainTextVal)).toBe(false); }); diff --git a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts index ccb42cd2d..19355f726 100644 --- a/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts +++ b/projects/dsp-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts @@ -126,7 +126,7 @@ export class DisplayEditComponent implements OnInit { this.valueTypeOrClass = this._valueTypeService.getValueTypeOrClass(this.displayValue); - this.readOnlyValue = this._valueTypeService.isReadOnly(this.valueTypeOrClass); + this.readOnlyValue = this._valueTypeService.isReadOnly(this.valueTypeOrClass, this.displayValue); this._dspApiConnection.admin.usersEndpoint.getUserByIri(this.displayValue.attachedToUser).subscribe( (response: ApiResponseData) => { diff --git a/projects/dsp-ui/src/lib/viewer/services/value-type.service.spec.ts b/projects/dsp-ui/src/lib/viewer/services/value-type.service.spec.ts index 0747d1fa9..2e5913d5d 100644 --- a/projects/dsp-ui/src/lib/viewer/services/value-type.service.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/services/value-type.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; -import { ReadIntValue, ReadTextValueAsHtml, ReadTextValueAsString } from '@dasch-swiss/dsp-js'; +import { ReadIntValue, ReadTextValueAsHtml, ReadTextValueAsString, ReadTextValueAsXml } from '@dasch-swiss/dsp-js'; import { ValueTypeService } from './value-type.service'; describe('ValueTypeService', () => { @@ -36,14 +36,30 @@ describe('ValueTypeService', () => { const readTextValueAsString = new ReadTextValueAsString(); readTextValueAsString.type = 'http://api.knora.org/ontology/knora-api/v2#TextValue'; const valueClass = service.getValueTypeOrClass(readTextValueAsString); - expect(service.isReadOnly(valueClass)).toBeFalsy(); + expect(service.isReadOnly(valueClass, readTextValueAsString)).toBeFalsy(); }); it('should mark ReadTextValueAsHtml as ReadOnly', () => { const readTextValueAsHtml = new ReadTextValueAsHtml(); readTextValueAsHtml.type = 'http://api.knora.org/ontology/knora-api/v2#TextValue'; const valueClass = service.getValueTypeOrClass(readTextValueAsHtml); - expect(service.isReadOnly(valueClass)).toBeTruthy(); + expect(service.isReadOnly(valueClass, readTextValueAsHtml)).toBeTruthy(); + }); + + it('should not mark ReadTextValueAsXml with standard mapping as ReadOnly', () => { + const readTextValueAsXml = new ReadTextValueAsXml(); + readTextValueAsXml.type = 'http://api.knora.org/ontology/knora-api/v2#TextValue'; + readTextValueAsXml.mapping = 'http://rdfh.ch/standoff/mappings/StandardMapping'; + const valueClass = service.getValueTypeOrClass(readTextValueAsXml); + expect(service.isReadOnly(valueClass, readTextValueAsXml)).toBeFalsy(); + }); + + it('should mark ReadTextValueAsXml with custom mapping as ReadOnly', () => { + const readTextValueAsXml = new ReadTextValueAsXml(); + readTextValueAsXml.type = 'http://api.knora.org/ontology/knora-api/v2#TextValue'; + readTextValueAsXml.mapping = 'http://rdfh.ch/standoff/mappings/CustomMapping'; + const valueClass = service.getValueTypeOrClass(readTextValueAsXml); + expect(service.isReadOnly(valueClass, readTextValueAsXml)).toBeTruthy(); }); }); diff --git a/projects/dsp-ui/src/lib/viewer/services/value-type.service.ts b/projects/dsp-ui/src/lib/viewer/services/value-type.service.ts index 83726effd..cbfd75eeb 100644 --- a/projects/dsp-ui/src/lib/viewer/services/value-type.service.ts +++ b/projects/dsp-ui/src/lib/viewer/services/value-type.service.ts @@ -56,7 +56,7 @@ export class ValueTypeService { if (resourcePropDef.guiElement === 'http://api.knora.org/ontology/salsah-gui/v2#SimpleText') { return this._readTextValueAsString; } else if (resourcePropDef.guiElement === 'http://api.knora.org/ontology/salsah-gui/v2#Richtext') { - return this._readTextValueAsHtml; + return this._readTextValueAsXml; } else { throw new Error(`unknown TextValue class ${resourcePropDef}`); } @@ -85,10 +85,14 @@ export class ValueTypeService { * Determines if the given value is readonly. * * @param valueTypeOrClass the type or class of the given value. + * @param value the given value. */ - isReadOnly(valueTypeOrClass: string): boolean { + isReadOnly(valueTypeOrClass: string, value: ReadValue): boolean { + const xmlValueNonStandardMapping + = valueTypeOrClass === this._readTextValueAsXml + && (value instanceof ReadTextValueAsXml && value.mapping !== 'http://rdfh.ch/standoff/mappings/StandardMapping'); + return valueTypeOrClass === this._readTextValueAsHtml || - valueTypeOrClass === this._readTextValueAsXml || - valueTypeOrClass === this.constants.GeomValue; + valueTypeOrClass === this.constants.GeomValue || xmlValueNonStandardMapping; } } diff --git a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.html b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.html index 5b47a4258..0155db956 100644 --- a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.html +++ b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.html @@ -1,18 +1,30 @@ -
- - - - -
- - No mapping or apt configuration was provided for "xmlTransform" in the app's configuration object. + +
+ + {{displayValue?.xml}} + + {{commentFormControl.value}} +
+ +
+ + + + + + +
+ + No class was provided for CKEditor. +
+ diff --git a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.scss b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.scss index e13b5d518..7ec769410 100644 --- a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.scss +++ b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.scss @@ -5,3 +5,9 @@ ::ng-deep .ck-content code { font-family: monospace; } + +.rm-value { + ::ng-deep p { + margin: 0; + } +} diff --git a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.spec.ts b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.spec.ts index 52b14e8ec..b259a254d 100644 --- a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.spec.ts @@ -105,23 +105,6 @@ class TestHostCreateValueComponent implements OnInit { describe('TextValueAsXMLComponent', () => { - const appInitServiceMock = { - config: { - xmlTransform: { - 'http://rdfh.ch/standoff/mappings/StandardMapping': { - '
': '
', - '': '', - '': '', - '': '', - '': '', - '': '', - '
': '', - '
': '' - } - } - } - }; - beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ @@ -134,9 +117,6 @@ describe('TextValueAsXMLComponent', () => { ReactiveFormsModule, MatInputModule, BrowserAnimationsModule - ], - providers: [ - {provide: AppInitService, useValue: appInitServiceMock} ] }) .compileComponents(); @@ -145,6 +125,12 @@ describe('TextValueAsXMLComponent', () => { describe('display and edit a text value with xml markup', () => { let testHostComponent: TestHostDisplayValueComponent; let testHostFixture: ComponentFixture; + + let valueComponentDe: DebugElement; + + let valueReadModeDebugElement: DebugElement; + let valueReadModeNativeElement; + let ckeditorDe: DebugElement; beforeEach(() => { @@ -153,11 +139,17 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); const hostCompDe = testHostFixture.debugElement; + valueComponentDe = hostCompDe.query(By.directive(TextValueAsXMLComponent)); + + valueReadModeDebugElement = valueComponentDe.query(By.css('.rm-value')); + valueReadModeNativeElement = valueReadModeDebugElement.nativeElement; + + // reset before each it + ckeditorDe = undefined; - ckeditorDe = hostCompDe.query(By.directive(TestCKEditorComponent)); }); - it('should display an existing value', () => { + it('should display an existing value for the standard mapping as formatted text', () => { expect(testHostComponent.inputValueComponent.displayValue.xml).toEqual('\n

test with markup

'); @@ -165,9 +157,32 @@ describe('TextValueAsXMLComponent', () => { expect(testHostComponent.inputValueComponent.mode).toEqual('read'); - expect(testHostComponent.inputValueComponent.valueFormControl.disabled).toBeTruthy(); + expect(valueReadModeNativeElement.innerHTML).toEqual('\n

test with markup

'); - expect(ckeditorDe.componentInstance.value).toEqual('\n

test with markup

'); + }); + + it('should display an existing value for a custom mapping as XML source code', () => { + + const newXml = new ReadTextValueAsXml(); + + newXml.xml = '

my updated text

'; + newXml.mapping = 'http://rdfh.ch/standoff/mappings/customMapping'; + + newXml.id = 'id'; + + testHostComponent.displayInputVal = newXml; + + testHostFixture.detectChanges(); + + valueReadModeDebugElement = valueComponentDe.query(By.css('.rm-value')); + + valueReadModeNativeElement = valueReadModeDebugElement.nativeElement; + + expect(valueReadModeNativeElement.innerText).toEqual( + '

my updated text

'); + + // custom mappings are not supported by this component + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); }); @@ -177,6 +192,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); @@ -208,6 +225,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); @@ -234,6 +253,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); @@ -258,7 +279,7 @@ describe('TextValueAsXMLComponent', () => { const newXml = new ReadTextValueAsXml(); - newXml.xml = '

my updated text

'; + newXml.xml = '

my updated text

'; newXml.mapping = 'http://rdfh.ch/standoff/mappings/StandardMapping'; newXml.id = 'updatedId'; @@ -267,7 +288,7 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); - expect(ckeditorDe.componentInstance.value).toEqual('

my updated text

'); + expect(valueReadModeNativeElement.innerHTML).toEqual('

my updated text

'); expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); @@ -279,6 +300,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + // simulate input in ckeditor ckeditorDe.componentInstance.value = '

test with a lot of markup

'; ckeditorDe.componentInstance._handleInput(); @@ -296,6 +319,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + // simulate input in ckeditor ckeditorDe.componentInstance.value = '

test with horizontal line


'; ckeditorDe.componentInstance._handleInput(); @@ -313,6 +338,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + // simulate input in ckeditor ckeditorDe.componentInstance.value = '

test with struck word

'; ckeditorDe.componentInstance._handleInput(); @@ -330,6 +357,8 @@ describe('TextValueAsXMLComponent', () => { testHostFixture.detectChanges(); + ckeditorDe = valueComponentDe.query(By.directive(TestCKEditorComponent)); + // simulate input in ckeditor ckeditorDe.componentInstance.value = '

testtest
testtest

'; ckeditorDe.componentInstance._handleInput(); diff --git a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.ts b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.ts index 6fe448851..d580321ce 100644 --- a/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.ts +++ b/projects/dsp-ui/src/lib/viewer/values/text-value/text-value-as-xml/text-value-as-xml.component.ts @@ -3,7 +3,6 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { Constants, CreateTextValueAsXml, ReadTextValueAsXml, UpdateTextValueAsXml } from '@dasch-swiss/dsp-js'; import * as Editor from 'ckeditor5-custom-build'; import { Subscription } from 'rxjs'; -import { AppInitService } from '../../../../core/app-init.service'; import { BaseValueComponent } from '../../base-value.component'; import { ValueErrorStateMatcher } from '../../value-error-state-matcher'; @@ -14,8 +13,9 @@ import { ValueErrorStateMatcher } from '../../value-error-state-matcher'; }) export class TextValueAsXMLComponent extends BaseValueComponent implements OnInit, OnChanges, OnDestroy { + readonly standardMapping = 'http://rdfh.ch/standoff/mappings/StandardMapping'; // TODO: define this somewhere else + @Input() displayValue?: ReadTextValueAsXml; - @Input() mapping = 'http://rdfh.ch/standoff/mappings/StandardMapping'; // TODO: define this somewhere else valueFormControl: FormControl; commentFormControl: FormControl; @@ -30,20 +30,36 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni editor: Editor; editorConfig; + // XML conversion + xmlTransform = { + '
': '
', + '': '', + '': '', + '': '', + '': '', + '': '', + '
': '', + '
': '' + }; + // TODO: get this from config via AppInitService readonly resourceBasePath = 'http://rdfh.ch/'; - constructor(private _appInitService: AppInitService, - @Inject(FormBuilder) private fb: FormBuilder) { + constructor(@Inject(FormBuilder) private fb: FormBuilder) { super(); } + standardValueComparisonFunc(initValue: any, curValue: any): boolean { + const initValueTrimmed = typeof initValue === 'string' ? initValue.trim() : initValue; + const curValueTrimmed = typeof curValue === 'string' ? curValue.trim() : curValue; + + return initValueTrimmed === this._handleXML(curValueTrimmed, false, false); + } + getInitValue(): string | null { // check for standard mapping - if (this.displayValue !== undefined) { - - // strip the doctype and text tag + if (this.displayValue !== undefined && this.displayValue.mapping === this.standardMapping) { return this._handleXML(this.displayValue.xml, true); } else { return null; @@ -52,65 +68,61 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni ngOnInit() { - if (this.mapping !== undefined - && this._appInitService.config['xmlTransform'] !== undefined - && this._appInitService.config['xmlTransform'][this.mapping] !== undefined) { - - this.editor = Editor; - - this.editorConfig = { - entities: false, - link: { - addTargetToExternalLinks: false, - decorators: { - isInternal: { - // label: 'internal link to a Knora resource', - mode: 'automatic', // automatic requires callback -> but the callback is async and the user could save the text before the check ... - callback: url => { /*console.log(url, url.startsWith( 'http://rdfh.ch/' ));*/ - return url.startsWith(this.resourceBasePath); - }, - attributes: { - class: Constants.SalsahLink - } + this.editor = Editor; + + this.editorConfig = { + entities: false, + link: { + addTargetToExternalLinks: false, + decorators: { + isInternal: { + // label: 'internal link to a Knora resource', + mode: 'automatic', // automatic requires callback -> but the callback is async and the user could save the text before the check ... + callback: url => { /*console.log(url, url.startsWith( 'http://rdfh.ch/' ));*/ + return !!url && url.startsWith(this.resourceBasePath); + }, + attributes: { + class: Constants.SalsahLink } } - }, - toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'underline', 'strikethrough', 'subscript', 'superscript', 'horizontalline', 'insertTable', 'code', 'codeBlock', 'removeformat', 'redo', 'undo'], - heading: { - options: [ - {model: 'heading1', view: 'h1', title: 'Heading 1'}, - {model: 'heading2', view: 'h2', title: 'Heading 2'}, - {model: 'heading3', view: 'h3', title: 'Heading 3'}, - {model: 'heading4', view: 'h4', title: 'Heading 4'}, - {model: 'heading5', view: 'h5', title: 'Heading 5'}, - {model: 'heading6', view: 'h6', title: 'Heading 6'}, - ] - }, - codeBlock: { - languages: [ - {language: 'plaintext', label: 'Plain text', class: ''} - ] } - }; + }, + toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'underline', 'strikethrough', 'subscript', 'superscript', 'horizontalline', 'insertTable', 'code', 'codeBlock', 'removeformat', 'redo', 'undo'], + heading: { + options: [ + {model: 'heading1', view: 'h1', title: 'Heading 1'}, + {model: 'heading2', view: 'h2', title: 'Heading 2'}, + {model: 'heading3', view: 'h3', title: 'Heading 3'}, + {model: 'heading4', view: 'h4', title: 'Heading 4'}, + {model: 'heading5', view: 'h5', title: 'Heading 5'}, + {model: 'heading6', view: 'h6', title: 'Heading 6'}, + ] + }, + codeBlock: { + languages: [ + {language: 'plaintext', label: 'Plain text', class: ''} + ] + } + }; - // initialize form control elements - this.valueFormControl = new FormControl({value: null, disabled: this.mode === 'read'}); + // initialize form control elements + this.valueFormControl = new FormControl(null); - this.commentFormControl = new FormControl(null); + this.commentFormControl = new FormControl(null); - this.valueChangesSubscription = this.commentFormControl.valueChanges.subscribe( - data => { - this.valueFormControl.updateValueAndValidity(); - } - ); + this.valueChangesSubscription = this.commentFormControl.valueChanges.subscribe( + data => { + this.valueFormControl.updateValueAndValidity(); + } + ); - this.form = this.fb.group({ - xmlValue: this.valueFormControl, - comment: this.commentFormControl - }); + this.form = this.fb.group({ + xmlValue: this.valueFormControl, + comment: this.commentFormControl + }); + + this.resetFormControl(); - this.resetFormControl(); - } } ngOnChanges(changes: SimpleChanges): void { @@ -119,13 +131,6 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni // at the first call of ngOnChanges, form control elements are not initialized yet this.resetFormControl(); - // mode is controlled via the FormControl - if (this.valueFormControl !== undefined && this.mode === 'read') { - this.valueFormControl.disable(); - } else if (this.valueFormControl !== undefined) { - this.valueFormControl.enable(); - } - } ngOnDestroy(): void { @@ -141,7 +146,7 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni const newTextValue = new CreateTextValueAsXml(); newTextValue.xml = this._handleXML(this.valueFormControl.value, false); - newTextValue.mapping = this.mapping; + newTextValue.mapping = this.standardMapping; if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { newTextValue.valueHasComment = this.commentFormControl.value; @@ -162,7 +167,7 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni updatedTextValue.id = this.displayValue.id; updatedTextValue.xml = this._handleXML(this.valueFormControl.value, false); - updatedTextValue.mapping = this.mapping; + updatedTextValue.mapping = this.standardMapping; if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { updatedTextValue.valueHasComment = this.commentFormControl.value; @@ -176,16 +181,22 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni * * @param xml xml to be processed. * @param fromKnora true if xml is received from Knora. + * @param addXMLDocType whether to add the doctype to the XML. */ - private _handleXML(xml: string, fromKnora: boolean) { + private _handleXML(xml: string, fromKnora: boolean, addXMLDocType = true) { const doctype = ''; const textTag = 'text'; const openingTextTag = `<${textTag}>`; const closingTextTag = ``; + // check if xml is a string + if (typeof xml !== 'string') { + return xml; + } + if (fromKnora) { - // CKEditor accepts tags from version 4, no conversion needed + // CKEditor accepts tags from version 4 // see 4 to 5 migration, see https://ckeditor.com/docs/ckeditor5/latest/builds/guides/migrate.html return xml.replace(doctype, '') .replace(openingTextTag, '') @@ -196,13 +207,17 @@ export class TextValueAsXMLComponent extends BaseValueComponent implements OnIni xml = xml.replace(/ /g, String.fromCharCode(160)); // get XML transform config - const keys = Object.keys(this._appInitService.config['xmlTransform'][this.mapping]); + const keys = Object.keys(this.xmlTransform); for (const key of keys) { // replace tags defined in config - xml = xml.replace(new RegExp(key, 'g'), this._appInitService.config['xmlTransform'][this.mapping][key]); + xml = xml.replace(new RegExp(key, 'g'), this.xmlTransform[key]); } - return doctype + openingTextTag + xml + closingTextTag; + if (addXMLDocType) { + return doctype + openingTextTag + xml + closingTextTag; + } else { + return xml; + } } } diff --git a/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.spec.ts b/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.spec.ts index 96c667ca4..833bc4d3f 100644 --- a/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.spec.ts @@ -219,7 +219,7 @@ describe('PropertyViewComponent', () => { it('should show an add button under each property that has a value component and value and appropriate cardinality', () => { const addButtons = propertyViewComponentDe.queryAll(By.css('button.create')); - expect(addButtons.length).toEqual(13); + expect(addButtons.length).toEqual(14); }); @@ -231,8 +231,8 @@ describe('PropertyViewComponent', () => { let addButtons = propertyViewComponentDe.queryAll(By.css('button.create')); - // current amount of buttons should equal 18 because the boolean property shouldn't have an add button if it has a value - expect(addButtons.length).toEqual(18); + // current amount of buttons should equal 19 because the boolean property shouldn't have an add button if it has a value + expect(addButtons.length).toEqual(19); // remove value from the boolean property testHostComponent.propArray[9].values = []; @@ -241,7 +241,7 @@ describe('PropertyViewComponent', () => { // now the boolean property should have an add button so the amount of add buttons on the page should increase by 1 addButtons = propertyViewComponentDe.queryAll(By.css('button.create')); - expect(addButtons.length).toEqual(19); + expect(addButtons.length).toEqual(20); }); @@ -258,7 +258,7 @@ describe('PropertyViewComponent', () => { const addButtons = propertyViewComponentDe.queryAll(By.css('button.create')); // the add button for the property with the open add value form is hidden - expect(addButtons.length).toEqual(12); + expect(addButtons.length).toEqual(13); expect(propertyViewComponentDe.query(By.css('.add-value'))).toBeDefined(); diff --git a/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.ts b/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.ts index 713392069..ba377e5cf 100644 --- a/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.ts +++ b/projects/dsp-ui/src/lib/viewer/views/property-view/property-view.component.ts @@ -104,10 +104,10 @@ export class PropertyViewComponent implements OnInit, OnDestroy { */ addValueIsAllowed(prop: PropertyInfoValues): boolean { // temporary until CkEditor is integrated - const guiElement = (prop.propDef as ResourcePropertyDefinition).guiElement; - if (guiElement === 'http://api.knora.org/ontology/salsah-gui/v2#Richtext') { - return false; - } + // const guiElement = (prop.propDef as ResourcePropertyDefinition).guiElement; + // if (guiElement === 'http://api.knora.org/ontology/salsah-gui/v2#Richtext') { + // return false; + // } const isAllowed = CardinalityUtil.createValueForPropertyAllowed( prop.propDef.id, prop.values.length, this.parentResource.entityInfo.classes[this.parentResource.type]); diff --git a/src/config/config.dev.json b/src/config/config.dev.json index 3b89c3cac..b27268b69 100644 --- a/src/config/config.dev.json +++ b/src/config/config.dev.json @@ -4,17 +4,5 @@ "apiPort": 3333, "apiPath": "", "jsonWebToken": "", - "logErrors": true, - "xmlTransform": { - "http://rdfh.ch/standoff/mappings/StandardMapping": { - "
": "
", - "": "", - "": "", - "": "", - "": "", - "": "", - "
": "", - "
": "" - } - } + "logErrors": true } diff --git a/src/config/config.prod.json b/src/config/config.prod.json index 2e0c58e83..1a5e4a9eb 100644 --- a/src/config/config.prod.json +++ b/src/config/config.prod.json @@ -4,17 +4,5 @@ "apiPort": 3333, "apiPath": "", "jsonWebToken": "", - "logErrors": false, - "xmlTransform": { - "http://rdfh.ch/standoff/mappings/StandardMapping": { - "
": "
", - "": "", - "": "", - "": "", - "": "", - "": "", - "
": "", - "
": "" - } - } + "logErrors": false }