@sapui5/sap.ui.richtexteditor 1.101.0 → 1.102.2

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 (22) 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 +142 -66
  5. package/src/sap/ui/richtexteditor/ToolbarWrapper.js +505 -293
  6. package/src/sap/ui/richtexteditor/library.js +59 -30
  7. package/src/sap/ui/richtexteditor/messagebundle_ru.properties +1 -1
  8. package/src/sap/ui/richtexteditor/themes/base/RichTextEditor.less +9 -48
  9. package/src/sap/ui/richtexteditor/themes/sap_belize/RichTextEditor.less +29 -0
  10. package/src/sap/ui/richtexteditor/themes/sap_belize/library.source.less +3 -1
  11. package/src/sap/ui/richtexteditor/themes/sap_belize_hcb/RichTextEditor.less +29 -0
  12. package/src/sap/ui/richtexteditor/themes/sap_belize_hcb/library.source.less +2 -0
  13. package/src/sap/ui/richtexteditor/themes/sap_belize_hcw/RichTextEditor.less +30 -0
  14. package/src/sap/ui/richtexteditor/themes/sap_belize_hcw/library.source.less +2 -0
  15. package/src/sap/ui/richtexteditor/themes/sap_fiori_3/RichTextEditor.less +4 -5
  16. package/src/sap/ui/richtexteditor/themes/sap_fiori_3_dark/RichTextEditor.less +4 -5
  17. package/src/sap/ui/richtexteditor/themes/sap_fiori_3_hcb/RichTextEditor.less +4 -5
  18. package/src/sap/ui/richtexteditor/themes/sap_fiori_3_hcw/RichTextEditor.less +4 -5
  19. package/src/sap/ui/richtexteditor/themes/sap_horizon/RichTextEditor.less +15 -30
  20. package/src/sap/ui/richtexteditor/themes/sap_horizon_dark/RichTextEditor.less +16 -31
  21. package/src/sap/ui/richtexteditor/themes/sap_horizon_hcb/RichTextEditor.less +9 -7
  22. package/src/sap/ui/richtexteditor/themes/sap_horizon_hcw/RichTextEditor.less +9 -7
