diff --git a/eclipse-scout-core/src/form/fields/FieldStatus.ts b/eclipse-scout-core/src/form/fields/FieldStatus.ts index b7c844ea9ad..7dafccea3a7 100644 --- a/eclipse-scout-core/src/form/fields/FieldStatus.ts +++ b/eclipse-scout-core/src/form/fields/FieldStatus.ts @@ -22,6 +22,7 @@ export class FieldStatus extends Widget implements FieldStatusModel { position: FormFieldStatusPosition; menus: Menu[]; tooltip: Tooltip; + tooltipHtmlEnabled: boolean; contextMenu: ContextMenuPopup; updating: boolean; @@ -34,6 +35,7 @@ export class FieldStatus extends Widget implements FieldStatusModel { constructor() { super(); this.tooltip = null; + this.tooltipHtmlEnabled = false; this.contextMenu = null; this.status = null; this.updating = false; @@ -178,6 +180,10 @@ export class FieldStatus extends Widget implements FieldStatusModel { this.invalidateLayoutTree(); } + setTooltipHtmlEnabled(tooltipHtmlEnabled: boolean) { + this.setProperty('tooltipHtmlEnabled', tooltipHtmlEnabled); + } + protected override _renderVisible() { super._renderVisible(); if (!this.visible) { @@ -278,6 +284,7 @@ export class FieldStatus extends Widget implements FieldStatusModel { if (this.tooltip) { // update existing tooltip this.tooltip.setText(this.status.message); + this.tooltip.setHtmlEnabled(this.tooltipHtmlEnabled); this.tooltip.setSeverity(this.status.severity); this.tooltip.setMenus(this.menus); } else { @@ -285,6 +292,7 @@ export class FieldStatus extends Widget implements FieldStatusModel { parent: this, $anchor: this.$container, text: this.status.message, + htmlEnabled: this.tooltipHtmlEnabled, severity: this.status.severity, autoRemove: this.autoRemove, menus: this.menus diff --git a/eclipse-scout-core/src/form/fields/FormField.ts b/eclipse-scout-core/src/form/fields/FormField.ts index 1fbd10929e8..0b71ceaec8a 100644 --- a/eclipse-scout-core/src/form/fields/FormField.ts +++ b/eclipse-scout-core/src/form/fields/FormField.ts @@ -54,6 +54,7 @@ export class FormField extends Widget implements FormFieldModel { /** If set to true, {@link saveNeeded} will return true as well, even if the value has not been changed. */ touched: boolean; tooltipText: string; + tooltipHtmlEnabled: boolean; font: string; foregroundColor: string; backgroundColor: string; @@ -120,6 +121,7 @@ export class FormField extends Widget implements FormFieldModel { this.suppressStatus = null; this.touched = false; this.tooltipText = null; + this.tooltipHtmlEnabled = false; this.tooltipAnchor = FormField.TooltipAnchor.DEFAULT; this.onFieldTooltipOptionsCreator = null; this.validationResultProvider = this._createValidationResultProvider(); @@ -228,7 +230,8 @@ export class FormField extends Widget implements FormFieldModel { protected _createFieldStatus(): FieldStatus { return scout.create(FieldStatus, { parent: this, - position: this.statusPosition + position: this.statusPosition, + tooltipHtmlEnabled: this.tooltipHtmlEnabled }); } @@ -495,6 +498,15 @@ export class FormField extends Widget implements FormFieldModel { this._updateTooltip(); } + /** @see FormFieldModel.tooltipHtmlEnabled */ + setTooltipHtmlEnabled(tooltipHtmlEnabled: boolean) { + this.setProperty('tooltipHtmlEnabled', tooltipHtmlEnabled); + } + + protected _renderTooltipHtmlEnabled() { + this._updateTooltip(); + } + /** @see FormFieldModel.tooltipAnchor */ setTooltipAnchor(tooltipAnchor: FormFieldTooltipAnchor) { this.setProperty('tooltipAnchor', tooltipAnchor); @@ -692,6 +704,7 @@ export class FormField extends Widget implements FormFieldModel { let statusVisible = this._computeStatusVisible(); this.fieldStatus.setPosition(this.statusPosition); this.fieldStatus.setVisible(statusVisible); + this.fieldStatus.setTooltipHtmlEnabled(this.tooltipHtmlEnabled); if (!statusVisible) { this.fieldStatus.setMenus(null); this.fieldStatus.setStatus(null); diff --git a/eclipse-scout-core/src/form/fields/FormFieldModel.ts b/eclipse-scout-core/src/form/fields/FormFieldModel.ts index 552346f07d0..a7d7ef3dc37 100644 --- a/eclipse-scout-core/src/form/fields/FormFieldModel.ts +++ b/eclipse-scout-core/src/form/fields/FormFieldModel.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -144,6 +144,12 @@ export interface FormFieldModel extends WidgetModel { * The text to be used in the {@link Tooltip} that is either displayed in the status area or when hovering over the field, depending on {@link tooltipAnchor}. */ tooltipText?: string; + /** + * Defines whether HTML code in the {@link tooltipText} property should be interpreted. If set to false, the HTML will be encoded. + * + * Default is false. + */ + tooltipHtmlEnabled?: boolean; /** * Defines where and how the tooltip configured by {@link tooltipText} should appear. * diff --git a/eclipse-scout-core/test/form/fields/FormFieldSpec.ts b/eclipse-scout-core/test/form/fields/FormFieldSpec.ts index 37781d3cc3c..0ad45a2048a 100644 --- a/eclipse-scout-core/test/form/fields/FormFieldSpec.ts +++ b/eclipse-scout-core/test/form/fields/FormFieldSpec.ts @@ -256,6 +256,72 @@ describe('FormField', () => { }); + describe('property tooltipHtmlEnabled', () => { + + it('if false, encodes html in tooltip', () => { + let field = scout.create(StringField, { + parent: session.desktop, + tooltipText: 'text' + }); + field.render(); + field.fieldStatus.doAction(); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(false); + expect(field.fieldStatus.tooltip.$content.html()).toBe('<b>text</b>'); + }); + + it('if true, does not encode html in tooltip', () => { + let field = scout.create(StringField, { + parent: session.desktop, + tooltipText: 'text', + tooltipHtmlEnabled: true + }); + field.render(); + field.fieldStatus.doAction(); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(true); + expect(field.fieldStatus.tooltip.$content.html()).toBe('text'); + }); + + it('can be changed dynamically', () => { + let field = scout.create(StringField, { + parent: session.desktop, + tooltipText: 'text' + }); + field.render(); + field.setTooltipHtmlEnabled(true); + field.fieldStatus.doAction(); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(true); + expect(field.fieldStatus.tooltip.$content.html()).toBe('text'); + + field.setTooltipHtmlEnabled(false); // closes tooltip + field.fieldStatus.doAction(); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(false); + expect(field.fieldStatus.tooltip.$content.html()).toBe('<b>text</b>'); + }); + + it('also affects error status tooltip', () => { + let field = scout.create(StringField, { + parent: session.desktop, + errorStatus: { + message: 'error', + severity: Status.Severity.ERROR + }, + tooltipHtmlEnabled: true + }); + field.render(); + // Tooltip is already open because tooltip.autoRemove is false on severity error + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(true); + expect(field.fieldStatus.tooltip.$content.html()).toBe('error'); + + field.setTooltipHtmlEnabled(false); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(false); + expect(field.fieldStatus.tooltip.$content.html()).toBe('<b>error</b>'); + + field.setTooltipHtmlEnabled(true); + expect(field.fieldStatus.tooltip.htmlEnabled).toBe(true); + expect(field.fieldStatus.tooltip.$content.html()).toBe('error'); + }); + }); + describe('property menus', () => { let formField, model; diff --git a/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/AbstractFormField.java b/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/AbstractFormField.java index eef24b50e81..5c6f43af96b 100644 --- a/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/AbstractFormField.java +++ b/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/AbstractFormField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -322,6 +322,12 @@ protected String getConfiguredTooltipText() { return null; } + @ConfigProperty(ConfigProperty.BOOLEAN) + @Order(52) + protected boolean getConfiguredTooltipHtmlEnabled() { + return false; + } + /** * @return One of the TOOLTIP_ANCHOR_* constants. Default is {@link #TOOLTIP_ANCHOR_DEFAULT}. */ @@ -857,6 +863,7 @@ protected void initConfig() { setMandatory(getConfiguredMandatory()); setOrder(calculateViewOrder()); setTooltipText(getConfiguredTooltipText()); + setTooltipHtmlEnabled(getConfiguredTooltipHtmlEnabled()); setTooltipAnchor(getConfiguredTooltipAnchor()); setInitialLabel(getConfiguredLabel()); setLabel(getConfiguredLabel()); @@ -1833,6 +1840,16 @@ public String getTooltipText() { return propertySupport.getPropertyString(PROP_TOOLTIP_TEXT); } + @Override + public void setTooltipHtmlEnabled(boolean tooltipHtmlEnabled) { + propertySupport.setPropertyBool(PROP_TOOLTIP_HTML_ENABLED, tooltipHtmlEnabled); + } + + @Override + public boolean isTooltipHtmlEnabled() { + return propertySupport.getPropertyBool(PROP_TOOLTIP_HTML_ENABLED); + } + @Override public void setTooltipAnchor(String tooltipAnchor) { propertySupport.setPropertyString(PROP_TOOLTIP_ANCHOR, tooltipAnchor); diff --git a/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/IFormField.java b/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/IFormField.java index 1d73753c726..65f779ba64c 100644 --- a/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/IFormField.java +++ b/org.eclipse.scout.rt.client/src/main/java/org/eclipse/scout/rt/client/ui/form/fields/IFormField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -73,6 +73,7 @@ public interface IFormField extends IWidget, IOrdered, IStyleable, IVisibleDimen String PROP_ORDER = "order"; String PROP_ERROR_STATUS = "errorStatus"; String PROP_TOOLTIP_TEXT = "tooltipText"; + String PROP_TOOLTIP_HTML_ENABLED = "tooltipHtmlEnabled"; String PROP_TOOLTIP_ANCHOR = "tooltipAnchor"; String PROP_FOREGROUND_COLOR = "foregroundColor"; String PROP_BACKGROUND_COLOR = "backgroundColor"; @@ -465,6 +466,10 @@ public interface IFormField extends IWidget, IOrdered, IStyleable, IVisibleDimen void setTooltipText(String text); + boolean isTooltipHtmlEnabled(); + + void setTooltipHtmlEnabled(boolean tooltipHtmlEnabled); + void setTooltipAnchor(String tooltipAnchor); String getTooltipAnchor(); diff --git a/org.eclipse.scout.rt.ui.html/src/main/java/org/eclipse/scout/rt/ui/html/json/form/fields/JsonFormField.java b/org.eclipse.scout.rt.ui.html/src/main/java/org/eclipse/scout/rt/ui/html/json/form/fields/JsonFormField.java index 9c44098a772..7db799a979e 100644 --- a/org.eclipse.scout.rt.ui.html/src/main/java/org/eclipse/scout/rt/ui/html/json/form/fields/JsonFormField.java +++ b/org.eclipse.scout.rt.ui.html/src/main/java/org/eclipse/scout/rt/ui/html/json/form/fields/JsonFormField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -101,6 +101,12 @@ protected String modelValue() { return getModel().getTooltipText(); } }); + putJsonProperty(new JsonProperty(IFormField.PROP_TOOLTIP_HTML_ENABLED, model) { + @Override + protected Boolean modelValue() { + return getModel().isTooltipHtmlEnabled(); + } + }); putJsonProperty(new JsonProperty(IFormField.PROP_TOOLTIP_ANCHOR, model) { @Override protected String modelValue() {