@sapui5/sap.ui.richtexteditor 1.139.0 → 1.141.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/src/sap/ui/richtexteditor/.library +1 -1
  3. package/src/sap/ui/richtexteditor/RTESplitButton.js +1 -1
  4. package/src/sap/ui/richtexteditor/RichTextEditor.js +49 -5
  5. package/src/sap/ui/richtexteditor/RichTextEditorFontFamily.js +78 -0
  6. package/src/sap/ui/richtexteditor/ToolbarWrapper.js +123 -60
  7. package/src/sap/ui/richtexteditor/js/styles/RichTextEditor.css +0 -3
  8. package/src/sap/ui/richtexteditor/library.js +56 -38
  9. package/src/sap/ui/richtexteditor/messagebundle.properties +3 -0
  10. package/src/sap/ui/richtexteditor/messagebundle_ar.properties +3 -0
  11. package/src/sap/ui/richtexteditor/messagebundle_bg.properties +3 -0
  12. package/src/sap/ui/richtexteditor/messagebundle_ca.properties +3 -0
  13. package/src/sap/ui/richtexteditor/messagebundle_cnr.properties +3 -0
  14. package/src/sap/ui/richtexteditor/messagebundle_cs.properties +3 -0
  15. package/src/sap/ui/richtexteditor/messagebundle_cy.properties +3 -0
  16. package/src/sap/ui/richtexteditor/messagebundle_da.properties +4 -1
  17. package/src/sap/ui/richtexteditor/messagebundle_de.properties +3 -0
  18. package/src/sap/ui/richtexteditor/messagebundle_el.properties +3 -0
  19. package/src/sap/ui/richtexteditor/messagebundle_en.properties +3 -0
  20. package/src/sap/ui/richtexteditor/messagebundle_en_GB.properties +3 -0
  21. package/src/sap/ui/richtexteditor/messagebundle_en_US_saprigi.properties +3 -0
  22. package/src/sap/ui/richtexteditor/messagebundle_es.properties +3 -0
  23. package/src/sap/ui/richtexteditor/messagebundle_es_MX.properties +3 -0
  24. package/src/sap/ui/richtexteditor/messagebundle_et.properties +3 -0
  25. package/src/sap/ui/richtexteditor/messagebundle_fi.properties +3 -0
  26. package/src/sap/ui/richtexteditor/messagebundle_fr.properties +3 -0
  27. package/src/sap/ui/richtexteditor/messagebundle_fr_CA.properties +3 -0
  28. package/src/sap/ui/richtexteditor/messagebundle_hi.properties +3 -0
  29. package/src/sap/ui/richtexteditor/messagebundle_hr.properties +3 -0
  30. package/src/sap/ui/richtexteditor/messagebundle_hu.properties +3 -0
  31. package/src/sap/ui/richtexteditor/messagebundle_id.properties +4 -1
  32. package/src/sap/ui/richtexteditor/messagebundle_it.properties +3 -0
  33. package/src/sap/ui/richtexteditor/messagebundle_iw.properties +3 -0
  34. package/src/sap/ui/richtexteditor/messagebundle_ja.properties +3 -0
  35. package/src/sap/ui/richtexteditor/messagebundle_kk.properties +3 -0
  36. package/src/sap/ui/richtexteditor/messagebundle_ko.properties +3 -0
  37. package/src/sap/ui/richtexteditor/messagebundle_lt.properties +3 -0
  38. package/src/sap/ui/richtexteditor/messagebundle_lv.properties +3 -0
  39. package/src/sap/ui/richtexteditor/messagebundle_mk.properties +3 -0
  40. package/src/sap/ui/richtexteditor/messagebundle_ms.properties +3 -0
  41. package/src/sap/ui/richtexteditor/messagebundle_nl.properties +3 -0
  42. package/src/sap/ui/richtexteditor/messagebundle_no.properties +3 -0
  43. package/src/sap/ui/richtexteditor/messagebundle_pl.properties +3 -0
  44. package/src/sap/ui/richtexteditor/messagebundle_pt.properties +3 -0
  45. package/src/sap/ui/richtexteditor/messagebundle_pt_PT.properties +3 -0
  46. package/src/sap/ui/richtexteditor/messagebundle_ro.properties +3 -0
  47. package/src/sap/ui/richtexteditor/messagebundle_ru.properties +3 -0
  48. package/src/sap/ui/richtexteditor/messagebundle_sh.properties +3 -0
  49. package/src/sap/ui/richtexteditor/messagebundle_sk.properties +3 -0
  50. package/src/sap/ui/richtexteditor/messagebundle_sl.properties +3 -0
  51. package/src/sap/ui/richtexteditor/messagebundle_sr.properties +3 -0
  52. package/src/sap/ui/richtexteditor/messagebundle_sv.properties +3 -0
  53. package/src/sap/ui/richtexteditor/messagebundle_th.properties +3 -0
  54. package/src/sap/ui/richtexteditor/messagebundle_tr.properties +3 -0
  55. package/src/sap/ui/richtexteditor/messagebundle_uk.properties +3 -0
  56. package/src/sap/ui/richtexteditor/messagebundle_vi.properties +3 -0
  57. package/src/sap/ui/richtexteditor/messagebundle_zh_CN.properties +3 -0
  58. package/src/sap/ui/richtexteditor/messagebundle_zh_TW.properties +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapui5/sap.ui.richtexteditor",