@@ -16,9 +16,22 @@ sap.ui.define([
16
16
  "sap/base/Log",
17
17
  "./ToolbarWrapperRenderer" // Control renderer
18
18
  ],
19
- function(jQuery, Control, library, IconPool, Item, Core, RTESplitButton, URLListValidator, Log) {
19
+ function(
20
+ jQuery,
21
+ Control,
22
+ library,
23
+ IconPool,
24
+ Item,
25
+ Core,
26
+ RTESplitButton,
27
+ URLListValidator,
28
+ Log
29
+ ) {
20
30
  "use strict";
21
31
 
32
+ var ButtonGroups = library.ButtonGroups,
33
+ EditorCommands = library.EditorCommands,
34
+ ButtonsToCommandsMap = library.ButtonsToCommandsMap;
22
35
 
23
36
  /**
24
37
  * Constructor for a new RichTextEditor's Custom Toolbar.
@@ -85,8 +98,8 @@ sap.ui.define([
85
98
  this._helper = library.RichTextEditorHelper;
86
99
  this._oResourceBundle = Core.getLibraryResourceBundle("sap.ui.richtexteditor");
87
100
  this._oAccessibilityTexts = {};
88
- this._sTextColor = library.EditorCommands.TextColor.defaultValue;
89
- this._sBackgroundColor = library.EditorCommands.BackgroundColor.defaultValue;
101
+ this._sTextColor = EditorCommands.TextColor.defaultValue;
102
+ this._sBackgroundColor = EditorCommands.BackgroundColor.defaultValue;
90
103
  };
91
104
 
92
105
  ToolbarWrapper.prototype.onBeforeRendering = function () {
@@ -116,12 +129,12 @@ sap.ui.define([
116
129
 
117
130
  ToolbarWrapper.prototype.onAfterRendering = function () {
118
131
  var oEditor = this.getEditor();
119
- // create an array of deep copies with the initia setupof the button groups
132
+ // create an array of deep copies with the initial setup of the button groups
120
133
  this._initialButtonGroupsState = oEditor && oEditor.getButtonGroups().map(function(oObject){
121
134
  return jQuery.extend(true, {}, oObject);
122
135
  });
123
136
 
124
- this._syncPopoverOpeningArrows();
137
+ this._modifyPopoverOpeningArrowHandlers(true);
125
138
  this._syncColors("TextColor", this._sTextColor);
126
139
  this._syncColors("BackgroundColor", this._sBackgroundColor);
127
140
  };
@@ -134,25 +147,78 @@ sap.ui.define([
134
147
 
135
148
  this._customButtons = null;
136
149
  this._oAccessibilityTexts = null;
150
+ this._helper = null;
151
+ this._oResourceBundle = null;
152
+ this._sTextColor = null;
153
+ this._sBackgroundColor = null;
137
154
  };
138
155
 
139
156
  /**
140
- * Helper function for synchronising the arrow button of the color selection SplitButtons
157
+ * Helper function for attaching / detaching the synchronization handlers of the color selection SplitButton arrow buttons
141
158
  * The arrow button should be displayed as active, while the corresponding color popover is open
142
159
  *
160
+ * @param {boolean} bAttach Will attach the handlers if true
143
161
  * @private
144
162
  */
145
- ToolbarWrapper.prototype._syncPopoverOpeningArrows = function () {
146
- var aFontButtons = this._findGroupedControls("font"),
147
- oTextColorArrowButton = aFontButtons[2] && aFontButtons[2]._getArrowButton(),
148
- oBackgroundColorArrowButton = aFontButtons[3] && aFontButtons[3]._getArrowButton();
163
+ ToolbarWrapper.prototype._modifyPopoverOpeningArrowHandlers = function (bAttach) {
164
+ var oTextColorButton = this._findButtonById("TextColor"),
165
+ oTextColorArrowButton = oTextColorButton && oTextColorButton._getArrowButton(),
166
+ oBackgroundColorButton = this._findButtonById("BackgroundColor"),
167
+ oBackgroundColorArrowButton = oBackgroundColorButton && oBackgroundColorButton._getArrowButton();
168
+
169
+ // Attaching handlers
170
+ // As this method is called each time after rendering, we need to ensure that we attach
171
+ // the necessary handlers only once. That is why two properties were introduced:
172
+ // _bTextColorSyncHandlersAttached
173
+ // _bBackgroundColorSyncHandlersAttached
174
+ if (bAttach && oTextColorArrowButton && !this._bTextColorSyncHandlersAttached) {
175
+ this.getAggregation("_customTextColorDialog")._ensurePopover()
176
+ .attachAfterOpen(oTextColorArrowButton, this._customColorDialogAfterOpen, this)
177
+ .attachAfterClose(oTextColorArrowButton, this._customColorDialogAfterClose, this);
178
+ this._bTextColorSyncHandlersAttached = true;
179
+ }
180
+ if (bAttach && oBackgroundColorArrowButton && !this._bBackgroundColorSyncHandlersAttached) {
181
+ this.getAggregation("_customBackgroundColorDialog")._ensurePopover()
182
+ .attachAfterOpen(oBackgroundColorArrowButton, this._customColorDialogAfterOpen, this)
183
+ .attachAfterClose(oBackgroundColorArrowButton, this._customColorDialogAfterClose, this);
184
+ this._bBackgroundColorSyncHandlersAttached = true;
185
+ }
186
+
187
+ // Detaching handlers
188
+ if (!bAttach && oTextColorArrowButton && this._bTextColorSyncHandlersAttached) {
189
+ this.getAggregation("_customTextColorDialog")._ensurePopover()
190
+ .detachAfterOpen(this._customColorDialogAfterOpen, this)
191
+ .detachAfterClose(this._customColorDialogAfterClose, this);
192
+ this._bTextColorSyncHandlersAttached = null;
193
+ }
194
+ if (!bAttach && oBackgroundColorArrowButton && this._bBackgroundColorSyncHandlersAttached) {
195
+ this.getAggregation("_customBackgroundColorDialog")._ensurePopover()
196
+ .detachAfterOpen(this._customColorDialogAfterOpen, this)
197
+ .detachAfterClose(this._customColorDialogAfterClose, this);
198
+ this._bBackgroundColorSyncHandlersAttached = null;
199
+ }
200
+ };
201
+
202
+ /**
203
+ * Synchronization handler called after opening of the text / background color picker dialog
204
+ *
205
+ * @param {object} oEvent The event object
206
+ * @param {object} oButton The color button
207
+ * @private
208
+ */
209
+ ToolbarWrapper.prototype._customColorDialogAfterOpen = function (oEvent, oButton) {
210
+ oButton && oButton._activeButton();
211
+ };
149
212
 
150
- this.getAggregation("_customTextColorDialog")._ensurePopover()
151
- .attachAfterOpen(function () { oTextColorArrowButton._activeButton();})
152
- .attachAfterClose(function () { oTextColorArrowButton._inactiveButton();});
153
- this.getAggregation("_customBackgroundColorDialog")._ensurePopover()
154
- .attachAfterOpen(function () { oBackgroundColorArrowButton._activeButton();})
155
- .attachAfterClose(function () { oBackgroundColorArrowButton._inactiveButton();});
213
+ /**
214
+ * Synchronization handler called after closing of the text / background color picker dialog
215
+ *
216
+ * @param {object} oEvent The event object
217
+ * @param {object} oButton The color button
218
+ * @private
219
+ */
220
+ ToolbarWrapper.prototype._customColorDialogAfterClose = function (oEvent, oButton) {
221
+ oButton && oButton._inactiveButton();
156
222
  };
157
223
 
158
224
  /**
@@ -197,7 +263,7 @@ sap.ui.define([
197
263
  * @public
198
264
  */
199
265
  ToolbarWrapper.prototype.modifyRTEToolbarConfig = function (oConfig) {
200
- var oToolbar = this;
266
+ var that = this;
201
267
 
202
268
  // Remove the native toolbar. From now on the sap.ui.richtexteditor.ToolbarWrapper will be used
203
269
  oConfig.toolbar = false;
@@ -206,7 +272,7 @@ sap.ui.define([
206
272
 
207
273
  // Sync sap.ui.richtexteditor.ToolbarWrapper buttons with the editor
208
274
  editor.on('NodeChange', function () {
209
- oToolbar._syncToolbarStates(this);
275
+ that._syncToolbarStates(this);
210
276
  });
211
277
  };
212
278
 
@@ -236,20 +302,20 @@ sap.ui.define([
236
302
  * @private
237
303
  */
238
304
  ToolbarWrapper.prototype._syncColors = function (sCommand, sColor) {
239
- var aControls = this._findGroupedControls("font"),
240
- oTextButtonIcon;
305
+ var oColorButton = this._findButtonById(sCommand),
306
+ oColorButtonIcon;
241
307
 
242
308
  if (!sColor) {
243
309
  return;
244
310
  }
245
- switch (sCommand) {
246
- case "TextColor":
247
- aControls[2] && aControls[2].setIconColor(sColor);
248
- break;
249
- case "BackgroundColor":
250
- oTextButtonIcon = aControls[3] && aControls[3]._getTextButton().getDomRef("img");
251
- oTextButtonIcon && Core.byId(oTextButtonIcon.id).setColor(sColor);
252
- break;
311
+
312
+ if (sCommand === "TextColor") {
313
+ oColorButton && oColorButton.setIconColor(sColor);
314
+ }
315
+
316
+ if (sCommand === "BackgroundColor") {
317
+ oColorButtonIcon = oColorButton && oColorButton._getTextButton().getDomRef("img");
318
+ oColorButtonIcon && Core.byId(oColorButtonIcon.id).setColor(sColor);
253
319
  }
254
320
  };
255
321
  /**
@@ -259,7 +325,6 @@ sap.ui.define([
259
325
  */
260
326
  ToolbarWrapper.prototype._syncToolbarStates = function (oNativeEditor) {
261
327
  var oEditorCommand, oControl, sEditorCommand,
262
- oEditorCommands = library.EditorCommands,
263
328
  oFormatter = oNativeEditor.formatter,
264
329
  oResourceBundle = this._oResourceBundle,
265
330
  _syncTextAlign = function (oTextAlignCommand, oEditorFormatter, oControl) {
@@ -343,12 +408,12 @@ sap.ui.define([
343
408
  }
344
409
  };
345
410
 
346
- for (sEditorCommand in oEditorCommands) {
347
- if (!oEditorCommands.hasOwnProperty(sEditorCommand)) {
411
+ for (sEditorCommand in EditorCommands) {
412
+ if (!EditorCommands.hasOwnProperty(sEditorCommand)) {
348
413
  continue;
349
414
  }
350
415
 
351
- oEditorCommand = oEditorCommands[sEditorCommand];
416
+ oEditorCommand = EditorCommands[sEditorCommand];
352
417
  // TODO: Probably there's a better way to handle this
353
418
  oControl = Core.byId(this._getId(sEditorCommand));
354
419
 
@@ -402,11 +467,9 @@ sap.ui.define([
402
467
  * @private
403
468
  */
404
469
  ToolbarWrapper.prototype._createButtonConfig = function (sCommand) {
405
- var oEditorCommands = library.EditorCommands,
406
- oCommand = oEditorCommands[sCommand],
470
+ var oCommand = EditorCommands[sCommand],
407
471
  oRTE = this.getEditor();
408
472
 
409
-
410
473
  return {
411
474
  id: this._getId(sCommand),
412
475
  icon: IconPool.getIconURI(oCommand.icon),
@@ -431,17 +494,16 @@ sap.ui.define([
431
494
  */
432
495
  ToolbarWrapper.prototype._createMenuButtonItems = function (sCommand) {
433
496
  var oEditorHelper = this._helper,
434
- oEditorCommands = library.EditorCommands,
435
497
  aItems = [],
436
498
  sItemText,
437
499
  oCommand;
438
500
 
439
- for (var sEditorCommand in oEditorCommands[sCommand]) {
501
+ for (var sEditorCommand in EditorCommands[sCommand]) {
440
502
  if (sEditorCommand === 'bundleKey') {
441
503
  continue;
442
504
  }
443
505
 
444
- oCommand = oEditorCommands[sCommand][sEditorCommand];
506
+ oCommand = EditorCommands[sCommand][sEditorCommand];
445
507
  sItemText = this._oResourceBundle.getText(oCommand.bundleKey) || oCommand.text;
446
508
  aItems.push(oEditorHelper.createMenuItem(this._getId(sCommand + sEditorCommand), sItemText, IconPool.getIconURI(oCommand.icon)));
447
509
  }
@@ -457,7 +519,7 @@ sap.ui.define([
457
519
  * @private
458
520
  */
459
521
  ToolbarWrapper.prototype._findTextAlignCommandByIcon = function (sIconUri) {
460
- var oEditorCommands = library.EditorCommands['TextAlign'],
522
+ var oEditorCommands = EditorCommands['TextAlign'],
461
523
  sCommandIconUri, sCommand;
462
524
 
463
525
  Object.keys(oEditorCommands)
@@ -479,8 +541,7 @@ sap.ui.define([
479
541
  * @private
480
542
  */
481
543
  ToolbarWrapper.prototype._createFontStyleSelectItems = function () {
482
- var oEditorCommands = library.EditorCommands,
483
- oFontFamilies = oEditorCommands["FontFamily"],
544
+ var oFontFamilies = EditorCommands["FontFamily"],
484
545
  aItems = [],
485
546
  oItem;
486
547
 
@@ -504,8 +565,7 @@ sap.ui.define([
504
565
  * @private
505
566
  */
506
567
  ToolbarWrapper.prototype._getFontStyleCommand = function (sItemText) {
507
- var oEditorCommands = library.EditorCommands,
508
- oFontFamilies = oEditorCommands["FontFamily"];
568
+ var oFontFamilies = EditorCommands["FontFamily"];
509
569
 
510
570
  for (var sFontStyle in oFontFamilies) {
511
571
  if (oFontFamilies.hasOwnProperty(sFontStyle) && oFontFamilies[sFontStyle].text === sItemText) {
@@ -522,8 +582,7 @@ sap.ui.define([
522
582
  * @private
523
583
  */
524
584
  ToolbarWrapper.prototype._getFormatBlockCommand = function (sItemText) {
525
- var oEditorCommands = library.EditorCommands,
526
- oFormat = oEditorCommands["FormatBlock"];
585
+ var oFormat = EditorCommands["FormatBlock"];
527
586
 
528
587
  for (var sFormat in oFormat) {
529
588
  if (oFormat.hasOwnProperty(sFormat) && this._oResourceBundle.getText(oFormat[sFormat].bundleKey) === sItemText) {
@@ -541,10 +600,9 @@ sap.ui.define([
541
600
  ToolbarWrapper.prototype._createFontSizeSelectItems = function () {
542
601
  var aItems = [],
543
602
  number = 1, //TinyMCE command values for font sizes have a value from 1 to 7
544
- oItem,
545
- oEditorCommands = library.EditorCommands;
603
+ oItem;
546
604
 
547
- oEditorCommands["FontSize"].forEach(function (item) {
605
+ EditorCommands["FontSize"].forEach(function (item) {
548
606
  oItem = {
549
607
  id: this._getId("FontSize" + number),
550
608
  text: item + " pt"
@@ -562,8 +620,7 @@ sap.ui.define([
562
620
  * @private
563
621
  */
564
622
  ToolbarWrapper.prototype._createFormatBlockItems = function () {
565
- var oEditorCommands = library.EditorCommands,
566
- oFormatBlock = oEditorCommands["FormatBlock"],
623
+ var oFormatBlock = EditorCommands["FormatBlock"],
567
624
  aItems = [],
568
625
  oItem;
569
626
 
@@ -588,7 +645,7 @@ sap.ui.define([
588
645
  */
589
646
  ToolbarWrapper.prototype._getColor = function (sCommand) {
590
647
  var oRTE = this.getEditor(),
591
- oCommandStyle = library.EditorCommands[sCommand].style,
648
+ oCommandStyle = EditorCommands[sCommand].style,
592
649
  oNode = oRTE.getNativeApi().selection.getNode(),
593
650
  aNodes = oRTE.getNativeApi().dom.getParents(oNode),
594
651
  i, aCurrentNode, sColor;
@@ -603,7 +660,7 @@ sap.ui.define([
603
660
  }
604
661
 
605
662
  // If there is no color style found, return the default color
606
- return library.EditorCommands[sCommand].defaultValue;
663
+ return EditorCommands[sCommand].defaultValue;
607
664
  };
608
665
 
609
666
 
@@ -612,32 +669,30 @@ sap.ui.define([
612
669
  *
613
670
  * @private
614
671
  * @param {string} [sCommand] Editor Command
615
- * @returns {object} The configuration object for the toolbar SplitButton which opens a command specific popover
672
+ * @returns {object|null} The configuration object for the toolbar SplitButton which opens a command specific popover or null
616
673
  */
617
674
  ToolbarWrapper.prototype._createSplitButtonForDialog = function (sCommand) {
618
- var oCommand = library.EditorCommands[sCommand],
619
- oToolbar = this,
675
+ var oCommand = EditorCommands[sCommand],
676
+ that = this,
620
677
  oDialog, oResultConfig;
621
678
 
622
679
  if (!oCommand) {
623
- return;
680
+ return null;
624
681
  }
625
682
 
626
683
  oResultConfig = {
627
684
  id: this._getId(sCommand),
628
685
  tooltip: this._oResourceBundle.getText(oCommand.bundleKey),
629
686
  press: function () {
630
- switch (sCommand) {
631
- case "TextColor":
632
- oToolbar._applyColor(sCommand, oCommand.command, oToolbar._sTextColor);
633
- break;
634
- case "BackgroundColor":
635
- oToolbar._applyColor(sCommand, oCommand.command, oToolbar._sBackgroundColor);
636
- break;
687
+ if (sCommand === "TextColor") {
688
+ that._applyColor(sCommand, oCommand.command, that._sTextColor);
689
+ }
690
+ if (sCommand === "BackgroundColor") {
691
+ that._applyColor(sCommand, oCommand.command, that._sBackgroundColor);
637
692
  }
638
693
  },
639
694
  arrowPress: function () {
640
- oDialog = oToolbar.getAggregation("_custom" + sCommand + "Dialog");
695
+ oDialog = that.getAggregation("_custom" + sCommand + "Dialog");
641
696
 
642
697
  this._getArrowButton()._activeButton();
643
698
  if (!oDialog) {
@@ -657,19 +712,19 @@ sap.ui.define([
657
712
 
658
713
 
659
714
  /**
660
- * Helper function for creating Button Control configuration for opening dialogs
715
+ * Helper function for creating Button Control configuration for opening dialogs.
661
716
  *
662
717
  * @private
663
718
  * @param {string} [sCommand] Editor Command
664
- * @returns {object} The configuration object for the toolbar button which opens a command specific dialog
719
+ * @returns {object|null} The configuration object for the toolbar button which opens a command specific dialog or null.
665
720
  */
666
721
  ToolbarWrapper.prototype._createButtonForDialog = function (sCommand) {
667
- var oCommand = library.EditorCommands[sCommand],
668
- oToolbar = this,
722
+ var oCommand = EditorCommands[sCommand],
723
+ that = this,
669
724
  oDialog;
670
725
 
671
726
  if (!oCommand) {
672
- return;
727
+ return null;
673
728
  }
674
729
 
675
730
  return {
@@ -678,7 +733,7 @@ sap.ui.define([
678
733
  tooltip: this._oResourceBundle.getText(oCommand.bundleKey),
679
734
  text: this._oResourceBundle.getText(oCommand.bundleKey),
680
735
  press: function () {
681
- oDialog = oToolbar.getAggregation("_custom" + sCommand + "Dialog");
736
+ oDialog = that.getAggregation("_custom" + sCommand + "Dialog");
682
737
 
683
738
  if (!oDialog) {
684
739
  return;
@@ -687,13 +742,16 @@ sap.ui.define([
687
742
  switch (sCommand) {
688
743
  case "InsertImage":
689
744
  this.setPressed(true);
690
- oToolbar._syncImageDialogData(oDialog);
745
+ that._syncImageDialogData(oDialog);
691
746
  break;
692
747
  case "InsertLink":
693
- oToolbar._syncLinkDialogData(oDialog);
748
+ that._syncLinkDialogData(oDialog);
694
749
  break;
695
750
  case "InsertTable":
696
- oToolbar._resetDialogContent(oDialog);
751
+ that._resetDialogContent(oDialog);
752
+ break;
753
+ default:
754
+ break;
697
755
  }
698
756
  oDialog.open();
699
757
  }
@@ -840,25 +898,22 @@ sap.ui.define([
840
898
  * @private
841
899
  */
842
900
  ToolbarWrapper.prototype._createColorPalettePopoverConfig = function(sType) {
843
- var oCommand = library.EditorCommands[sType],
901
+ var oCommand = EditorCommands[sType],
844
902
  sColor = oCommand.defaultValue,
845
- oToolbar = this;
903
+ that = this;
846
904
 
847
905
  return {
848
906
  defaultColor: sColor,
849
907
  colorSelect: function (oEvent) {
850
908
  var sColor = oEvent.getParameters().value;
851
- oToolbar._applyColor(sType, oCommand.command, sColor, oEvent.getParameter("defaultAction"));
852
-
853
- switch (sType) {
854
- case "TextColor":
855
- oToolbar._sTextColor = sColor;
856
- oToolbar._syncColors("TextColor", sColor);
857
- break;
858
- case "BackgroundColor":
859
- oToolbar._sBackgroundColor = sColor;
860
- oToolbar._syncColors("BackgroundColor", sColor);
861
- break;
909
+ that._applyColor(sType, oCommand.command, sColor, oEvent.getParameter("defaultAction"));
910
+ if (sType === "TextColor") {
911
+ that._sTextColor = sColor;
912
+ that._syncColors("TextColor", sColor);
913
+ }
914
+ if (sType === "BackgroundColor") {
915
+ that._sBackgroundColor = sColor;
916
+ that._syncColors("BackgroundColor", sColor);
862
917
  }
863
918
  }
864
919
  };
@@ -894,7 +949,7 @@ sap.ui.define([
894
949
  */
895
950
  ToolbarWrapper.prototype._createInsertImageConfig = function() {
896
951
  var iRationCoeff,
897
- oTitleBundleText = this._oResourceBundle.getText(sap.ui.richtexteditor.EditorCommands["InsertImage"].bundleKey),
952
+ oTitleBundleText = this._oResourceBundle.getText(EditorCommands["InsertImage"].bundleKey),
898
953
  oURLInput = this._helper.createInput(),
899
954
  oURLLabel = this._helper.createLabel({
900
955
  text: this._oResourceBundle.getText("INSERT_IMAGE_URL"),
@@ -978,7 +1033,7 @@ sap.ui.define([
978
1033
  oDimensionHeightInput.setValue(fWidthInputValue / iRationCoeff);
979
1034
  }
980
1035
  },
981
- oToolbar = this,
1036
+ that = this,
982
1037
  aButtons = [];
983
1038
 
984
1039
  oDimensionsLabel.setLabelFor(oDimensionWidthInput);
@@ -988,13 +1043,13 @@ sap.ui.define([
988
1043
  text: this._oResourceBundle.getText("DIALOG_OK_BUTTON"),
989
1044
  press: function () {
990
1045
  oRTE.getNativeApi()
991
- .insertContent(oToolbar._generateImageHTML(oURLInput.getValue(),
1046
+ .insertContent(that._generateImageHTML(oURLInput.getValue(),
992
1047
  oTextInput.getValue(),
993
1048
  oDimensionHeightInput.getValue(),
994
1049
  oDimensionWidthInput.getValue(),
995
1050
  oRatioCheckBox.getSelected()));
996
- oToolbar.getAggregation("_customInsertImageDialog").close();
997
- oToolbar._syncToolbarStates(oRTE.getNativeApi());
1051
+ that.getAggregation("_customInsertImageDialog").close();
1052
+ that._syncToolbarStates(oRTE.getNativeApi());
998
1053
  }
999
1054
  }));
1000
1055
 
@@ -1002,8 +1057,8 @@ sap.ui.define([
1002
1057
  id: this._getId("CancelInsertImageButton"),
1003
1058
  text: this._oResourceBundle.getText("DIALOG_CANCEL_BUTTON"),
1004
1059
  press: function () {
1005
- oToolbar.getAggregation("_customInsertImageDialog").close();
1006
- oToolbar._syncToolbarStates(oRTE.getNativeApi());
1060
+ that.getAggregation("_customInsertImageDialog").close();
1061
+ that._syncToolbarStates(oRTE.getNativeApi());
1007
1062
  }
1008
1063
  }));
1009
1064
 
@@ -1127,7 +1182,7 @@ sap.ui.define([
1127
1182
  * @private
1128
1183
  */
1129
1184
  ToolbarWrapper.prototype._createInsertLinkConfig = function() {
1130
- var oTitleBundleText = this._oResourceBundle.getText(sap.ui.richtexteditor.EditorCommands["InsertLink"].bundleKey),
1185
+ var oTitleBundleText = this._oResourceBundle.getText(EditorCommands["InsertLink"].bundleKey),
1131
1186
  oURLInput = this._helper.createInput(),
1132
1187
  oURLLabel = this._helper.createLabel({
1133
1188
  text: this._oResourceBundle.getText("INSERT_LINK_URL"),
@@ -1167,7 +1222,7 @@ sap.ui.define([
1167
1222
  oTargetSelect]
1168
1223
  }),
1169
1224
  oRTE = this.getEditor(),
1170
- oToolbar = this,
1225
+ that = this,
1171
1226
  aButtons = [];
1172
1227
 
1173
1228
  aButtons.push(this._helper.createButton({
@@ -1175,12 +1230,12 @@ sap.ui.define([
1175
1230
  text: this._oResourceBundle.getText("DIALOG_OK_BUTTON"),
1176
1231
  press: function () {
1177
1232
  var bTarget = (oTargetSelect.getSelectedItem() === oTargetSelect.getItems()[1]);
1178
- oToolbar._generateLinkHTML(oURLInput.getValue(),
1233
+ that._generateLinkHTML(oURLInput.getValue(),
1179
1234
  oTitleInput.getValue(),
1180
1235
  bTarget,
1181
1236
  oTextInput.getValue());
1182
- oToolbar.getAggregation("_customInsertLinkDialog").close();
1183
- oToolbar._syncToolbarStates(oRTE.getNativeApi());
1237
+ that.getAggregation("_customInsertLinkDialog").close();
1238
+ that._syncToolbarStates(oRTE.getNativeApi());
1184
1239
  }
1185
1240
  }));
1186
1241
 
@@ -1188,8 +1243,8 @@ sap.ui.define([
1188
1243
  id: this._getId("CancelInsertLinkButton"),
1189
1244
  text: this._oResourceBundle.getText("DIALOG_CANCEL_BUTTON"),
1190
1245
  press: function () {
1191
- oToolbar.getAggregation("_customInsertLinkDialog").close();
1192
- oToolbar._syncToolbarStates(oRTE.getNativeApi());
1246
+ that.getAggregation("_customInsertLinkDialog").close();
1247
+ that._syncToolbarStates(oRTE.getNativeApi());
1193
1248
  }
1194
1249
  }));
1195
1250
 
@@ -1216,7 +1271,7 @@ sap.ui.define([
1216
1271
  * @private
1217
1272
  */
1218
1273
  ToolbarWrapper.prototype._createInsertTableConfig = function() {
1219
- var oTitleBundleText = this._oResourceBundle.getText(sap.ui.richtexteditor.EditorCommands["InsertTable"].bundleKey),
1274
+ var oTitleBundleText = this._oResourceBundle.getText(EditorCommands["InsertTable"].bundleKey),
1220
1275
  oRowsInput = this._helper.createStepInput({
1221
1276
  value: 2,
1222
1277
  min: 0,
@@ -1264,7 +1319,7 @@ sap.ui.define([
1264
1319
  oDimensionWidthInput]
1265
1320
  }),
1266
1321
  oRTE = this.getEditor(),
1267
- oToolbar = this,
1322
+ that = this,
1268
1323
  aButtons = [];
1269
1324
 
1270
1325
  aButtons.push(this._helper.createButton({
@@ -1278,7 +1333,7 @@ sap.ui.define([
1278
1333
  dom.setStyle(tableElm, 'width', oDimensionWidthInput.getValue() + "px");
1279
1334
  dom.setStyle(tableElm, 'height', oDimensionHeightInput.getValue() + "px");
1280
1335
 
1281
- oToolbar.getAggregation("_customInsertTableDialog").close();
1336
+ that.getAggregation("_customInsertTableDialog").close();
1282
1337
  }
1283
1338
  }));
1284
1339
 
@@ -1286,7 +1341,7 @@ sap.ui.define([
1286
1341
  id: this._getId("CancelInsertTableButton"),
1287
1342
  text: this._oResourceBundle.getText("DIALOG_CANCEL_BUTTON"),
1288
1343
  press: function () {
1289
- oToolbar.getAggregation("_customInsertTableDialog").close();
1344
+ that.getAggregation("_customInsertTableDialog").close();
1290
1345
  }
1291
1346
  }));
1292
1347
 
@@ -1315,8 +1370,7 @@ sap.ui.define([
1315
1370
  ToolbarWrapper.prototype._createCustomToolbar = function () {
1316
1371
  var oEditorHelper = this._helper,
1317
1372
  aContent = [],
1318
- oButtonGroups = library.ButtonGroups,
1319
- aGroupNames = Object.keys(oButtonGroups),
1373
+ aGroupNames = Object.keys(ButtonGroups),
1320
1374
  aGroups = [],
1321
1375
  aGroupObjects = this.getEditor() ? this.getEditor().getButtonGroups() : [];
1322
1376
 
@@ -1333,7 +1387,7 @@ sap.ui.define([
1333
1387
  aGroups = this._sortToolbarContent(aGroups);
1334
1388
 
1335
1389
  aGroups.forEach(function(oGroup){
1336
- aContent = aContent.concat(this.addButtonGroup(oGroup.name));
1390
+ aContent = aContent.concat(this._createButtonGroup(oGroup));
1337
1391
  }.bind(this));
1338
1392
 
1339
1393
  return oEditorHelper.createOverflowToolbar(this._getId(), aContent);
@@ -1373,195 +1427,326 @@ sap.ui.define([
1373
1427
  };
1374
1428
 
1375
1429
  /**
1376
- * Adds a Button Group to the Custom Toolbar
1430
+ * Maps the native TinyMCE style button names to ones supported by the toolbar wrapper.
1377
1431
  *
1378
- * @param {string} [sGroupName] Group name
1432
+ * @param {string} sGroupName Name of the group
1433
+ * @param {string[]} aNativeButtons Array of native TinyMCE style button names.
1434
+ * @returns {string[]} Array of supported button names (commands).
1435
+ * @private
1436
+ */
1437
+ ToolbarWrapper.prototype._mapNativeButtonsToCommands = function (sGroupName, aNativeButtons) {
1438
+ var oRTE = this.getEditor();
1439
+ var aCommandsToCreate = [];
1440
+ var aSupportedButtonGroup = ButtonGroups[sGroupName];
1441
+
1442
+ if (!Array.isArray(aSupportedButtonGroup) || aNativeButtons && !aNativeButtons.length) {
1443
+ return [];
1444
+ }
1445
+
1446
+ // There are some special groups which do not map 1 to 1 with the native button types
1447
+ // Those groups require some special attention as they might render all buttons as single menu one
1448
+ // or create select type controls.
1449
+ switch (sGroupName) {
1450
+ case "text-align":
1451
+ aCommandsToCreate.push("TextAlign");
1452
+ break;
1453
+ case "formatselect":
1454
+ case "styleselect":
1455
+ aCommandsToCreate.push("FormatBlock");
1456
+ break;
1457
+ case "insert":
1458
+ aCommandsToCreate.push("InsertImage");
1459
+ break;
1460
+ default:
1461
+ // Check the provided buttons in the group against the supported ones for this particular group from the library.
1462
+ aNativeButtons.forEach(function (sNativeButtonName) {
1463
+ var sCustomCommandName = ButtonsToCommandsMap[sNativeButtonName];
1464
+ if (aSupportedButtonGroup.indexOf(sCustomCommandName) > -1) {
1465
+ // The button is supported in the custom toolbar and can be added
1466
+ aCommandsToCreate.push(sCustomCommandName);
1467
+ } else {
1468
+ // For unsupported buttons - log warning and do not do anything
1469
+ Log.warning("Unsupported button for the custom toolbar found: " + sNativeButtonName + ", for group: " + sGroupName + ".", oRTE);
1470
+ }
1471
+ });
1472
+ break;
1473
+ }
1474
+
1475
+ return aCommandsToCreate;
1476
+ };
1477
+
1478
+ ToolbarWrapper.prototype._createFontToolbarContent = function (aButtonsToCreate, bVisible) {
1479
+ // All buttons in this group should be handled case by case as they are not of the same type.
1480
+ var aToolbarContent = [];
1481
+ var oAccessibilityKeys = library.Accessibility;
1482
+ var oRTE = this.getEditor();
1483
+ var that = this;
1484
+
1485
+ // --- Font Family ---
1486
+ if (aButtonsToCreate.indexOf("FontFamily") !== -1) {
1487
+ var oInvisibleTextFontFamily = this._helper.createInvisibleText({
1488
+ text: this._oResourceBundle.getText(oAccessibilityKeys["FontFamily"])
1489
+ }).toStatic();
1490
+ this._registerAssociatedInvisibleTexts("font", oInvisibleTextFontFamily.getId());
1491
+
1492
+ aToolbarContent.push(
1493
+ this._helper.createSelect({
1494
+ id: this._getId("FontFamily"),
1495
+ ariaLabelledBy: oInvisibleTextFontFamily,
1496
+ selectedItemId: this._getId("FontFamilyVerdana"),
1497
+ items: this._createFontStyleSelectItems(),
1498
+ change: function (oEvent) {
1499
+ var oItem;
1500
+
1501
+ if (oRTE) {
1502
+ oItem = oEvent.getSource().getSelectedItem();
1503
+ oRTE.getNativeApi().execCommand('FontName', false, that._getFontStyleCommand(oItem.getText()));
1504
+ } else {
1505
+ Log.warning("Cannot execute native command: " + 'FontName');
1506
+ }
1507
+ }
1508
+ }).setVisible(bVisible)
1509
+ );
1510
+ }
1511
+
1512
+ // --- Font Size ---
1513
+ if (aButtonsToCreate.indexOf("FontSize") !== -1) {
1514
+ var oInvisibleTextFontSize = this._helper.createInvisibleText({
1515
+ text: this._oResourceBundle.getText(oAccessibilityKeys["FontSize"])
1516
+ }).toStatic();
1517
+ this._registerAssociatedInvisibleTexts("font", oInvisibleTextFontSize.getId());
1518
+
1519
+ aToolbarContent.push(
1520
+ this._helper.createSelect({
1521
+ id: this._getId("FontSize"),
1522
+ ariaLabelledBy: oInvisibleTextFontSize,
1523
+ selectedItemId: this._getId("FontSize2"),
1524
+ items: this._createFontSizeSelectItems(),
1525
+ change: function (oEvent) {
1526
+ var oItem;
1527
+
1528
+ if (oRTE) {
1529
+ oItem = oEvent.getSource().getSelectedItem();
1530
+ oRTE.getNativeApi().execCommand('FontSize', false, oItem.getText().replace(/\s/g, ""));
1531
+ } else {
1532
+ Log.warning("Cannot execute native command: " + 'FontSize');
1533
+ }
1534
+ }
1535
+ }).setVisible(bVisible)
1536
+ );
1537
+ }
1538
+
1539
+ // --- Font Color ---
1540
+ if (aButtonsToCreate.indexOf("TextColor") !== -1) {
1541
+ var oInvisibleTextFontColor = this._helper.createInvisibleText({
1542
+ text: this._oResourceBundle.getText(oAccessibilityKeys["FontColor"])
1543
+ }).toStatic();
1544
+
1545
+ var oRTESplitButton = new RTESplitButton(this._createSplitButtonForDialog("TextColor")).setVisible(bVisible);
1546
+ oRTESplitButton._getTextButton().addAriaLabelledBy(oInvisibleTextFontColor);
1547
+
1548
+ aToolbarContent.push(oRTESplitButton);
1549
+ }
1550
+
1551
+ // --- Background Color ---
1552
+ if (aButtonsToCreate.indexOf("BackgroundColor") !== -1) {
1553
+ var oInvisibleTextBackgroundColor = this._helper.createInvisibleText({
1554
+ text: this._oResourceBundle.getText(oAccessibilityKeys["BackgroundColor"])
1555
+ }).toStatic();
1556
+
1557
+ var oBackgroundColorButton = this._helper.createSplitButton(this._createSplitButtonForDialog("BackgroundColor")).setVisible(bVisible);
1558
+ oBackgroundColorButton._getTextButton().addAriaLabelledBy(oInvisibleTextBackgroundColor);
1559
+ aToolbarContent.push(oBackgroundColorButton);
1560
+ }
1561
+
1562
+ return aToolbarContent;
1563
+ };
1564
+
1565
+ ToolbarWrapper.prototype._createTextAlignToolbarContent = function (bVisible) {
1566
+ var oRTE = this.getEditor();
1567
+ var bGroupVisible = oRTE ? oRTE.getShowGroupFontStyle() || bVisible : false;
1568
+ var that = this;
1569
+ var bTextAlignLRight = oRTE._getTextDirection() === "rtl";
1570
+ var iDefaultItemIndex = bTextAlignLRight ? 2 : 0;
1571
+ var aMenuItems = this._createMenuButtonItems("TextAlign");
1572
+
1573
+ return [
1574
+ this._helper.createMenuButton(
1575
+ this._getId("TextAlign"),
1576
+ aMenuItems,
1577
+ function (oEvent) {
1578
+ var oSelectedItem, oEditor, oSelectedItemIcon;
1579
+
1580
+ if (oRTE) {
1581
+ oSelectedItem = oEvent.getParameter("item");
1582
+ oEditor = oRTE.getNativeApi();
1583
+ oSelectedItemIcon = oSelectedItem.getIcon();
1584
+ if (oSelectedItemIcon === this.getParent().getIcon()) {
1585
+ var sTextAlign = bTextAlignLRight ? "JustifyRight" : "JustifyLeft";
1586
+ // Text Align commands in TinyMCE have a toggle behavior when you set a
1587
+ // certain command twice the default command (text-align-left) will be applied
1588
+ oEditor.execCommand(sTextAlign);
1589
+ } else {
1590
+ oEditor.execCommand('Justify' + that._findTextAlignCommandByIcon(oSelectedItemIcon));
1591
+ }
1592
+ } else {
1593
+ Log.warning("Cannot execute native command: " + 'Justify');
1594
+ }
1595
+ },
1596
+ aMenuItems[iDefaultItemIndex].getIcon(),
1597
+ this._oResourceBundle.getText(EditorCommands["TextAlign"].bundleKey)
1598
+ ).setVisible(bGroupVisible)
1599
+ ];
1600
+ };
1601
+
1602
+ ToolbarWrapper.prototype._createFormatSelectToolbarContent = function (bVisible) {
1603
+ var oRTE = this.getEditor();
1604
+ var oAccessibilityKeys = library.Accessibility;
1605
+ var oInvisibleTextFormatBlock = this._helper.createInvisibleText({
1606
+ text: this._oResourceBundle.getText(oAccessibilityKeys["FormatBlock"])
1607
+ }).toStatic();
1608
+
1609
+ this._registerAssociatedInvisibleTexts("formatselect", oInvisibleTextFormatBlock.getId());
1610
+
1611
+ return [
1612
+ this._helper.createSelect({
1613
+ id: this._getId("FormatBlock"),
1614
+ ariaLabelledBy: oInvisibleTextFormatBlock,
1615
+ items: this._createFormatBlockItems(),
1616
+ change: function (oEvent) {
1617
+ var oSelectedItem;
1618
+ if (oRTE) {
1619
+ oSelectedItem = oEvent.getSource().getSelectedItem();
1620
+ if (oSelectedItem) {
1621
+ var currentFormatterCommand = oRTE.getAggregation("_toolbarWrapper")._getFormatBlockCommand(oSelectedItem.getText());
1622
+ oRTE.getNativeApi().execCommand('FormatBlock', false, currentFormatterCommand);
1623
+ }
1624
+ } else {
1625
+ Log.warning("Cannot execute native command: " + 'FormatBlock');
1626
+ }
1627
+ }
1628
+ }).setVisible(bVisible)
1629
+ ];
1630
+ };
1631
+
1632
+ ToolbarWrapper.prototype._createFontStyleToolbarContent = function (aButtonsToCreate, bVisible) {
1633
+ var aToolbarContent = [];
1634
+
1635
+ aButtonsToCreate.forEach(function (oCommand) {
1636
+ aToolbarContent.push(this._helper.createOverflowToolbarToggleButton(this._createButtonConfig(oCommand)).setVisible(bVisible));
1637
+ }, this);
1638
+
1639
+ return aToolbarContent;
1640
+ };
1641
+
1642
+ ToolbarWrapper.prototype._createInsertToolbarContent = function (bVisible) {
1643
+ return [this._helper.createOverflowToolbarToggleButton(this._createButtonForDialog("InsertImage")).setVisible(bVisible)];
1644
+ };
1645
+
1646
+ ToolbarWrapper.prototype._createLinkToolbarContent = function (aButtonsToCreate, bVisible) {
1647
+ var aToolbarContent = [];
1648
+
1649
+ // All buttons in this group should be handled case by case as they are not of the same type.
1650
+ if (aButtonsToCreate.indexOf("InsertLink") !== -1) {
1651
+ aToolbarContent.push(this._helper.createOverflowToolbarToggleButton(this._createButtonForDialog("InsertLink")).setVisible(bVisible));
1652
+ }
1653
+ if (aButtonsToCreate.indexOf("Unlink") !== -1) {
1654
+ aToolbarContent.push(this._helper.createOverflowToolbarButton(this._createButtonConfig("Unlink")).setVisible(bVisible));
1655
+ }
1656
+
1657
+ return aToolbarContent;
1658
+ };
1659
+
1660
+ ToolbarWrapper.prototype._createStructureToolbarContent = function (aButtonsToCreate, bVisible) {
1661
+ var aToolbarContent = [];
1662
+
1663
+ aButtonsToCreate.forEach(function (oCommand) {
1664
+ aToolbarContent.push(this._helper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisible));
1665
+ }, this);
1666
+
1667
+ return aToolbarContent;
1668
+ };
1669
+
1670
+ ToolbarWrapper.prototype._createClipboardToolbarContent = function (aButtonsToCreate, bVisible) {
1671
+ var aToolbarContent = [];
1672
+
1673
+ aButtonsToCreate.forEach(function (oCommand) {
1674
+ aToolbarContent.push(this._helper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisible));
1675
+ }, this);
1676
+
1677
+ return aToolbarContent;
1678
+ };
1679
+
1680
+ ToolbarWrapper.prototype._createUndoToolbarContent = function (aButtonsToCreate, bVisible) {
1681
+ var aToolbarContent = [];
1682
+
1683
+ aButtonsToCreate.forEach(function (oCommand) {
1684
+ aToolbarContent.push(this._helper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisible));
1685
+ }, this);
1686
+
1687
+ return aToolbarContent;
1688
+ };
1689
+
1690
+ /**
1691
+ * Creates a Button Group for the Custom Toolbar
1692
+ *
1693
+ * @param {string} [mGroup] Object map containing group information.
1694
+ * @param {string[]} [mGroup.buttons] Array of name/IDs of the buttons in the group
1695
+ * @param {string} [mGroup.name] Name/ID of the group.
1696
+ * @param {boolean} [mGroup.visible=true] (optional) The priority of the button group. Lower priorities are added first.
1697
+ * @param {int} [mGroup.row=0] (optional) Row number in which the button should be
1698
+ * @param {int} [mGroup.priority=10] (optional) The priority of the button group. Lower priorities are added first.
1699
+ * @param {int} [mGroup.customToolbarPriority] (optional) The priority of the button group in the custom toolbar. Each default group in the custom toolbar has a predefined <code>customToolbarPriority</code>. Lower priorities are added in first.
1379
1700
  * @returns {Array} An array containing the buttons in the group that should be added to the Custom Toolbar's content
1380
- * @public
1701
+ * @private
1381
1702
  */
1382
- ToolbarWrapper.prototype.addButtonGroup = function (sGroupName) {
1703
+ ToolbarWrapper.prototype._createButtonGroup = function (mGroup) {
1383
1704
  var oRTE = this.getEditor(),
1384
1705
  oEditorHelper = this._helper,
1385
1706
  aContent = [],
1386
- oButtonGroups = library.ButtonGroups,
1387
- oCommands = library.EditorCommands,
1388
- oAccessibilityKeys = library.Accessibility,
1389
- bVisibleGroupClipboard,
1390
- bVisibleGroupStructure,
1391
- bVisibleGroupFont,
1392
- bVisibleGroupFontStyle,
1393
- bVisibleGroupUndo,
1394
- bVisibleGroupTextAlign,
1395
- bVisibleGroupFormatBlock,
1396
- bVisibleGroupLink,
1397
- bVisibleGroupInsert,
1398
- oToolbar = this;
1707
+ aToolbarButtonsToCreate = [];
1399
1708
 
1709
+ if (!oRTE) {
1710
+ return [];
1711
+ }
1400
1712
 
1401
- switch (sGroupName) {
1402
- case "font-style":
1403
- bVisibleGroupFontStyle = oRTE ? oRTE.getShowGroupFontStyle() : false;
1713
+ // Map native tinyMCE style button names (e.g. "bold", "forecolor") to supported by the custom toolbar button commands (e.g. "Bold", "TextColor").
1714
+ // If the group does not have "buttons" property, the default configuration for this particular group will be used.
1715
+ aToolbarButtonsToCreate = this._mapNativeButtonsToCommands(mGroup.name, mGroup.buttons);
1404
1716
 
1405
- oButtonGroups["font-style"].forEach(function (oCommand) {
1406
- aContent.push(oEditorHelper.createOverflowToolbarToggleButton(this._createButtonConfig(oCommand)).setVisible(bVisibleGroupFontStyle));
1407
- }, this);
1717
+ switch (mGroup.name) {
1718
+ case "font-style":
1719
+ aContent = this._createFontStyleToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1408
1720
  break;
1409
1721
  case "font":
1410
- bVisibleGroupFont = oRTE ? oRTE.getShowGroupFont() : false;
1411
-
1412
- var oInvisibleTextFontFamily = oEditorHelper.createInvisibleText({
1413
- text: this._oResourceBundle.getText(oAccessibilityKeys["FontFamily"])
1414
- }).toStatic(),
1415
- oInvisibleTextFontSize = oEditorHelper.createInvisibleText({
1416
- text: this._oResourceBundle.getText(oAccessibilityKeys["FontSize"])
1417
- }).toStatic(),
1418
- oInvisibleTextFontColor = oEditorHelper.createInvisibleText({
1419
- text: this._oResourceBundle.getText(oAccessibilityKeys["FontColor"])
1420
- }).toStatic(),
1421
- oInvisibleTextBackgroundColor = oEditorHelper.createInvisibleText({
1422
- text: this._oResourceBundle.getText(oAccessibilityKeys["BackgroundColor"])
1423
- }).toStatic();
1424
- this._registerAssociatedInvisibleTexts("font", oInvisibleTextFontFamily.getId());
1425
- this._registerAssociatedInvisibleTexts("font", oInvisibleTextFontSize.getId());
1426
-
1427
- aContent.push(
1428
- oEditorHelper.createSelect({
1429
- id: this._getId("FontFamily"),
1430
- ariaLabelledBy: oInvisibleTextFontFamily,
1431
- selectedItemId: this._getId("FontFamilyVerdana"),
1432
- items: this._createFontStyleSelectItems(),
1433
- change: function (oEvent) {
1434
- var oItem;
1435
-
1436
- if (oRTE) {
1437
- oItem = oEvent.getSource().getSelectedItem();
1438
- oRTE.getNativeApi().execCommand('FontName', false, this._getFontStyleCommand(oItem.getText()));
1439
- } else {
1440
- Log.warning("Cannot execute native command: " + 'FontName');
1441
- }
1442
- }.bind(this)
1443
- }).setVisible(bVisibleGroupFont)
1444
- );
1445
-
1446
- aContent.push(
1447
- oEditorHelper.createSelect({
1448
- id: this._getId("FontSize"),
1449
- ariaLabelledBy: oInvisibleTextFontSize,
1450
- selectedItemId: this._getId("FontSize2"),
1451
- items: this._createFontSizeSelectItems(),
1452
- change: function (oEvent) {
1453
- var oItem;
1454
-
1455
- if (oRTE) {
1456
- oItem = oEvent.getSource().getSelectedItem();
1457
- oRTE.getNativeApi().execCommand('FontSize', false, oItem.getText().replace(/\s/g, ""));
1458
- } else {
1459
- Log.warning("Cannot execute native command: " + 'FontSize');
1460
- }
1461
- }
1462
- }).setVisible(bVisibleGroupFont)
1463
- );
1464
- var oRTESplitButton = new RTESplitButton(this._createSplitButtonForDialog("TextColor")).setVisible(bVisibleGroupFont),
1465
- oBackgroundColorButton = oEditorHelper.createSplitButton(this._createSplitButtonForDialog("BackgroundColor")).setVisible(bVisibleGroupFont);
1466
-
1467
- oRTESplitButton._getTextButton().addAriaLabelledBy(oInvisibleTextFontColor);
1468
- aContent.push(oRTESplitButton);
1469
-
1470
- oBackgroundColorButton._getTextButton().addAriaLabelledBy(oInvisibleTextBackgroundColor);
1471
- aContent.push(oBackgroundColorButton);
1722
+ aContent = this._createFontToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1472
1723
  break;
1473
1724
  case "text-align":
1474
- bVisibleGroupTextAlign = oRTE ? oRTE.getShowGroupTextAlign() : false;
1475
- var bTextAlignLRight = oRTE._getTextDirection() === "rtl";
1476
- var iDefaultItemIndex = bTextAlignLRight ? 2 : 0;
1477
- var aMenuItems = this._createMenuButtonItems("TextAlign");
1478
- aContent.push(
1479
- oEditorHelper.createMenuButton(
1480
- this._getId("TextAlign"),
1481
- aMenuItems,
1482
- function (oEvent) {
1483
- var oSelectedItem, oEditor, oSelectedItemIcon;
1484
-
1485
- if (oRTE) {
1486
- oSelectedItem = oEvent.getParameter("item");
1487
- oEditor = oRTE.getNativeApi();
1488
- oSelectedItemIcon = oSelectedItem.getIcon();
1489
- if (oSelectedItemIcon === this.getParent().getIcon()) {
1490
- var sTextAlign = bTextAlignLRight ? "JustifyRight" : "JustifyLeft";
1491
- // Text Align commands in TinyMCE have a toggle behavior when you set a
1492
- // certain command twice the default command (text-align-left) will be applied
1493
- oEditor.execCommand(sTextAlign);
1494
- } else {
1495
- oEditor.execCommand('Justify' + oToolbar._findTextAlignCommandByIcon(oSelectedItemIcon));
1496
- }
1497
- } else {
1498
- Log.warning("Cannot execute native command: " + 'Justify');
1499
- }
1500
- },
1501
- aMenuItems[iDefaultItemIndex].getIcon(),
1502
- this._oResourceBundle.getText(oCommands["TextAlign"].bundleKey)
1503
- ).setVisible(bVisibleGroupTextAlign)
1504
- );
1725
+ aContent = this._createTextAlignToolbarContent(mGroup.visible);
1505
1726
  break;
1727
+ case "styleselect":
1506
1728
  case "formatselect":
1507
- bVisibleGroupFormatBlock = oRTE ? (this._isButtonGroupAdded("styleselect") || this._isButtonGroupAdded("formatselect")) : false;
1508
-
1509
- if (bVisibleGroupFormatBlock) {
1510
- var oInvisibleTextFormatBlock = oEditorHelper.createInvisibleText({
1511
- text: this._oResourceBundle.getText(oAccessibilityKeys["FormatBlock"])
1512
- }).toStatic();
1513
- this._registerAssociatedInvisibleTexts("formatselect", oInvisibleTextFormatBlock.getId());
1514
- aContent.push(
1515
- oEditorHelper.createSelect({
1516
- id: this._getId("FormatBlock"),
1517
- ariaLabelledBy: oInvisibleTextFormatBlock,
1518
- items: this._createFormatBlockItems(),
1519
- change: function (oEvent) {
1520
- var oSelectedItem;
1521
- if (oRTE) {
1522
- oSelectedItem = oEvent.getSource().getSelectedItem();
1523
- if (oSelectedItem) {
1524
- var currentFormatterCommand = oRTE.getAggregation("_toolbarWrapper")._getFormatBlockCommand(oSelectedItem.getText());
1525
- oRTE.getNativeApi().execCommand('FormatBlock', false, currentFormatterCommand);
1526
- }
1527
- } else {
1528
- Log.warning("Cannot execute native command: " + 'FormatBlock');
1529
- }
1530
- }
1531
- }).setVisible(bVisibleGroupFormatBlock)
1532
- );
1533
- }
1729
+ aContent = this._createFormatSelectToolbarContent(this._isButtonGroupAdded("styleselect") || this._isButtonGroupAdded("formatselect"));
1534
1730
  break;
1535
1731
  case "structure":
1536
- bVisibleGroupStructure = oRTE ? oRTE.getShowGroupStructure() : false;
1537
- oButtonGroups["structure"].forEach(function (oCommand) {
1538
- aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisibleGroupStructure));
1539
- }, this);
1732
+ aContent = this._createStructureToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1540
1733
  break;
1541
1734
  case "clipboard":
1542
- bVisibleGroupClipboard = oRTE ? oRTE.getShowGroupClipboard() : false;
1543
- oButtonGroups["clipboard"].forEach(function (oCommand) {
1544
- aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisibleGroupClipboard));
1545
- }, this);
1735
+ aContent = this._createClipboardToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1546
1736
  break;
1547
1737
  case "undo":
1548
- bVisibleGroupUndo = oRTE ? oRTE.getShowGroupUndo() : false;
1549
- oButtonGroups["undo"].forEach(function (oCommand) {
1550
- aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonConfig(oCommand)).setVisible(bVisibleGroupUndo));
1551
- }, this);
1738
+ aContent = this._createUndoToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1552
1739
  break;
1553
1740
  case "insert":
1554
- bVisibleGroupInsert = oRTE ? oRTE.getShowGroupInsert() : false;
1555
- aContent.push(oEditorHelper.createOverflowToolbarToggleButton(this._createButtonForDialog("InsertImage")).setVisible(bVisibleGroupInsert));
1741
+ aContent = this._createInsertToolbarContent(mGroup.visible);
1556
1742
  break;
1557
1743
  case "link":
1558
- bVisibleGroupLink = oRTE ? oRTE.getShowGroupLink() : false;
1559
- aContent.push(oEditorHelper.createOverflowToolbarToggleButton(this._createButtonForDialog("InsertLink")).setVisible(bVisibleGroupLink));
1560
- aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonConfig("Unlink")).setVisible(bVisibleGroupLink));
1744
+ aContent = this._createLinkToolbarContent(aToolbarButtonsToCreate, mGroup.visible);
1561
1745
  break;
1562
1746
  case "table":
1563
- aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonForDialog("InsertTable")));
1747
+ aContent.push(oEditorHelper.createOverflowToolbarButton(this._createButtonForDialog("InsertTable")).setVisible(mGroup.visible));
1564
1748
  break;
1749
+ default: break;
1565
1750
  }
1566
1751
 
1567
1752
  return aContent;
@@ -1571,36 +1756,28 @@ sap.ui.define([
1571
1756
  * Adds a Button Group to an existing Toolbar
1572
1757
  *
1573
1758
  * @param {map} [mGroup] Group object
1574
- * @param {boolean} [bFullGroup] If false, the group is generated from a group name
1575
1759
  * @returns {object} this for method chaining
1576
1760
  * @public
1577
1761
  */
1578
- ToolbarWrapper.prototype.addButtonGroupToContent = function (mGroup, bFullGroup) {
1762
+ ToolbarWrapper.prototype.addButtonGroupToContent = function (mGroup) {
1579
1763
  var sGroupName;
1580
1764
  // if the group is generated add it to the button groups object
1581
1765
  // as a custom group (if it contains supported group buttons - ex."table")
1582
- if (!bFullGroup && mGroup.buttons[0] === "table") {
1583
- sGroupName = mGroup.buttons[0];
1584
- sap.ui.richtexteditor.ButtonGroups.custom[mGroup.name] = {
1585
- name: mGroup.buttons[0],
1586
- controls: ["InsertTable"]
1587
- };
1588
- }
1589
1766
 
1590
1767
  // if the group is supported (ex. "table") add it to the button groups object
1591
- if (bFullGroup && mGroup.name === "table") {
1768
+ if (mGroup.name === "table") {
1592
1769
  sGroupName = mGroup.name;
1593
- sap.ui.richtexteditor.ButtonGroups[mGroup.name] = ["InsertTable"];
1770
+ ButtonGroups[mGroup.name] = ["InsertTable"];
1594
1771
  }
1595
1772
 
1596
1773
  // if the group is supported (ex. "formatselect") add it to the button groups object
1597
- if (bFullGroup && (mGroup.name === "formatselect" || mGroup.name === "styleselect")) {
1774
+ if (mGroup.name === "formatselect" || mGroup.name === "styleselect") {
1598
1775
  sGroupName = "formatselect";
1599
- sap.ui.richtexteditor.ButtonGroups[mGroup.name] = ["FormatBlock"];
1776
+ ButtonGroups[mGroup.name] = ["FormatBlock"];
1600
1777
  }
1601
1778
 
1602
1779
  // if not supported return and do not add content
1603
- if (!sap.ui.richtexteditor.ButtonGroups[mGroup.name] && !sap.ui.richtexteditor.ButtonGroups.custom[mGroup.name]) {
1780
+ if (!ButtonGroups[mGroup.name] && !ButtonGroups.custom[mGroup.name]) {
1604
1781
  return this;
1605
1782
  }
1606
1783
 
@@ -1611,7 +1788,7 @@ sap.ui.define([
1611
1788
  }
1612
1789
 
1613
1790
  var oToolbar = this.getAggregation("_toolbar"),
1614
- aContent = this.addButtonGroup(sGroupName),
1791
+ aContent = this._createButtonGroup(mGroup),
1615
1792
  iContentSize = aContent.length,
1616
1793
  i, iStartIndex;
1617
1794
 
@@ -1646,7 +1823,6 @@ sap.ui.define([
1646
1823
  */
1647
1824
  ToolbarWrapper.prototype._findGroupPriorityPosition = function (mGroup) {
1648
1825
  var aGroups = this.getEditor().getButtonGroups(),
1649
- aCustomToolbarGroups = library.ButtonGroups,
1650
1826
  iStartIndex = 0;
1651
1827
 
1652
1828
  // place groups without predefined customToolbarPriority at the end
@@ -1657,10 +1833,23 @@ sap.ui.define([
1657
1833
  // sort groups according to customToolbarPriority
1658
1834
  aGroups = this._sortToolbarContent(aGroups);
1659
1835
 
1660
- aGroups.forEach(function (oGroup) {
1661
- if (oGroup.customToolbarPriority < mGroup.customToolbarPriority && oGroup.name !== mGroup.name) {
1836
+ aGroups
1837
+ // Map all groups to supported buttons that can be created in the custom toolbar
1838
+ // based on the current group configuration
1839
+ .map(function (oGroup) {
1840
+ // We need new object that maps buttons to commands, as they do not map directly and some of the configurations
1841
+ // may have many buttons, which is then translated to single control in the custom toolbar.
1842
+ return {
1843
+ name: oGroup.name,
1844
+ iButtonsCount: this._mapNativeButtonsToCommands(oGroup.name, oGroup.buttons).length,
1845
+ customToolbarPriority: oGroup.customToolbarPriority
1846
+ };
1847
+ }.bind(this))
1848
+ // Find the correct starting index for this group, based on the customToolbarPriority group property
1849
+ .forEach(function (oMappedGroup) {
1850
+ if (oMappedGroup.customToolbarPriority < mGroup.customToolbarPriority && oMappedGroup.name !== mGroup.name) {
1662
1851
  // if the group exist for the customToolbar, add its button count to the startIndex
1663
- iStartIndex += aCustomToolbarGroups[oGroup.name] ? aCustomToolbarGroups[oGroup.name].length : 0;
1852
+ iStartIndex += ButtonGroups[oMappedGroup.name] ? oMappedGroup.iButtonsCount : 0;
1664
1853
  }
1665
1854
  });
1666
1855
 
@@ -1691,6 +1880,11 @@ sap.ui.define([
1691
1880
  ToolbarWrapper.prototype.removeButtonGroup = function (sGroupName) {
1692
1881
  var aObjects = this._findGroupedControls(sGroupName);
1693
1882
 
1883
+ // Detach handlers from color picker dialogs if the font group is removed
1884
+ if (sGroupName === "font") {
1885
+ this._modifyPopoverOpeningArrowHandlers(false);
1886
+ }
1887
+
1694
1888
  // destroys associated InvisibleTexts for the group
1695
1889
  this._destroyAssociatedInvisibleTexts(sGroupName);
1696
1890
 
@@ -1818,18 +2012,17 @@ sap.ui.define([
1818
2012
  * @private
1819
2013
  */
1820
2014
  ToolbarWrapper.prototype._findGroupedControls = function (sGroupName) {
1821
- var oButtonGroups = library.ButtonGroups,
1822
- oToolbar = this.getAggregation("_toolbar"),
2015
+ var oToolbar = this.getAggregation("_toolbar"),
1823
2016
  aControls = [];
1824
2017
 
1825
2018
  if (!oToolbar) {
1826
2019
  return [];
1827
2020
  }
1828
2021
 
1829
- if (oButtonGroups[sGroupName]) {
1830
- aControls = oButtonGroups[sGroupName];
1831
- } else if (oButtonGroups.custom[sGroupName]) {
1832
- aControls = oButtonGroups.custom[sGroupName].controls;
2022
+ if (ButtonGroups[sGroupName]) {
2023
+ aControls = ButtonGroups[sGroupName];
2024
+ } else if (ButtonGroups.custom[sGroupName]) {
2025
+ aControls = ButtonGroups.custom[sGroupName].controls;
1833
2026
  }
1834
2027
 
1835
2028
  var aIds = aControls.map(function (sName) {
@@ -1889,6 +2082,9 @@ sap.ui.define([
1889
2082
  case "remove":
1890
2083
  vResult = this._proxyToolbarRemove.apply(this, args);
1891
2084
  break;
2085
+
2086
+ default:
2087
+ break;
1892
2088
  }
1893
2089
 
1894
2090
  return vResult;
@@ -2016,6 +2212,8 @@ sap.ui.define([
2016
2212
  case "number":
2017
2213
  sId = this._customButtons[vItem];
2018
2214
  break;
2215
+ default:
2216
+ break;
2019
2217
  }
2020
2218
 
2021
2219
  vResult = oToolbar.removeContent(sId);
@@ -2027,5 +2225,19 @@ sap.ui.define([
2027
2225
  return vResult;
2028
2226
  };
2029
2227
 
2228
+ /**
2229
+ * Helper function for finding controls in the Toolbar by their corresponding names.
2230
+ *
2231
+ * @param {string} sButtonName Custom toolbar button name (Bold, TextAlign, Italic, TextColor, etc...)
2232
+ * @returns {sap.ui.core.Control|null} The control with the corresponding name or null.
2233
+ */
2234
+ ToolbarWrapper.prototype._findButtonById = function (sButtonName) {
2235
+ var oRTE = this.getEditor();
2236
+ if (!oRTE) {
2237
+ return null;
2238
+ }
2239
+ return Core.byId(oRTE.getId() + this.getId() + "-" + sButtonName);
2240
+ };
2241
+
2030
2242
  return ToolbarWrapper;
2031
2243
  });