3
- "version": "1.139.0",
3
+ "version": "1.141.0",
4
4
  "description": "SAPUI5 Library sap.ui.richtexteditor",
5
5
  "homepage": "https://sap.github.io/ui5-tooling/pages/SAPUI5/",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -5,7 +5,7 @@
5
5
  <vendor>SAP SE</vendor>
6
6
  <copyright>SAPUI5
7
7
  * (c) Copyright 2025 SAP SE. All rights reserved.</copyright>
8
- <version>1.139.0</version>
8
+ <version>1.141.0</version>
9
9
 
10
10
  <documentation>A rich text editor (RTE) control. Requires installation of an additional rich text editor library.</documentation>
11
11
 
@@ -24,7 +24,7 @@ sap.ui.define([
24
24
  * @alias sap.ui.richtexteditor.RTESplitButton
25
25
  *
26
26
  * @author SAP SE
27
- * @version 1.139.0
27
+ * @version 1.141.0
28
28
  */
29
29
  var RTESplitButton = SplitButton.extend("sap.ui.richtexteditor.RTESplitButton", {
30
30
  metadata: {
@@ -372,11 +372,18 @@ sap.ui.define([
372
372
  /**
373
373
  * Custom buttons are meant to extend the <code>RichTextEditor</code>'s custom toolbar.
374
374
  * Though type is set to sap.ui.Control, only sap.m.Button is allowed.
375
- * <b>Note:</b> customButtons are available only when the customToolbar is enabled and all the requirements are fulfilled.
375
+ * <b>Note:</b> customButtons are available only when the <code>customToolbar</code> is enabled and all the requirements are fulfilled.
376
376
  *
377
377
  * @since 1.48
378
378
  */
379
- customButtons: {type: "sap.ui.core.Control", multiple: true, singularName: "customButton", defaultValue: null}
379
+ customButtons: {type: "sap.ui.core.Control", multiple: true, singularName: "customButton", defaultValue: null},
380
+ /**
381
+ * Custom font families that can be used in the <code>RichTextEditor</code>.
382
+ * <b>Note:</b> Custom fonts are available only when the <code>customToolbar</code> is enabled.
383
+ *
384
+ * @since 1.141
385
+ */
386
+ customFonts: {type: "sap.ui.richtexteditor.RichTextEditorFontFamily", multiple: true, singularName: "customFont", defaultValue: null}
380
387
  },
381
388
  associations: {
382
389
  /**
@@ -412,6 +419,9 @@ sap.ui.define([
412
419
  */
413
420
  RichTextEditor.EDITORTYPE_TINYMCE5 = library.EditorType.TinyMCE5;
414
421
 
422
+ /**
423
+ * @deprecated As of version 1.141.0
424
+ */
415
425
  RichTextEditor.EDITORTYPE_TINYMCE6 = library.EditorType.TinyMCE6;
416
426
 
417
427
  RichTextEditor.EDITORTYPE_TINYMCE7 = library.EditorType.TinyMCE7;
@@ -448,6 +458,9 @@ sap.ui.define([
448
458
  "powerpaste"
449
459
  ];
450
460
 
461
+ /**
462
+ * @deprecated As of version 1.141.0
463
+ */
451
464
  RichTextEditor.DEFAULT_PLUGINS_TINYMCE6 = [
452
465
  "emoticons",
453
466
  "directionality",
@@ -1305,11 +1318,14 @@ sap.ui.define([
1305
1318
  * @deprecated As of version 1.120
1306
1319
  */
1307
1320
  if (oEditorMapping[sEditorType] === "TinyMCE5") {
1308
- Log.error("TinyMCE version 5 is used as editor type. TinyMCE 5 is deprecated and will be removed from the code entirely in near future.");
1321
+ Log.error("TinyMCE version 5 is used as editor type. TinyMCE 5 is deprecated and will be removed from the code entirely at the beginning of 2026. The latest version will be automatically loaded instead.");
1309
1322
  }
1310
1323
 
1324
+ /**
1325
+ * @deprecated As of version 1.141.0
1326
+ */
1311
1327
  if (oEditorMapping[sEditorType] === "TinyMCE6") {
1312
- Log.warning("TinyMCE version 6 is used as editor type. TinyMCE 6 will be deprecated and removed from the code entirely in near future.");
1328
+ Log.error("TinyMCE version 6 is used as editor type. TinyMCE 6 is deprecated as of version 1.141.0 and will be removed from the code entirely in near future.");
1313
1329
  }
1314
1330
 
1315
1331
  this.initTinyMCE();
@@ -1932,7 +1948,6 @@ sap.ui.define([
1932
1948
  toolbar_items_size: 'small',
1933
1949
  toolbar: aButtonRows,
1934
1950
  toolbar_mode: "sliding",
1935
- content_css: [sap.ui.require.toUrl("sap/ui/richtexteditor/js/styles/RichTextEditor.css")],
1936
1951
  statusbar: false, // disables display of the status bar at the bottom of the editor
1937
1952
  image_advtab: true, // Adds an "Advanced" tab to the image dialog allowing you to add custom styles, spacing and borders to images
1938
1953
  readonly: !this.getEditable(),
@@ -1943,6 +1958,7 @@ sap.ui.define([
1943
1958
  sandbox_iframes: true, // default for v.7, remove after upgrade
1944
1959
  init_instance_callback: function(oEditor) {
1945
1960
  this._oEditor = oEditor;
1961
+ this._insertCustomFonts();
1946
1962
  fnOnInit();
1947
1963
  }.bind(this)
1948
1964
  };
@@ -1961,6 +1977,34 @@ sap.ui.define([
1961
1977
  return oConfig;
1962
1978
  };
1963
1979
 
1980
+ RichTextEditor.prototype._insertCustomFonts = function() {
1981
+ const doc = this._oEditor?.getDoc();
1982
+
1983
+ if (!doc) {
1984
+ return;
1985
+ }
1986
+
1987
+ const head = doc.getElementsByTagName("head")[0];
1988
+ const style = doc.getElementById("custom-fonts") || doc.createElement("style");
1989
+ style?.setAttribute("id", "custom-fonts");
1990
+
1991
+ const fontImports = this.getCustomFonts().map((oFont) => {
1992
+ return `@import url('${oFont.getUrl()}');`;
1993
+ }).join("\n");
1994
+
1995
+ const currentFonts = style?.textContent || "";
1996
+
1997
+ if (currentFonts === fontImports) {
1998
+ return;
1999
+ }
2000
+
2001
+ style.textContent = fontImports;
2002
+
2003
+ if (head && style) {
2004
+ head.appendChild(style);
2005
+ }
2006
+ };
2007
+
1964
2008
 
1965
2009
  /**
1966
2010
  * Map languages that are incorrectly assigned or fallback if languages do not work
@@ -0,0 +1,78 @@
1
+ /*!
2
+ * SAPUI5
3
+ * (c) Copyright 2025 SAP SE. All rights reserved.
4
+ */
5
+
6
+ // Provides control sap.ui.richtexteditor.RichTextEditorFontFamily.
7
+ sap.ui.define([
8
+ "sap/ui/core/Element",
9
+ "sap/base/Log",
10
+ "./library"
11
+ ], function(Element, Log, library) {
12
+ "use strict";
13
+
14
+ /**
15
+ * Constructor for a new <code>RichTextEditorFontFamily</code>.
16
+ *
17
+ * @param {string} [sId] id for the new control, generated automatically if no id is given
18
+ * @param {object} [mSettings] initial settings for the new control
19
+ *
20
+ * @class
21
+ * Represents a font family option for <code>RichTextEditor</code>.
22
+ * @extends sap.ui.core.Element
23
+ *
24
+ * @author SAP SE
25
+ * @version 1.141.0
26
+ *
27
+ * @public
28
+ * @alias sap.ui.richtexteditor.RichTextEditorFontFamily
29
+ */
30
+ var RichTextEditorFontFamily = Element.extend("sap.ui.richtexteditor.RichTextEditorFontFamily", /** @lends sap.ui.richtexteditor.RichTextEditorFontFamily.prototype */ {
31
+ metadata : {
32
+ library : "sap.ui.richtexteditor",
33
+ properties : {
34
+
35
+ /**
36
+ * Used to identify the font in the editor.
37
+ * Names should be unique and descriptive.
38
+ */
39
+ name : {type : "string", group : "Misc", defaultValue : null},
40
+
41
+ /**
42
+ * The text displayed in the font family dropdown.
43
+ */
44
+ text : {type : "string", group : "Misc", defaultValue : null},
45
+
46
+ /**
47
+ * The value of the font family.
48
+ * CSS font-family value that will be applied to the text.
49
+ */
50
+ value : {type : "string", group : "Misc", defaultValue : null},
51
+
52
+ /**
53
+ * Used to load the font.
54
+ * The URL should point to a CSS file that defines the font-face.
55
+ */
56
+ url : {type: "sap.ui.core.URI", group : "Data", defaultValue : null}
57
+ }
58
+ }
59
+ });
60
+
61
+ RichTextEditorFontFamily.prototype.validateProperty = function(sPropertyName, oValue) {
62
+ if (sPropertyName === "url") {
63
+ var sUrl = Element.prototype.validateProperty.call(this, sPropertyName, oValue);
64
+
65
+ // Stronger validation to prevent CSS injection
66
+ if (sUrl && /[<>()'"\\]|\/\*|\*\/|javascript:|data:/i.test(sUrl)) {
67
+ Log.Error("RichTextEditorFontFamily: URL contains potentially dangerous characters: " + sUrl, this);
68
+ return "";
69
+ }
70
+
71
+ return sUrl;
72
+ }
73
+ return Element.prototype.validateProperty.call(this, sPropertyName, oValue);
74
+ };
75
+
76
+ return RichTextEditorFontFamily;
77
+
78
+ });
@@ -39,6 +39,11 @@ sap.ui.define([
39
39
  ButtonsToCommandsMap = library.ButtonsToCommandsMap,
40
40
  ButtonType = mLibrary.ButtonType;
41
41
 
42
+ const SYSTEM_FONT_CHROME = "-apple-system,system-ui,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif";
43
+ // Safari and FF return BlinkMacSystemFont, Chrome returns system-ui
44
+ const SYSTEM_FONT_LEGACY = "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif";
45
+ const SYSTEM_FONT_KEY = "custom-font-family";
46
+
42
47
  /**
43
48
  * Constructor for a new RichTextEditor's Custom Toolbar.
44
49
  *
@@ -105,6 +110,7 @@ sap.ui.define([
105
110
  this._oAccessibilityTexts = {};
106
111
  this._sTextColor = EditorCommands.TextColor.defaultValue;
107
112
  this._sBackgroundColor = EditorCommands.BackgroundColor.defaultValue;
113
+ this._oPreservedMergetagSelection = null;
108
114
  };
109
115
 
110
116
  ToolbarWrapper.prototype.onBeforeRendering = function () {
@@ -157,6 +163,7 @@ sap.ui.define([
157
163
  this._sTextColor = null;
158
164
  this._sBackgroundColor = null;
159
165
  this._bLinkPrefixChecked = null;
166
+ this._oPreservedMergetagSelection = null;
160
167
  };
161
168
 
162
169
  /**
@@ -291,6 +298,17 @@ sap.ui.define([
291
298
  editor.on('NodeChange', function () {
292
299
  that._syncToolbarStates(this);
293
300
  });
301
+
302
+ // When using mergetags plugin, the selection is lost when the user clicks on a toolbar action.
303
+ // This is a workaround to restore the last selection made by the user.
304
+ editor.on('SelectionChange', function() {
305
+ var oSelectionNode = this.selection.getNode();
306
+ if (oSelectionNode && oSelectionNode.classList && oSelectionNode.classList.contains('mce-mergetag')) {
307
+ that._oPreservedMergetagSelection = oSelectionNode;
308
+ } else {
309
+ that._oPreservedMergetagSelection = null;
310
+ }
311
+ });
294
312
  };
295
313
 
296
314
  return oConfig;
@@ -309,6 +327,7 @@ sap.ui.define([
309
327
  // Prevent losing the focus to the overflow toolbar button after the menu popover is closed
310
328
  setTimeout(function(){
311
329
  if (bDefaultColor || this._getColor(sCommand).replace(/,\s/g, ',') !== sColor) {
330
+ this._restoreMergetagSelection();
312
331
  this.getEditor().getNativeApi().execCommand(sCommandName, false, sColor);
313
332
  }
314
333
  }.bind(this), 0);
@@ -347,6 +366,7 @@ sap.ui.define([
347
366
  var oEditorCommand, oControl, sEditorCommand,
348
367
  oFormatter = oNativeEditor.formatter,
349
368
  oResourceBundle = this._oResourceBundle,
369
+ that = this,
350
370
  _syncTextAlign = function (oTextAlignCommand, oEditorFormatter, oControl) {
351
371
  var sAlignCommand, sIconUri, oCommand;
352
372
 
@@ -386,29 +406,6 @@ sap.ui.define([
386
406
  }
387
407
  }
388
408
  },
389
- _syncTextFontFamily = function (oEditor, oFontFamilyCommand, oControl) {
390
- var sFontName, sCommandValue, sText, sItemId,
391
- sFontNameCommandValue = oEditor.getDoc().queryCommandValue("FontName");
392
-
393
- // Synchronize the selected item of the Font Family Select with the applied font family style
394
- for (sFontName in oFontFamilyCommand) {
395
- if (!oFontFamilyCommand.hasOwnProperty(sFontName)) {
396
- continue;
397
- }
398
- sItemId = oControl.getId() + sFontName;
399
-
400
- sCommandValue = oFontFamilyCommand[sFontName].commandValue.match(/\w+/g).join("").toLowerCase();
401
- sFontNameCommandValue = sFontNameCommandValue && sFontNameCommandValue.match(/\w+/g)?.join("").toLowerCase();
402
- sText = oFontFamilyCommand[sFontName].text.match(/\w+/g).join("").toLowerCase();
403
-
404
- // the selected item should be changed, only when the new one is different
405
- if ((oControl.getSelectedItemId() !== sItemId) &&
406
- (sCommandValue === sFontNameCommandValue || sFontNameCommandValue === sText)) {
407
- oControl.setSelectedItemId(sItemId);
408
- break;
409
- }
410
- }
411
- },
412
409
  _syncImage = function (oEditor, oControl) {
413
410
  var oSelection = oEditor.selection.getNode(),
414
411
  bImage = oSelection && oSelection.tagName.toLowerCase() === "img" ||
@@ -445,9 +442,32 @@ sap.ui.define([
445
442
  case "TextAlign":
446
443
  _syncTextAlign(oEditorCommand, oFormatter, oControl);
447
444
  break;
448
- case "FontFamily":
449
- _syncTextFontFamily(oNativeEditor, oEditorCommand, oControl);
445
+ case "FontFamily": {
446
+ let sFontName = oNativeEditor.queryCommandValue("FontName");
447
+ const bSystemFont = sFontName.includes(SYSTEM_FONT_CHROME) || sFontName.includes(SYSTEM_FONT_LEGACY);
448
+
449
+ // Enhanced mergetag font family detection
450
+ if (that._oPreservedMergetagSelection) {
451
+ var oPreservedComputedStyle = oNativeEditor.getDoc().defaultView.getComputedStyle(that._oPreservedMergetagSelection);
452
+ sFontName = oPreservedComputedStyle.fontFamily || sFontName;
453
+ }
454
+
455
+ if (bSystemFont) {
456
+ oControl.setSelectedKey(SYSTEM_FONT_KEY);
457
+ oControl.getSelectedItem()?.setText(oResourceBundle.getText("FONT_FAMILY_DEFAULT_TEXT"));
458
+ break;
459
+ }
460
+
461
+ const bExistingFont = oControl.getItems().find((oItem) => oItem.getKey() === sFontName);
462
+
463
+ if (bExistingFont) {
464
+ oControl.setSelectedKey(sFontName);
465
+ } else {
466
+ oControl.setSelectedKey(SYSTEM_FONT_KEY);
467
+ oControl.getSelectedItem()?.setText(sFontName);
468
+ }
450
469
  break;
470
+ }
451
471
  case "FormatBlock":
452
472
  _syncTextFormatBlock(oNativeEditor, oEditorCommand, oControl);
453
473
  break;
@@ -502,7 +522,8 @@ sap.ui.define([
502
522
  */
503
523
  ToolbarWrapper.prototype._createButtonConfig = function (sCommand) {
504
524
  var oCommand = EditorCommands[sCommand],
505
- oRTE = this.getEditor();
525
+ oRTE = this.getEditor(),
526
+ that = this;
506
527
 
507
528
  return {
508
529
  id: this._getId(sCommand),
@@ -511,6 +532,7 @@ sap.ui.define([
511
532
  text: this._oResourceBundle.getText(oCommand.bundleKey),
512
533
  press: function () {
513
534
  if (oRTE) {
535
+ that._restoreMergetagSelection();
514
536
  oRTE.getNativeApi().execCommand(oCommand.command);
515
537
  } else {
516
538
  Log.warning("Cannot execute native command: " + oCommand.command);
@@ -575,37 +597,25 @@ sap.ui.define([
575
597
  * @private
576
598
  */
577
599
  ToolbarWrapper.prototype._createFontStyleSelectItems = function () {
578
- var oFontFamilies = EditorCommands["FontFamily"],
579
- aItems = [],
580
- oItem;
581
-
582
- for (var sFontStyle in oFontFamilies) {
583
- oItem = {
584
- id: this._getId("FontFamily" + sFontStyle),
585
- text: oFontFamilies[sFontStyle].text
586
- };
587
-
588
- aItems.push(new Item(oItem));
589
- }
590
-
591
- return aItems;
592
- };
593
-
594
- /**
595
- * Helper function for finding the command value of a given font style command
596
- *
597
- * @param {string} [sItemText] Font Family
598
- * @returns {string} The command value of the given font style
599
- * @private
600
- */
601
- ToolbarWrapper.prototype._getFontStyleCommand = function (sItemText) {
602
- var oFontFamilies = EditorCommands["FontFamily"];
600
+ const aFontFamilies = EditorCommands["FontFamily"];
601
+ const aCustomFonts = this.getEditor().getCustomFonts();
602
+ const cleanFontString = (fontKey) => {
603
+ return fontKey
604
+ .replace(/['"]/g, "")
605
+ .replace(/,\s+/g, ",");
606
+ };
603
607
 
604
- for (var sFontStyle in oFontFamilies) {
605
- if (oFontFamilies.hasOwnProperty(sFontStyle) && oFontFamilies[sFontStyle].text === sItemText) {
606
- return oFontFamilies[sFontStyle].commandValue;
607
- }
608
- }
608
+ return [...aFontFamilies.map((oFontFamily) => {
609
+ return new Item({
610
+ text: oFontFamily.text,
611
+ key: oFontFamily.value
612
+ });
613
+ }), ...aCustomFonts.map((oFont) => {
614
+ return new Item({
615
+ text: oFont.getText(),
616
+ key: cleanFontString(oFont.getValue())
617
+ });
618
+ })];
609
619
  };
610
620
 
611
621
  /**
@@ -727,6 +737,9 @@ sap.ui.define([
727
737
  }
728
738
  },
729
739
  arrowPress: function () {
740
+ // Preserve mergetag selection before opening popover
741
+ that._preserveMergetagSelection();
742
+
730
743
  oDialog = that.getAggregation("_custom" + sCommand + "Dialog");
731
744
 
732
745
  this._getArrowButton()._activeButton();
@@ -1593,14 +1606,21 @@ sap.ui.define([
1593
1606
  this._helper.createSelect({
1594
1607
  id: this._getId("FontFamily"),
1595
1608
  ariaLabelledBy: oInvisibleTextFontFamily,
1596
- selectedItemId: this._getId("FontFamilyVerdana"),
1597
- items: this._createFontStyleSelectItems(),
1609
+ items: [
1610
+ ...this._createFontStyleSelectItems(),
1611
+ new Item({
1612
+ key: "custom-font-family",
1613
+ enabled: false
1614
+ })
1615
+ ],
1598
1616
  change: function (oEvent) {
1617
+ that._preserveMergetagSelection();
1599
1618
  var oItem;
1600
1619
 
1601
1620
  if (oRTE) {
1602
1621
  oItem = oEvent.getSource().getSelectedItem();
1603
- oRTE.getNativeApi().execCommand('FontName', false, that._getFontStyleCommand(oItem.getText()));
1622
+ that._restoreMergetagSelection();
1623
+ oRTE.getNativeApi().execCommand('FontName', false, oItem.getKey());
1604
1624
  } else {
1605
1625
  Log.warning("Cannot execute native command: " + 'FontName');
1606
1626
  }
@@ -1629,10 +1649,12 @@ sap.ui.define([
1629
1649
  })
1630
1650
  ],
1631
1651
  change: function (oEvent) {
1652
+ that._preserveMergetagSelection();
1632
1653
  var oItem;
1633
1654
 
1634
1655
  if (oRTE) {
1635
1656
  oItem = oEvent.getSource().getSelectedItem();
1657
+ that._restoreMergetagSelection();
1636
1658
  oRTE.getNativeApi().execCommand('FontSize', false, oItem.getText().replace(/\s/g, ""));
1637
1659
  } else {
1638
1660
  Log.warning("Cannot execute native command: " + 'FontSize');
@@ -1671,22 +1693,26 @@ sap.ui.define([
1671
1693
  ToolbarWrapper.prototype._createTextAlignToolbarContent = function (bVisible) {
1672
1694
  var oRTE = this.getEditor();
1673
1695
  var bGroupVisible = oRTE ? oRTE.getShowGroupFontStyle() || bVisible : false;
1674
- var that = this;
1675
1696
  var bTextAlignLRight = oRTE._getTextDirection() === "rtl";
1676
1697
  var iDefaultItemIndex = bTextAlignLRight ? 2 : 0;
1677
1698
  var aMenuItems = this._createMenuButtonItems("TextAlign");
1699
+ var that = this;
1678
1700
 
1679
1701
  return [
1680
1702
  this._helper.createMenuButton(
1681
1703
  this._getId("TextAlign"),
1682
1704
  aMenuItems,
1683
1705
  function (oEvent) {
1706
+ that._preserveMergetagSelection();
1684
1707
  var oSelectedItem, oEditor, oSelectedItemIcon;
1708
+ var oPreservedNode = that._oPreservedMergetagSelection;
1685
1709
 
1686
1710
  if (oRTE) {
1687
1711
  oSelectedItem = oEvent.getParameter("item");
1688
1712
  oEditor = oRTE.getNativeApi();
1689
1713
  oSelectedItemIcon = oSelectedItem.getIcon();
1714
+
1715
+ that._restoreMergetagSelection();
1690
1716
  if (oSelectedItemIcon === this.getParent().getIcon()) {
1691
1717
  var sTextAlign = bTextAlignLRight ? "JustifyRight" : "JustifyLeft";
1692
1718
  // Text Align commands in TinyMCE have a toggle behavior when you set a
@@ -1695,6 +1721,14 @@ sap.ui.define([
1695
1721
  } else {
1696
1722
  oEditor.execCommand('Justify' + that._findTextAlignCommandByIcon(oSelectedItemIcon));
1697
1723
  }
1724
+
1725
+ // Restore mergetag selection after TinyMCE moves focus
1726
+ if (oPreservedNode && oPreservedNode.classList && oPreservedNode.classList.contains('mce-mergetag')) {
1727
+ // Prevent losing the focus to the overflow toolbar button after the menu popover is closed
1728
+ requestAnimationFrame(function() {
1729
+ oEditor.selection.select(oPreservedNode);
1730
+ });
1731
+ }
1698
1732
  } else {
1699
1733
  Log.warning("Cannot execute native command: " + 'Justify');
1700
1734
  }
@@ -1706,6 +1740,7 @@ sap.ui.define([
1706
1740
  };
1707
1741
 
1708
1742
  ToolbarWrapper.prototype._createFormatSelectToolbarContent = function (bVisible) {
1743
+ var that = this;
1709
1744
  var oRTE = this.getEditor();
1710
1745
  var oAccessibilityKeys = library.Accessibility;
1711
1746
  var oInvisibleTextFormatBlock = this._helper.createInvisibleText({
@@ -1720,10 +1755,12 @@ sap.ui.define([
1720
1755
  ariaLabelledBy: oInvisibleTextFormatBlock,
1721
1756
  items: this._createFormatBlockItems(),
1722
1757
  change: function (oEvent) {
1758
+ that._preserveMergetagSelection();
1723
1759
  var oSelectedItem;
1724
1760
  if (oRTE) {
1725
1761
  oSelectedItem = oEvent.getSource().getSelectedItem();
1726
1762
  if (oSelectedItem) {
1763
+ that._restoreMergetagSelection();
1727
1764
  var currentFormatterCommand = oRTE.getAggregation("_toolbarWrapper")._getFormatBlockCommand(oSelectedItem.getText());
1728
1765
  oRTE.getNativeApi().execCommand('FormatBlock', false, currentFormatterCommand);
1729
1766
  }
@@ -2352,5 +2389,31 @@ sap.ui.define([
2352
2389
  return Element.getElementById(oRTE.getId() + this.getId() + "-" + sButtonName);
2353
2390
  };
2354
2391
 
2392
+ // When using mergetags plugin, the selection is lost when the user clicks on a toolbar action.
2393
+ // This is a workaround to restore the last selection made by the user.
2394
+ ToolbarWrapper.prototype._preserveMergetagSelection = function () {
2395
+ var oEditor = this.getEditor();
2396
+ if (!oEditor) {
2397
+ return;
2398
+ }
2399
+
2400
+ var oSelectionNode = oEditor.getNativeApi().selection.getNode();
2401
+
2402
+ if (oSelectionNode && oSelectionNode.classList && oSelectionNode.classList.contains('mce-mergetag')) {
2403
+ this._oPreservedMergetagSelection = oSelectionNode;
2404
+ }
2405
+ };
2406
+
2407
+ ToolbarWrapper.prototype._restoreMergetagSelection = function () {
2408
+ if (this._oPreservedMergetagSelection) {
2409
+ var oEditor = this.getEditor();
2410
+ if (oEditor) {
2411
+ var oNativeEditor = oEditor.getNativeApi();
2412
+ oNativeEditor.selection.select(this._oPreservedMergetagSelection);
2413
+ }
2414
+ this._oPreservedMergetagSelection = null;
2415
+ }
2416
+ };
2417
+
2355
2418
  return ToolbarWrapper;
2356
2419
  });
@@ -1,3 +0,0 @@
1
- body {
2
- font-family: verdana, geneva, sans-serif;
3
- }