@openui5/sap.f 1.119.1 → 1.120.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 (130) hide show
  1. package/THIRDPARTY.txt +6 -6
  2. package/package.json +4 -4
  3. package/src/sap/f/.library +1 -1
  4. package/src/sap/f/Avatar.js +1 -1
  5. package/src/sap/f/AvatarGroup.js +1 -1
  6. package/src/sap/f/AvatarGroupItem.js +1 -1
  7. package/src/sap/f/CalendarAppointmentInCard.js +1 -1
  8. package/src/sap/f/CalendarInCard.js +1 -1
  9. package/src/sap/f/Card.js +1 -1
  10. package/src/sap/f/CardBase.js +1 -1
  11. package/src/sap/f/DynamicPage.js +1 -1
  12. package/src/sap/f/DynamicPageAccessibleLandmarkInfo.js +1 -1
  13. package/src/sap/f/DynamicPageHeader.js +1 -1
  14. package/src/sap/f/DynamicPageTitle.js +1 -1
  15. package/src/sap/f/FlexibleColumnLayout.js +1143 -427
  16. package/src/sap/f/FlexibleColumnLayoutAccessibleLandmarkInfo.js +1 -1
  17. package/src/sap/f/FlexibleColumnLayoutRenderer.js +64 -27
  18. package/src/sap/f/FlexibleColumnLayoutSemanticHelper.js +5 -5
  19. package/src/sap/f/GridContainer.js +2 -4
  20. package/src/sap/f/GridContainerItemLayoutData.js +1 -1
  21. package/src/sap/f/GridContainerSettings.js +2 -2
  22. package/src/sap/f/GridList.js +2 -2
  23. package/src/sap/f/GridListItem.js +1 -1
  24. package/src/sap/f/IllustratedMessage.js +1 -1
  25. package/src/sap/f/Illustration.js +1 -1
  26. package/src/sap/f/PlanningCalendarInCardLegend.js +1 -1
  27. package/src/sap/f/ProductSwitch.js +1 -1
  28. package/src/sap/f/ProductSwitchItem.js +1 -1
  29. package/src/sap/f/SearchManager.js +1 -1
  30. package/src/sap/f/ShellBar.js +1 -1
  31. package/src/sap/f/SidePanel.js +1 -1
  32. package/src/sap/f/SidePanelItem.js +1 -1
  33. package/src/sap/f/cards/BaseHeader.js +1 -1
  34. package/src/sap/f/cards/Header.js +1 -1
  35. package/src/sap/f/cards/NumericHeader.js +1 -1
  36. package/src/sap/f/cards/NumericIndicators.js +1 -1
  37. package/src/sap/f/cards/NumericSideIndicator.js +1 -1
  38. package/src/sap/f/cards/loading/AnalyticalPlaceholder.js +1 -1
  39. package/src/sap/f/cards/loading/CalendarPlaceholder.js +8 -1
  40. package/src/sap/f/cards/loading/GenericPlaceholder.js +1 -1
  41. package/src/sap/f/cards/loading/ListPlaceholder.js +33 -4
  42. package/src/sap/f/cards/loading/ListPlaceholderRenderer.js +18 -21
  43. package/src/sap/f/cards/loading/ObjectPlaceholder.js +1 -1
  44. package/src/sap/f/cards/loading/PlaceholderBase.js +1 -1
  45. package/src/sap/f/cards/loading/TablePlaceholder.js +1 -1
  46. package/src/sap/f/cards/loading/TimelinePlaceholder.js +1 -1
  47. package/src/sap/f/changeHandler/MoveDynamicPageTitleActions.js +1 -1
  48. package/src/sap/f/delegate/GridContainerItemNavigation.js +6 -1
  49. package/src/sap/f/delegate/GridItemNavigation.js +16 -19
  50. package/src/sap/f/designtime/messagebundle_mk.properties +8 -0
  51. package/src/sap/f/dnd/GridDragOver.js +1 -1
  52. package/src/sap/f/dnd/GridDropInfo.js +1 -1
  53. package/src/sap/f/library.js +2 -2
  54. package/src/sap/f/messagebundle.properties +3 -12
  55. package/src/sap/f/messagebundle_ar.properties +2 -8
  56. package/src/sap/f/messagebundle_bg.properties +2 -8
  57. package/src/sap/f/messagebundle_ca.properties +2 -8
  58. package/src/sap/f/messagebundle_cs.properties +2 -8
  59. package/src/sap/f/messagebundle_cy.properties +2 -8
  60. package/src/sap/f/messagebundle_da.properties +2 -8
  61. package/src/sap/f/messagebundle_de.properties +2 -8
  62. package/src/sap/f/messagebundle_el.properties +2 -8
  63. package/src/sap/f/messagebundle_en.properties +2 -8
  64. package/src/sap/f/messagebundle_en_GB.properties +2 -8
  65. package/src/sap/f/messagebundle_es.properties +2 -8
  66. package/src/sap/f/messagebundle_es_MX.properties +2 -8
  67. package/src/sap/f/messagebundle_et.properties +2 -8
  68. package/src/sap/f/messagebundle_fi.properties +2 -8
  69. package/src/sap/f/messagebundle_fr.properties +3 -9
  70. package/src/sap/f/messagebundle_fr_CA.properties +2 -8
  71. package/src/sap/f/messagebundle_hi.properties +2 -8
  72. package/src/sap/f/messagebundle_hr.properties +2 -8
  73. package/src/sap/f/messagebundle_hu.properties +2 -8
  74. package/src/sap/f/messagebundle_id.properties +2 -8
  75. package/src/sap/f/messagebundle_it.properties +2 -8
  76. package/src/sap/f/messagebundle_iw.properties +2 -8
  77. package/src/sap/f/messagebundle_ja.properties +2 -8
  78. package/src/sap/f/messagebundle_kk.properties +2 -8
  79. package/src/sap/f/messagebundle_ko.properties +2 -8
  80. package/src/sap/f/messagebundle_lt.properties +2 -8
  81. package/src/sap/f/messagebundle_lv.properties +2 -8
  82. package/src/sap/f/messagebundle_mk.properties +161 -0
  83. package/src/sap/f/messagebundle_ms.properties +2 -8
  84. package/src/sap/f/messagebundle_nl.properties +2 -8
  85. package/src/sap/f/messagebundle_no.properties +2 -8
  86. package/src/sap/f/messagebundle_pl.properties +2 -8
  87. package/src/sap/f/messagebundle_pt.properties +2 -8
  88. package/src/sap/f/messagebundle_pt_PT.properties +2 -8
  89. package/src/sap/f/messagebundle_ro.properties +2 -8
  90. package/src/sap/f/messagebundle_ru.properties +2 -8
  91. package/src/sap/f/messagebundle_sh.properties +10 -16
  92. package/src/sap/f/messagebundle_sk.properties +2 -8
  93. package/src/sap/f/messagebundle_sl.properties +2 -8
  94. package/src/sap/f/messagebundle_sv.properties +2 -8
  95. package/src/sap/f/messagebundle_th.properties +2 -8
  96. package/src/sap/f/messagebundle_tr.properties +2 -8
  97. package/src/sap/f/messagebundle_uk.properties +2 -8
  98. package/src/sap/f/messagebundle_vi.properties +2 -8
  99. package/src/sap/f/messagebundle_zh_CN.properties +2 -8
  100. package/src/sap/f/messagebundle_zh_TW.properties +2 -8
  101. package/src/sap/f/semantic/AddAction.js +1 -1
  102. package/src/sap/f/semantic/CloseAction.js +1 -1
  103. package/src/sap/f/semantic/CopyAction.js +1 -1
  104. package/src/sap/f/semantic/DeleteAction.js +1 -1
  105. package/src/sap/f/semantic/DiscussInJamAction.js +1 -1
  106. package/src/sap/f/semantic/EditAction.js +1 -1
  107. package/src/sap/f/semantic/ExitFullScreenAction.js +1 -1
  108. package/src/sap/f/semantic/FavoriteAction.js +1 -1
  109. package/src/sap/f/semantic/FlagAction.js +1 -1
  110. package/src/sap/f/semantic/FooterMainAction.js +1 -1
  111. package/src/sap/f/semantic/FullScreenAction.js +1 -1
  112. package/src/sap/f/semantic/MainAction.js +1 -1
  113. package/src/sap/f/semantic/MessagesIndicator.js +1 -1
  114. package/src/sap/f/semantic/NegativeAction.js +1 -1
  115. package/src/sap/f/semantic/PositiveAction.js +1 -1
  116. package/src/sap/f/semantic/PrintAction.js +1 -1
  117. package/src/sap/f/semantic/SemanticButton.js +1 -1
  118. package/src/sap/f/semantic/SemanticConfiguration.js +1 -1
  119. package/src/sap/f/semantic/SemanticControl.js +1 -1
  120. package/src/sap/f/semantic/SemanticPage.js +1 -1
  121. package/src/sap/f/semantic/SemanticToggleButton.js +1 -1
  122. package/src/sap/f/semantic/SendEmailAction.js +1 -1
  123. package/src/sap/f/semantic/SendMessageAction.js +1 -1
  124. package/src/sap/f/semantic/ShareInJamAction.js +1 -1
  125. package/src/sap/f/semantic/TitleMainAction.js +1 -1
  126. package/src/sap/f/shellBar/AdditionalContentSupport.js +1 -1
  127. package/src/sap/f/shellBar/CoPilot.js +1 -1
  128. package/src/sap/f/shellBar/ControlSpacer.js +1 -1
  129. package/src/sap/f/shellBar/Search.js +1 -1
  130. package/src/sap/f/themes/base/FlexibleColumnLayout.less +146 -38
@@ -12,8 +12,8 @@ sap.ui.define([
12
12
  "sap/ui/Device",
13
13
  "sap/ui/core/ResizeHandler",
14
14
  "sap/ui/core/Control",
15
+ "sap/ui/util/Storage",
15
16
  "sap/m/library",
16
- "sap/m/Button",
17
17
  "sap/m/NavContainer",
18
18
  "sap/ui/core/Configuration",
19
19
  'sap/ui/dom/units/Rem',
@@ -31,8 +31,8 @@ sap.ui.define([
31
31
  Device,
32
32
  ResizeHandler,
33
33
  Control,
34
+ Storage,
34
35
  mobileLibrary,
35
- Button,
36
36
  NavContainer,
37
37
  Configuration,
38
38
  DomUnitsRem,
@@ -97,7 +97,7 @@ sap.ui.define([
97
97
  *
98
98
  * @extends sap.ui.core.Control
99
99
  * @author SAP SE
100
- * @version 1.119.1
100
+ * @version 1.120.0
101
101
  *
102
102
  * @constructor
103
103
  * @public
@@ -191,12 +191,7 @@ sap.ui.define([
191
191
 
192
192
  _beginColumnNav: {type : "sap.m.NavContainer", multiple : false, visibility : "hidden"},
193
193
  _midColumnNav: {type : "sap.m.NavContainer", multiple : false, visibility : "hidden"},
194
- _endColumnNav: {type : "sap.m.NavContainer", multiple : false, visibility : "hidden"},
195
-
196
- _beginColumnBackArrow: {type: "sap.m.Button", multiple: false, visibility: "hidden"},
197
- _midColumnForwardArrow: {type: "sap.m.Button", multiple: false, visibility: "hidden"},
198
- _midColumnBackArrow: {type: "sap.m.Button", multiple: false, visibility: "hidden"},
199
- _endColumnForwardArrow: {type: "sap.m.Button", multiple: false, visibility: "hidden"}
194
+ _endColumnNav: {type : "sap.m.NavContainer", multiple : false, visibility : "hidden"}
200
195
  },
201
196
  associations : {
202
197
 
@@ -657,25 +652,12 @@ sap.ui.define([
657
652
  "LastColumn" : "FCL_END_COLUMN_REGION_TEXT"
658
653
  };
659
654
 
660
- FlexibleColumnLayout.DEFAULT_ARROW_LABELS = {
661
- "FirstColumnBackArrow" : "FCL_BEGIN_COLUMN_BACK_ARROW",
662
- "MiddleColumnForwardArrow" : "FCL_MID_COLUMN_FORWARD_ARROW",
663
- "MiddleColumnBackArrow" : "FCL_MID_COLUMN_BACK_ARROW",
664
- "LastColumnForwardArrow" : "FCL_END_COLUMN_FORWARD_ARROW"
665
- };
666
-
667
- FlexibleColumnLayout.ARROW_AGGREGATION_TO_LABEL_MAP = {
668
- "_beginColumnBackArrow" : "FirstColumnBackArrow",
669
- "_midColumnForwardArrow" : "MiddleColumnForwardArrow",
670
- "_midColumnBackArrow" : "MiddleColumnBackArrow",
671
- "_endColumnForwardArrow" : "LastColumnForwardArrow"
672
- };
673
-
674
655
  FlexibleColumnLayout.COLUMN_RESIZING_ANIMATION_DURATION = 560; // ms
675
656
  FlexibleColumnLayout.PINNED_COLUMN_CLASS_NAME = "sapFFCLPinnedColumn";
657
+ FlexibleColumnLayout.ANIMATED_COLUMN_CLASS_NAME = "sapFFCLAnimatedColumn";
676
658
  FlexibleColumnLayout.COLUMN_ORDER = ["begin", "mid", "end"]; // natural order of the columns in FCL
677
- // synced with @_sap_f_FCL_navigation_arrow_width in base less file
678
- FlexibleColumnLayout.NAVIGATION_ARROW_WIDTH = DomUnitsRem.toPx("1rem");
659
+ // synced with @_sap_f_FCL_SeparatorWidth in base less file
660
+ FlexibleColumnLayout.COLUMN_SEPARATOR_WIDTH = DomUnitsRem.toPx("1rem");
679
661
 
680
662
  FlexibleColumnLayout.prototype.init = function () {
681
663
  this._iWidth = 0;
@@ -690,9 +672,6 @@ sap.ui.define([
690
672
  // Create the 3 nav containers
691
673
  this._initNavContainers();
692
674
 
693
- // Create the expand/collapse arrows
694
- this._initButtons();
695
-
696
675
  // Holds an object, responsible for saving and searching the layout history
697
676
  this._oLayoutHistory = new LayoutHistory();
698
677
 
@@ -708,6 +687,24 @@ sap.ui.define([
708
687
  };
709
688
 
710
689
  this._oInvisibleMessage = null;
690
+ this._boundColumnSeparatorMove = this._onColumnSeparatorMove.bind(this);
691
+ this._boundColumnSeparatorMoveEnd = this._onColumnSeparatorMoveEnd.bind(this);
692
+ this._oLocalStorage = {};
693
+ this._bNeverRendered = true;
694
+ };
695
+
696
+ FlexibleColumnLayout.prototype._getLocalStorage = function (iMaxColumnsCount) {
697
+ if (!iMaxColumnsCount) {
698
+ iMaxColumnsCount = this.getMaxColumnsCount();
699
+ }
700
+ var sKey = (iMaxColumnsCount === 3) ? "desktop" : "tablet";
701
+ if (!this._oLocalStorage[sKey]) {
702
+ var sPrefix = sKey === 'desktop' ?
703
+ FlexibleColumnLayout.STORAGE_PREFIX_DESKTOP :
704
+ FlexibleColumnLayout.STORAGE_PREFIX_TABLET;
705
+ this._oLocalStorage[sKey] = new Storage(Storage.Type.local, sPrefix);
706
+ }
707
+ return this._oLocalStorage[sKey];
711
708
  };
712
709
 
713
710
  FlexibleColumnLayout.prototype._announceMessage = function (sResourceBundleKey) {
@@ -731,7 +728,7 @@ sap.ui.define([
731
728
  this._setColumnPagesRendered(oColumnNavContainer.getId(), bHasPages);
732
729
 
733
730
  if (this._hasAnyColumnPagesRendered() !== bHadAnyColumnPagesRendered) {
734
- this._hideShowArrows();
731
+ this._hideShowColumnSeparators();
735
732
  }
736
733
  };
737
734
 
@@ -787,27 +784,6 @@ sap.ui.define([
787
784
  };
788
785
  };
789
786
 
790
- /**
791
- * Formats <code>FlexibleColumnLayoutAccessibleLandmarkInfo</code> label/tooltip of the provided <code>FlexibleColumnLayout</code> arrow.
792
- *
793
- * @param {sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo} oLandmarkInfo FlexibleColumnLayout LandmarkInfo
794
- * @param {string} sArrowAggregationName arrow aggregation name of the layout
795
- * @private
796
- */
797
- FlexibleColumnLayout.prototype._formatArrowLandmarkInfo = function (oLandmarkInfo, sArrowAggregationName) {
798
- var sLabel = null,
799
- sArrowName = FlexibleColumnLayout.ARROW_AGGREGATION_TO_LABEL_MAP[sArrowAggregationName];
800
-
801
- if (oLandmarkInfo) {
802
- sLabel = oLandmarkInfo["get" + sArrowName + "Label"]();
803
- }
804
-
805
- this.getAggregation(sArrowAggregationName).setTooltip(
806
- sLabel ||
807
- FlexibleColumnLayout._getResourceBundle().getText(FlexibleColumnLayout.DEFAULT_ARROW_LABELS[sArrowName]
808
- ));
809
- };
810
-
811
787
  /**
812
788
  * Proxies the navigation events from the internal nav containers to the app.
813
789
  * @param oEvent
@@ -899,7 +875,6 @@ sap.ui.define([
899
875
 
900
876
  var vResult = this.setProperty("layout", sNewLayout, true);
901
877
  this._oLayoutHistory.addEntry(sNewLayout);
902
- this._hideShowArrows();
903
878
  this._resizeColumns();
904
879
 
905
880
  return vResult;
@@ -937,7 +912,6 @@ sap.ui.define([
937
912
 
938
913
  this._cacheDOMElements();
939
914
 
940
- this._hideShowArrows();
941
915
  this._resizeColumns();
942
916
 
943
917
  this._flushColumnContent("begin");
@@ -945,6 +919,37 @@ sap.ui.define([
945
919
  this._flushColumnContent("end");
946
920
 
947
921
  this._fireStateChange(false, false);
922
+ this._bNeverRendered = false;
923
+ };
924
+
925
+ FlexibleColumnLayout.prototype.onmousedown = function (oEvent) {
926
+ if (this._ignoreMouse) {
927
+ return;
928
+ }
929
+ var oTarget = this._getColumnSeparator(oEvent.target);
930
+
931
+ if (!oTarget) {
932
+ return;
933
+ }
934
+ this._ignoreTouch = true;
935
+ this._onColumnSeparatorMoveStart(oEvent, oTarget);
936
+ };
937
+
938
+ FlexibleColumnLayout.prototype.ontouchstart = function (oEvent) {
939
+ if (this._ignoreTouch) {
940
+ return;
941
+ }
942
+ var oTarget = this._getColumnSeparator(oEvent.target);
943
+
944
+ if (!oTarget) {
945
+ return;
946
+ }
947
+ if (!oEvent.changedTouches || !oEvent.changedTouches[0]) {
948
+ // No touch in event
949
+ return;
950
+ }
951
+ this._ignoreMouse = true;
952
+ this._onColumnSeparatorMoveStart(oEvent.changedTouches[0], oTarget, true);
948
953
  };
949
954
 
950
955
  /**
@@ -984,11 +989,13 @@ sap.ui.define([
984
989
  * Checks whether or not the focus is in some columns that are previous to the current
985
990
  * column. For example, if the current is "end", checks if the focus is
986
991
  * in "mid" or "begin" columns.
992
+ * @param {sap.f.LayoutType} sLayout the layout to check
987
993
  * @returns {boolean} whether or not the focus is in columns that are previous to the current column
988
994
  * @private
989
995
  */
990
- FlexibleColumnLayout.prototype._isFocusInSomeOfThePreviousColumns = function () {
991
- var iIndex = FlexibleColumnLayout.COLUMN_ORDER.indexOf(this._sPreviuosLastVisibleColumn) - 1,
996
+ FlexibleColumnLayout.prototype._isFocusInSomeOfThePreviousColumns = function (sLayout) {
997
+ var sLastVisibleColumn = this._getLastVisibleColumnForLayout(sLayout),
998
+ iIndex = FlexibleColumnLayout.COLUMN_ORDER.indexOf(sLastVisibleColumn) - 1,
992
999
  oCurrentColumn;
993
1000
 
994
1001
  for (; iIndex >= 0; iIndex--) {
@@ -1024,6 +1031,7 @@ sap.ui.define([
1024
1031
  this._removeNavContainersFocusOutDelegate();
1025
1032
  this._oRenderedColumnPagesBoolMap = null;
1026
1033
  this._oColumnFocusInfo = null;
1034
+ this._oLocalStorage = null;
1027
1035
  this._deregisterResizeHandler();
1028
1036
  this._handleEvent(jQuery.Event("Destroy"));
1029
1037
  };
@@ -1065,52 +1073,6 @@ sap.ui.define([
1065
1073
  return [this._getBeginColumn(), this._getMidColumn(), this._getEndColumn()];
1066
1074
  };
1067
1075
 
1068
- /**
1069
- * Creates the buttons for the layout arrows, which are initially hidden and will only be shown on demand without re-rendering.
1070
- * @private
1071
- */
1072
- FlexibleColumnLayout.prototype._initButtons = function () {
1073
- var oBeginColumnBackArrow = new Button(this.getId() + "-beginBack", {
1074
- icon: "sap-icon://slim-arrow-left",
1075
- type: "Transparent",
1076
- press: function () {
1077
- this._onArrowClick("left");
1078
- this._announceMessage("FCL_MIDDLE_COLUMN_EXPANDED_MESSAGE");
1079
- }.bind(this)
1080
- }).addStyleClass("sapFFCLNavigationButton").addStyleClass("sapFFCLNavigationButtonRight");
1081
- this.setAggregation("_beginColumnBackArrow", oBeginColumnBackArrow, true);
1082
-
1083
- var oMidColumnForwardArrow = new Button(this.getId() + "-midForward", {
1084
- icon: "sap-icon://slim-arrow-right",
1085
- type: "Transparent",
1086
- press: function () {
1087
- this._onArrowClick("right");
1088
- this._announceMessage("FCL_FIRST_COLUMN_EXPANDED_MESSAGE");
1089
- }.bind(this)
1090
- }).addStyleClass("sapFFCLNavigationButton").addStyleClass("sapFFCLNavigationButtonLeft");
1091
- this.setAggregation("_midColumnForwardArrow", oMidColumnForwardArrow, true);
1092
-
1093
- var oMidColumnBackArrow = new Button(this.getId() + "-midBack", {
1094
- icon: "sap-icon://slim-arrow-left",
1095
- type: "Transparent",
1096
- press: function () {
1097
- this._onArrowClick("left");
1098
- this._announceMessage("FCL_LAST_COLUMN_EXPANDED_MESSAGE");
1099
- }.bind(this)
1100
- }).addStyleClass("sapFFCLNavigationButton").addStyleClass("sapFFCLNavigationButtonRight");
1101
- this.setAggregation("_midColumnBackArrow", oMidColumnBackArrow, true);
1102
-
1103
- var oEndColumnForwardArrow = new Button(this.getId() + "-endForward", {
1104
- icon: "sap-icon://slim-arrow-right",
1105
- type: "Transparent",
1106
- press: function () {
1107
- this._onArrowClick("right");
1108
- this._announceMessage("FCL_MIDDLE_COLUMN_EXPANDED_MESSAGE");
1109
- }.bind(this)
1110
- }).addStyleClass("sapFFCLNavigationButton").addStyleClass("sapFFCLNavigationButtonLeft");
1111
- this.setAggregation("_endColumnForwardArrow", oEndColumnForwardArrow, true);
1112
- };
1113
-
1114
1076
  /**
1115
1077
  * Saves the DOM references of the columns and layout arrows.
1116
1078
  * @private
@@ -1119,7 +1081,9 @@ sap.ui.define([
1119
1081
  this._cacheColumns();
1120
1082
 
1121
1083
  if (!Device.system.phone) {
1122
- this._cacheArrows();
1084
+ this._cacheColumnSeparators();
1085
+ this._$overlay = this.$("overlay");
1086
+ this._$overlaySeparator = this.$("overlaySeparator");
1123
1087
  }
1124
1088
  };
1125
1089
 
@@ -1131,225 +1095,365 @@ sap.ui.define([
1131
1095
  };
1132
1096
  };
1133
1097
 
1134
- FlexibleColumnLayout.prototype._cacheArrows = function () {
1135
- this._oColumnSeparatorArrows = {
1136
- beginBack: this.$("beginBack"),
1137
- midForward: this.$("midForward"),
1138
- midBack: this.$("midBack"),
1139
- endForward: this.$("endForward")
1098
+ FlexibleColumnLayout.prototype._cacheColumnSeparators = function () {
1099
+ this._oColumnSeparators = {
1100
+ begin: this.$("separator-begin"),
1101
+ end: this.$("separator-end")
1140
1102
  };
1141
1103
  };
1142
1104
 
1143
1105
  /**
1144
1106
  * Returns the number of columns that have width > 0
1145
- * @returns {Array.<string>}
1107
+ * @param {sap.f.LayoutType} sLayout the layout to check
1108
+ * @returns {number} the count
1146
1109
  * @private
1147
1110
  */
1148
- FlexibleColumnLayout.prototype._getVisibleColumnsCount = function () {
1111
+ FlexibleColumnLayout.prototype._getVisibleColumnsCount = function (sLayout) {
1112
+ return this._getVisibleColumnsForLayout(sLayout).length;
1113
+ };
1114
+
1115
+ /**
1116
+ * Returns the names of columns that have width > 0
1117
+ * @param {sap.f.LayoutType} sLayout the layout to check
1118
+ * @returns {Array.<string>} the column names
1119
+ * @private
1120
+ */
1121
+ FlexibleColumnLayout.prototype._getVisibleColumnsForLayout = function (sLayout) {
1149
1122
  return FlexibleColumnLayout.COLUMN_ORDER.filter(function (sColumn) {
1150
- return this._getColumnSize(sColumn) > 0;
1151
- }, this).length;
1123
+ return this._getColumnSizeForLayout(sColumn, sLayout) > 0;
1124
+ }, this);
1152
1125
  };
1153
1126
 
1154
1127
  /**
1155
1128
  * Returns the number of columns that have width > 0.
1156
- * @returns {number}
1129
+ * @returns {number} the count
1157
1130
  * @private
1158
1131
  */
1159
- FlexibleColumnLayout.prototype._getVisibleArrowsCount = function () {
1160
- if (!this._oColumnSeparatorArrows) {
1132
+ FlexibleColumnLayout.prototype._getVisibleColumnSeparatorsCount = function () {
1133
+ if (!this._oColumnSeparators) {
1161
1134
  return 0;
1162
1135
  }
1163
1136
 
1164
- return Object.keys(this._oColumnSeparatorArrows).filter(function (sArrow) {
1165
- return this._oColumnSeparatorArrows[sArrow].data("visible");
1137
+ return Object.keys(this._oColumnSeparators).filter(function (sName) {
1138
+ return this._oColumnSeparators[sName].data("visible");
1166
1139
  }, this).length;
1167
1140
  };
1168
1141
 
1169
1142
  /**
1170
1143
  * Returns the total width available for the columns.
1171
- * @param {boolean} bHasInsetColumn
1172
- * @returns {number}
1144
+ * @param {sap.f.LayoutType} sLayout the layout t ckeck
1145
+ * @returns {number} the width in px
1173
1146
  * @private
1174
1147
  */
1175
- FlexibleColumnLayout.prototype._getTotalColumnsWidth = function (bHasInsetColumn) {
1176
- var iSeparatorsCount = this._getVisibleArrowsCount();
1177
- if (bHasInsetColumn) { // inset column has temporarily hidden nav arrow,
1178
- // but empty space *in place of* the navigation arrows for visual consistency
1179
- iSeparatorsCount++;
1180
- }
1181
-
1182
- return this._getControlWidth() - iSeparatorsCount * FlexibleColumnLayout.NAVIGATION_ARROW_WIDTH;
1183
- };
1184
-
1185
- /**
1186
- * Changes the width
1148
+ FlexibleColumnLayout.prototype._getTotalColumnsWidth = function (sLayout) {
1149
+ var iSeparatorsCount = this._getRequiredColumnSeparatorsForLayout(sLayout).length;
1150
+ return this._getControlWidth() - iSeparatorsCount * FlexibleColumnLayout.COLUMN_SEPARATOR_WIDTH;
1151
+ };
1152
+
1153
+ /**
1154
+ * Changes the width of the columns
1155
+ * @param {object} [oOptions] custom resize options (the custom sizes on interactive resize). If not
1156
+ * provided, the default options returned from <code>_getDefaultResizeOptions</code> will be taken.
1157
+ * @param {Object<string,number>} [oOptions.columnWidths] the column widths. If not provided, the default widths
1158
+ * for the current layout will be taken
1159
+ * @param {int} [oOptions.columnWidths.begin] the width of the 'begin' column in px
1160
+ * @param {int} [oOptions.columnWidths.mid] the width of the 'mid' column in px
1161
+ * @param {int} [oOptions.columnWidths.end] the width of the 'end' column in px
1162
+ * @param {sap.f.LayoutType} [oOptions.layout] the current layout type
1163
+ * @param {sap.f.LayoutType} [oOptions.previousLayout] the current layout type. If not provided,
1164
+ * the previous entry from the <code>sap.f.FlexibleColumnLayout.LayoutHistory</code> will be taken.
1165
+ * @param {boolean} oOptions.restoreFocusOnBackNavigation if focus should be restored upon
1166
+ * resize that corresponds to back navigation
1167
+ * @param {boolean} oOptions.updateDetailedActiveClasses specifies if the CSS classes
1168
+ * 'sapFFCLColumnOnlyActive', sapFFCLColumnFirstActive, sapFFCLColumnLastActive should be updated
1169
+ * @param {boolean} oOptions.updateContextualSettings specifies if the contextual settings (for the
1170
+ * new widths) should be propagated to the controls inside the columns
1171
+ * @param {boolean} oOptions.updateMediaCSSClases specifies if the CSS classes for the media
1172
+ * corresponsing to the current columns' width should be set to the columns
1173
+ * @param {boolean} oOptions.hasAnimations specifies if animations are enabled
1187
1174
  * @private
1188
1175
  */
1189
- FlexibleColumnLayout.prototype._resizeColumns = function () {
1190
- var iPercentWidth,
1191
- iAvailableWidth,
1192
- aColumns = FlexibleColumnLayout.COLUMN_ORDER.slice(),
1193
- bRtl = Configuration.getRTL(),
1194
- sAnimationMode = Configuration.getAnimationMode(),
1195
- bHasAnimations = sAnimationMode !== Configuration.AnimationMode.none && sAnimationMode !== Configuration.AnimationMode.minimal,
1196
- aActiveColumns,
1197
- iVisibleColumnsCount,
1198
- iDefaultVisibleColumnsCount,
1176
+ FlexibleColumnLayout.prototype._resizeColumns = function (oOptions) {
1177
+ var aColumns = FlexibleColumnLayout.COLUMN_ORDER.slice(),
1178
+ bHasAnimations,
1199
1179
  sLayout,
1180
+ sPreviousLayout,
1181
+ iVisibleColumnsCount,
1182
+ oColumnWidths,
1200
1183
  sLastVisibleColumn,
1201
1184
  bInsetMidColumn,
1202
1185
  bRestoreFocusOnBackNavigation,
1203
- oPendingAnimationEnd = {};
1186
+ oPendingAnimationEnd;
1204
1187
 
1205
1188
  // Stop here if the control isn't rendered yet
1206
1189
  if (!this.isActive()) {
1207
1190
  return;
1208
1191
  }
1209
1192
 
1210
- iVisibleColumnsCount = this._getVisibleColumnsCount();
1193
+ oOptions = merge(this._getDefaultResizeOptions(), oOptions);
1194
+ sLayout = oOptions.layout;
1195
+ iVisibleColumnsCount = this._getVisibleColumnsCount(sLayout);
1196
+
1211
1197
  if (iVisibleColumnsCount === 0) {
1212
1198
  return;
1213
1199
  }
1214
1200
 
1215
- sLayout = this.getLayout();
1216
- // the default number of columns is the number at maximum control width
1217
- iDefaultVisibleColumnsCount = this._getMaxColumnsCountForLayout(sLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT);
1218
-
1219
- sLastVisibleColumn = aColumns[iDefaultVisibleColumnsCount - 1];
1220
-
1221
- bRestoreFocusOnBackNavigation = this.getRestoreFocusOnBackNavigation() &&
1222
- this._isNavigatingBackward(sLastVisibleColumn) &&
1223
- !this._isFocusInSomeOfThePreviousColumns();
1224
-
1201
+ bHasAnimations = oOptions.hasAnimations;
1202
+ sPreviousLayout = oOptions.previousLayout;
1225
1203
  bInsetMidColumn = (iVisibleColumnsCount === 3) && (sLayout === LT.ThreeColumnsEndExpanded);
1226
- // Calculate the width available for the columns
1227
- iAvailableWidth = this._getTotalColumnsWidth(bInsetMidColumn);
1204
+ oColumnWidths = oOptions.columnWidths || this._getAllColumnSizesForLayout(sLayout, true);
1205
+ sLastVisibleColumn = this._getLastVisibleColumnForLayout(sLayout);
1206
+ bRestoreFocusOnBackNavigation = oOptions.restoreFocusOnBackNavigation &&
1207
+ sPreviousLayout &&
1208
+ this._isNavigatingBackward(sLayout, sPreviousLayout) &&
1209
+ !this._isFocusInSomeOfThePreviousColumns(sPreviousLayout);
1210
+ oPendingAnimationEnd = (bHasAnimations && sPreviousLayout) ?
1211
+ // checks if the previous animation completed
1212
+ this._getAnimationEndStatusForColumns() : {};
1228
1213
 
1229
- // Animations on - Before resizing pin the columns that should not be animated in order to create the reveal/conceal effect
1230
- if (bHasAnimations) {
1231
1214
 
1232
- aColumns.forEach(function (sColumn) {
1233
- var bShouldConcealColumn = this._shouldConcealColumn(iDefaultVisibleColumnsCount, sColumn),
1234
- bShouldRevealColumn = this._shouldRevealColumn(iDefaultVisibleColumnsCount, sColumn === sLastVisibleColumn),
1235
- oColumn = this._$columns[sColumn];
1236
-
1237
- oColumn.toggleClass(FlexibleColumnLayout.PINNED_COLUMN_CLASS_NAME, bShouldConcealColumn || bShouldRevealColumn);
1238
-
1239
- }, this);
1215
+ // Animations on - Before resizing pin the columns that should not be animated in order to create the reveal/conceal effect
1216
+ if (bHasAnimations && sPreviousLayout) {
1217
+ this._pinColumnsBeforeResize(sLayout, sPreviousLayout, oColumnWidths);
1240
1218
 
1241
- // check if the previous animation completed
1242
- aColumns.forEach(function(sColumn) {
1243
- oPendingAnimationEnd[sColumn] = this._oAnimationEndListener.isWaitingForColumnResizeEnd(this._$columns[sColumn]);
1244
- }, this);
1245
1219
  // detach all listeners to any previous unfinished animation
1246
1220
  this._oAnimationEndListener.cancelAll();
1247
1221
  }
1222
+ // update separator visibility only after pinning the columns
1223
+ // to prevent unnecessary resize in the concealed column due to
1224
+ // change of its width upon hiding its preceding separator
1225
+ this._hideShowColumnSeparators();
1248
1226
 
1249
1227
 
1250
1228
  aColumns.forEach(function (sColumn) {
1251
- var oColumn = this._$columns[sColumn],
1252
- oColumnDomRef = oColumn.get(0),
1253
- iNewWidth,
1254
- sNewWidth,
1255
- bShouldRevealColumn,
1256
- bShouldConcealColumn,
1257
- bPinned,
1258
- bCanResizeColumnWithAnimation,
1259
- oOptions;
1260
-
1261
-
1262
- // Calculate the width of the column
1263
- iPercentWidth = this._getColumnSize(sColumn);
1264
- iNewWidth = Math.round(iAvailableWidth * (iPercentWidth / 100));
1265
- if ([100, 0].indexOf(iPercentWidth) !== -1) {
1266
- sNewWidth = iPercentWidth + "%";
1267
- } else {
1268
- sNewWidth = iNewWidth + "px";
1269
- }
1270
1229
 
1230
+ var iWidth = oColumnWidths[sColumn],
1231
+ bShouldRevealColumn = bHasAnimations
1232
+ && this._shouldRevealColumn(sColumn, sLayout, sPreviousLayout),
1233
+ //&& this._$columns[sColumn].width() < FlexibleColumnLayout.COLUMN_MIN_WIDTH,
1234
+ bShouldConcealColumn = bHasAnimations
1235
+ && this._shouldConcealColumn(sColumn, sLayout, sPreviousLayout);
1271
1236
 
1272
- // set the resize options for the column:
1273
- oOptions = {
1274
- previousAnimationCompleted: !oPendingAnimationEnd[oColumn],
1275
- iNewWidth: iNewWidth,
1276
- shouldRestoreFocus: bRestoreFocusOnBackNavigation && (sColumn === sLastVisibleColumn),
1277
- hidden: iPercentWidth === 0 && this._oColumnWidthInfo[sColumn] === 0 // is hidden both before and after the resize
1278
- };
1279
- if (bHasAnimations) {
1280
- bShouldRevealColumn = this._shouldRevealColumn(iDefaultVisibleColumnsCount, sColumn === sLastVisibleColumn);
1281
- bShouldConcealColumn = this._shouldConcealColumn(iDefaultVisibleColumnsCount, sColumn);
1282
- bPinned = bShouldRevealColumn || bShouldConcealColumn;
1283
- oOptions = merge(oOptions, {
1284
- hasAnimations: true,
1285
- shouldConcealColumn: bShouldConcealColumn,
1286
- pinned: bPinned
1287
- });
1288
- bCanResizeColumnWithAnimation = this._canResizeColumnWithAnimation(sColumn, oOptions);
1289
- }
1237
+ this._resizeColumn(sColumn, {
1238
+ width: iWidth,
1290
1239
 
1240
+ shouldRestoreFocus: bRestoreFocusOnBackNavigation &&
1241
+ (sColumn === sLastVisibleColumn),
1291
1242
 
1292
- if (!bShouldConcealColumn) { // do not remove the active class of the concealed column for now (it should remain visible until the end of animations for other columns)
1293
- // Add the active class to the column if it shows something
1294
- oColumn.toggleClass("sapFFCLColumnActive", iPercentWidth > 0);
1295
- }
1243
+ shouldInsetColumn: bInsetMidColumn && (sColumn === "mid"),
1296
1244
 
1297
- oColumn.toggleClass("sapFFCLColumnInset", bInsetMidColumn && (sColumn === "mid"));
1245
+ shouldRevealColumn: bShouldRevealColumn,
1246
+ shouldConcealColumn: bShouldConcealColumn,
1298
1247
 
1299
- // Remove all the classes that are used for HCB theme borders, they will be set again later
1300
- oColumn.removeClass("sapFFCLColumnHidden");
1301
- oColumn.removeClass("sapFFCLColumnOnlyActive");
1302
- oColumn.removeClass("sapFFCLColumnLastActive");
1303
- oColumn.removeClass("sapFFCLColumnFirstActive");
1304
-
1305
-
1306
- // toggle ResizeHandler during the animation
1307
- if (bCanResizeColumnWithAnimation) {
1308
- ResizeHandler.suspend(oColumnDomRef); // Suspend ResizeHandler while animation is running
1309
- this._oAnimationEndListener.waitForColumnResizeEnd(oColumn).then(function() {
1310
- ResizeHandler.resume(oColumnDomRef); // Resume ResizeHandler once animation ended
1311
- }).catch(function() {
1312
- ResizeHandler.resume(oColumnDomRef); // Resume ResizeHandler if animation cancelled
1313
- });
1248
+ // is hidden both before and after the resize
1249
+ hidden: iWidth === 0 && this._oColumnWidthInfo[sColumn] === 0,
1250
+ autoSize: iWidth > 0 && (sColumn === "mid"),
1251
+
1252
+ hasAnimations: bHasAnimations,
1253
+ previousAnimationCompleted: !oPendingAnimationEnd[this._$columns[sColumn]],
1254
+ updateContextualSettings: oOptions.updateContextualSettings,
1255
+ updateMediaCSSClases: oOptions.updateMediaCSSClases
1256
+ });
1257
+ }, this);
1258
+
1259
+ if (oOptions.updateDetailedActiveClasses) {
1260
+ this._addDetailedActiveClasses(sLayout);
1261
+ }
1262
+ };
1263
+
1264
+ /**
1265
+ * Changes the width of the given column
1266
+ * @param {"begin" | "mid" | "end"} sColumn the column name
1267
+ * @param {object} oColumnConfig resize options
1268
+ * @param {int} oColumnConfig.width the width of the column in px
1269
+ * @param {boolean} oColumnConfig.shouldInsetColumn if CSS class "sapFFCLColumnInset"
1270
+ * should be set
1271
+ * @param {boolean} oColumnConfig.autoSize if autoSize, the it should NOT set a fixed width
1272
+ * (in px) to the column, to allow the default width of "100%" take effect. As a result,
1273
+ * the column will take the space that remains after sizing its sibling columns
1274
+ * @param {boolean} oColumnConfig.shouldRestoreFocus if focus should be restored after resize
1275
+ * @param {boolean} oColumnConfig.shouldRevealColumn if the column should be resized with
1276
+ * reveal effect
1277
+ * @param {boolean} oColumnConfig.shouldConcealColumn if the column should be resized with
1278
+ * conceal effect
1279
+ * @param {boolean} oColumnConfig.updateContextualSettings specifies if the contextual settings (for the
1280
+ * new widths) should be propagated to the controls inside the column
1281
+ * @param {boolean} oColumnConfig.updateMediaCSSClases specifies if the CSS classes for the media
1282
+ * corresponsing to the current width should be set to the column
1283
+ * @param {boolean} oColumnConfig.hasAnimations specifies if animations are enabled
1284
+ * @private
1285
+ */
1286
+ FlexibleColumnLayout.prototype._resizeColumn = function (sColumn, oColumnConfig) {
1287
+ var $column = this._$columns[sColumn],
1288
+ oColumnDomRef = $column.get(0),
1289
+ iNewWidth = oColumnConfig.width,
1290
+ sNewWidth = convertPxToCSSSizeString(iNewWidth, this._getControlWidth(), oColumnConfig.shouldInsetColumn),
1291
+ bAutoSize = oColumnConfig.autoSize,
1292
+ bAnimationsEnabled = oColumnConfig.hasAnimations,
1293
+ bPinned = oColumnConfig.shouldRevealColumn || oColumnConfig.shouldConcealColumn,
1294
+ bResizeColumnWithAnimation = this._canResizeColumnWithAnimation(sColumn, oColumnConfig),
1295
+ bSuspendResizeHandler = bAnimationsEnabled && (bResizeColumnWithAnimation || bAutoSize) && !bPinned,
1296
+ fnAfterResizeCallback = this._afterColumnResize.bind(this, sColumn, merge(oColumnConfig, {
1297
+ resumeResizeHandler: bSuspendResizeHandler // toggle back after resize
1298
+ })),
1299
+ fnResizeErrorCallback = function() {
1300
+ ResizeHandler.resume(oColumnDomRef);
1301
+ oColumnDomRef.querySelector(".sapFFCLColumnContent").style.width = "";
1302
+ };
1303
+
1304
+ if (bAutoSize) {
1305
+ // do not set a fixed size to allow the default width:100% take effect
1306
+ sNewWidth = "";
1314
1307
  }
1315
1308
 
1309
+ // Add the active class to the column if it shows something
1310
+ // the concealed column should remain visible until the end of animations for other columns
1311
+ $column.toggleClass("sapFFCLColumnActive", iNewWidth > 0 || oColumnConfig.shouldConcealColumn);
1312
+ $column.toggleClass("sapFFCLColumnInset", oColumnConfig.shouldInsetColumn);
1313
+ // Remove all the classes that are used for HCB theme borders, they will be set again later
1314
+ $column.removeClass("sapFFCLColumnHidden sapFFCLColumnOnlyActive sapFFCLColumnLastActive sapFFCLColumnFirstActive");
1316
1315
 
1317
- // Update the width of the column DOM element
1318
- if (!bShouldConcealColumn) { // regular case
1319
- oColumn.width(sNewWidth);
1320
- } else {
1321
- this._oAnimationEndListener.waitForAllColumnsResizeEnd().then(function() {
1322
- // the concealed column should be resized last (after all other columns resized)
1323
- oColumn.width(sNewWidth);
1324
- }).catch(function() {
1325
- // no action when no resize
1326
- });
1316
+ // Suspend ResizeHandler while animation is running
1317
+ if (bSuspendResizeHandler) {
1318
+ ResizeHandler.suspend(oColumnDomRef);
1327
1319
  }
1328
1320
 
1321
+ if (bResizeColumnWithAnimation) {
1322
+ $column.addClass(FlexibleColumnLayout.ANIMATED_COLUMN_CLASS_NAME);
1323
+ $column.width(sNewWidth);
1324
+ this._attachAfterColumnResizedOnce(sColumn, fnAfterResizeCallback, fnResizeErrorCallback);
1325
+
1326
+ } else if (bAutoSize && bAnimationsEnabled){
1327
+ $column.width(sNewWidth);
1328
+ this._attachAfterAllColumnsResizedOnce(fnAfterResizeCallback, fnResizeErrorCallback);
1329
1329
 
1330
- // Adjust column after resize
1331
- if (bCanResizeColumnWithAnimation || bPinned) {
1332
- this._oAnimationEndListener.waitForAllColumnsResizeEnd().then(this._afterColumnResize.bind(this, sColumn, oOptions)).catch(function() {
1333
- // no action if resize did not complete
1334
- });
1335
1330
  } else {
1336
- this._afterColumnResize(sColumn, oOptions);
1331
+ $column.width(sNewWidth);
1332
+ fnAfterResizeCallback();
1337
1333
  }
1338
1334
 
1339
-
1340
1335
  // For tablet and desktop - notify child controls to render with reduced container size, if they need to
1341
- if (!Device.system.phone) {
1336
+ if (oColumnConfig.updateContextualSettings && !Device.system.phone) {
1342
1337
  this._updateColumnContextualSettings(sColumn, iNewWidth);
1338
+ }
1339
+ if (oColumnConfig.updateMediaCSSClases && !Device.system.phone) {
1343
1340
  this._updateColumnCSSClasses(sColumn, iNewWidth);
1344
1341
  }
1342
+ };
1343
+
1344
+ /**
1345
+ * Adjusts the column after resize
1346
+ *
1347
+ * @param {"begin" | "mid" | "end"} sColumn the column name
1348
+ * @param {object} oOptions the resize options
1349
+ * @param {int} oOptions.width the width of the column in px
1350
+ * @param {boolean} oOptions.shouldRestoreFocus if focus should be restored after resize
1351
+ * @param {boolean} oOptions.shouldRevealColumn if the column is being resized with reveal effect
1352
+ * @param {boolean} oOptions.shouldConcealColumn if the column is being resized with conceal effect
1353
+ * @param {boolean} oOptions.resumeResizeHandler if the <code>ResizeHandler.resume</code> should
1354
+ * be called for the column's DOM elemnt after the resize
1355
+ * @private
1356
+ */
1357
+ FlexibleColumnLayout.prototype._afterColumnResize = function (sColumn, oOptions) {
1358
+ var oColumn = this._$columns[sColumn],
1359
+ bShouldRevealColumn = oOptions.shouldRevealColumn,
1360
+ bShouldConcealColumn = oOptions.shouldConcealColumn,
1361
+ iNewWidth = oOptions.width,
1362
+ bShouldRestoreFocus = oOptions.shouldRestoreFocus;
1363
+
1364
+ if (bShouldRevealColumn || bShouldConcealColumn ) {
1365
+ oColumn[0].querySelector(".sapFFCLColumnContent").style.width = "";
1366
+ }
1367
+ oColumn.toggleClass(FlexibleColumnLayout.PINNED_COLUMN_CLASS_NAME, false);
1368
+ oColumn.toggleClass(FlexibleColumnLayout.ANIMATED_COLUMN_CLASS_NAME, false);
1369
+
1370
+ if (bShouldConcealColumn) {
1371
+ // The column does not show anything anymore, so we can remove the active class
1372
+ oColumn.removeClass("sapFFCLColumnActive");
1373
+ }
1374
+
1375
+ //BCP: 1980006195
1376
+ oColumn.toggleClass("sapFFCLColumnHidden", iNewWidth === 0);
1377
+
1378
+ if (oOptions.resumeResizeHandler) {
1379
+ ResizeHandler.resume(oColumn[0]);
1380
+ }
1381
+
1382
+ this._cacheColumnWidth(sColumn, iNewWidth);
1383
+ if (bShouldRestoreFocus) {
1384
+ this._restoreFocusToColumn(sColumn);
1385
+ }
1386
+ };
1387
+
1388
+ FlexibleColumnLayout.prototype._pinColumnsBeforeResize = function (sLayout, sPreviousLayout, oColumnWidths) {
1389
+ FlexibleColumnLayout.COLUMN_ORDER.slice().forEach(function (sColumn) {
1390
+ var bShouldConcealColumn = this._shouldConcealColumn(sColumn, sLayout, sPreviousLayout),
1391
+ bShouldRevealColumn = this._shouldRevealColumn(sColumn, sLayout, sPreviousLayout),
1392
+ bShouldPin = bShouldConcealColumn || bShouldRevealColumn,
1393
+ oColumn = this._$columns[sColumn],
1394
+ oColumnDomRef = oColumn[0];
1395
+
1396
+ oColumn.toggleClass(FlexibleColumnLayout.PINNED_COLUMN_CLASS_NAME, bShouldPin);
1397
+
1398
+ if (bShouldRevealColumn) {
1399
+ oColumnDomRef.querySelector(".sapFFCLColumnContent").style.width = convertPxToCSSSizeString(oColumnWidths[sColumn], this._getControlWidth());
1400
+ } else if (bShouldConcealColumn) {
1401
+ oColumnDomRef.querySelector(".sapFFCLColumnContent").style.width = oColumnDomRef.offsetWidth + "px";
1402
+ }
1345
1403
 
1404
+ }, this);
1405
+ };
1346
1406
 
1407
+ FlexibleColumnLayout.prototype._getAnimationEndStatusForColumns = function () {
1408
+ var oPendingAnimationEnd = {};
1409
+ // check if the previous animation completed
1410
+ FlexibleColumnLayout.COLUMN_ORDER.slice().forEach(function(sColumn) {
1411
+ oPendingAnimationEnd[sColumn] = this._oAnimationEndListener.isWaitingForColumnResizeEnd(this._$columns[sColumn]);
1347
1412
  }, this);
1413
+ return oPendingAnimationEnd;
1414
+ };
1348
1415
 
1349
- aActiveColumns = aColumns.filter(function (sColumn) {
1350
- return this._getColumnSize(sColumn) > 0;
1416
+ FlexibleColumnLayout.prototype._getAllColumnSizesForLayout = function (sLayout, bNormalizeWidths) {
1417
+ var oSizes = {};
1418
+ FlexibleColumnLayout.COLUMN_ORDER.slice().forEach(function(sColumn) {
1419
+ var iPercentSize = this._getColumnSizeForLayout(sColumn, sLayout),
1420
+ iPxSize = this._convertColumnPercentWidthToPx(iPercentSize, sLayout);
1421
+ oSizes[sColumn] = iPxSize;
1351
1422
  }, this);
1352
1423
 
1424
+ ///needed to cover the case when the custom column sizes (in %) were saved
1425
+ // when using a *larger* screen size, to prevent too narrow columns if the same sizes (in %)
1426
+ // are applied on the smaller screen size
1427
+ if (bNormalizeWidths) {
1428
+ this._normalizeColumnWidths(oSizes, this._getVisibleColumnsForLayout(sLayout));
1429
+ }
1430
+ return oSizes;
1431
+ };
1432
+
1433
+ FlexibleColumnLayout.prototype._getDefaultResizeOptions = function () {
1434
+ var sAnimationMode = Configuration.getAnimationMode();
1435
+ return {
1436
+ layout: this.getLayout(),
1437
+ previousLayout: this._getPreviousLayout(),
1438
+ restoreFocusOnBackNavigation: this.getRestoreFocusOnBackNavigation(),
1439
+ updateDetailedActiveClasses: true,
1440
+ updateContextualSettings: true,
1441
+ updateMediaCSSClases: true,
1442
+ hasAnimations: sAnimationMode !== Configuration.AnimationMode.none && sAnimationMode !== Configuration.AnimationMode.minimal
1443
+ };
1444
+ };
1445
+
1446
+ FlexibleColumnLayout.prototype._getPreviousLayout = function () {
1447
+ return this._getLayoutHistory().getEntry(1, true /* recent first */) || LT.OneColumn;
1448
+ };
1449
+
1450
+ FlexibleColumnLayout.prototype._addDetailedActiveClasses = function (sLayout) {
1451
+ var aColumns = FlexibleColumnLayout.COLUMN_ORDER.slice(),
1452
+ bRtl = Configuration.getRTL(),
1453
+ aActiveColumns = aColumns.filter(function (sColumn) {
1454
+ return this._getColumnSizeForLayout(sColumn, sLayout) > 0;
1455
+ }, this);
1456
+
1353
1457
  if (bRtl) {
1354
1458
  aColumns.reverse();
1355
1459
  }
@@ -1362,37 +1466,569 @@ sap.ui.define([
1362
1466
  this._$columns[aActiveColumns[0]].addClass("sapFFCLColumnFirstActive");
1363
1467
  this._$columns[aActiveColumns[aActiveColumns.length - 1]].addClass("sapFFCLColumnLastActive");
1364
1468
  }
1469
+ };
1365
1470
 
1366
- this._storePreviousResizingInfo(iDefaultVisibleColumnsCount, sLastVisibleColumn);
1471
+ FlexibleColumnLayout.prototype._onColumnSeparatorMoveStart = function (oEvent, oSeparator, bTouch) {
1472
+ // needed to position the separator presizely
1473
+ var bRtl = Configuration.getRTL(),
1474
+ iStartOffset = this._getDraggedSeparatorStartOffset(oSeparator, bRtl);
1475
+
1476
+ this._oDragInfo = {
1477
+ cursorStartX: oEvent.pageX,
1478
+ cursorX: oEvent.pageX, // the mouse/finger position-x
1479
+ columnWidths: {
1480
+ begin: this._$columns.begin.get(0).offsetWidth,
1481
+ mid: this._$columns.mid.get(0).offsetWidth,
1482
+ end: this._$columns.end.get(0).offsetWidth
1483
+ },
1484
+ separator: oSeparator,
1485
+ separatorPosition: {
1486
+ x: iStartOffset,
1487
+ direction: bRtl ? "right" : "left"
1488
+ },
1489
+ layout: this.getLayout(),
1490
+ rtl: bRtl
1491
+ };
1492
+
1493
+ this._enterInteractiveResizeMode(bTouch);
1494
+ };
1495
+
1496
+ FlexibleColumnLayout.prototype._getDraggedSeparatorStartOffset = function (oSeparator, bRtl) {
1497
+ if (bRtl) {
1498
+ return window.innerWidth - oSeparator.getBoundingClientRect().right;
1499
+ }
1500
+ return oSeparator.getBoundingClientRect().left;
1501
+ };
1502
+
1503
+ FlexibleColumnLayout.prototype._onColumnSeparatorMove = function (oEvent) {
1504
+ if (oEvent.preventDefault && !(oEvent.changedTouches)) {
1505
+ oEvent.preventDefault(); // Do not select text
1506
+ }
1507
+
1508
+ var iCursonX = getCursorPositionX(oEvent);
1509
+ this._previewResizedColumnsOnDrag(iCursonX);
1510
+ };
1511
+
1512
+ FlexibleColumnLayout.prototype._onColumnSeparatorMoveEnd = function (oEvent) {
1513
+ var iCursonX = getCursorPositionX(oEvent);
1514
+ this._previewResizedColumnsOnDrag(iCursonX, true /* resize end */);
1515
+ this._saveResizedColumWidths();
1516
+
1517
+ if (this._oDragInfo.layout !== this.getLayout()) {
1518
+ this.setLayout(this._oDragInfo.layout);
1519
+ this._fireStateChange(true, false);
1520
+ }
1521
+
1522
+ this._exitInteractiveResizeMode();
1367
1523
  };
1368
1524
 
1369
1525
  /**
1370
- * Adjusts the column after resize
1526
+ * Returns the separator for the given target. If there isn't such, null is returned
1527
+ * @param {HTMLElement} oTarget The target
1528
+ * @returns {HTMLElement|null} The found bar or null
1529
+ */
1530
+ FlexibleColumnLayout.prototype._getColumnSeparator = function (oTarget) {
1531
+ var oSeparator = oTarget,
1532
+ sId = this.getId();
1533
+
1534
+ if (oSeparator.classList.contains("sapFFCLColumnSeparatorGripIcon")) {
1535
+ oSeparator = oTarget.parentElement;
1536
+ }
1537
+
1538
+ if (oSeparator.classList.contains("sapFFCLColumnSeparatorDecorationBefore")
1539
+ || oSeparator.classList.contains("sapFFCLColumnSeparatorDecorationAfter")
1540
+ || oSeparator.classList.contains("sapFFCLColumnSeparatorGrip")) {
1541
+ oSeparator = oSeparator.parentElement;
1542
+ }
1543
+
1544
+ if (!oSeparator.id || oSeparator.id.indexOf(sId + "-separator") !== 0) {
1545
+ // The clicked element was not one of my splitter bars
1546
+ return null;
1547
+ }
1548
+ return oSeparator;
1549
+ };
1550
+
1551
+ FlexibleColumnLayout.prototype._enterInteractiveResizeMode = function (bTouch) {
1552
+ var oSeparatorPosition = this._oDragInfo.separatorPosition;
1553
+
1554
+ this._$overlay.css("display", "block");
1555
+ this._$overlaySeparator.css(oSeparatorPosition.direction, oSeparatorPosition.x);
1556
+ this._oDragInfo.separator.style.visibility = "hidden";
1557
+
1558
+ if (bTouch) {
1559
+ document.addEventListener("touchend", this._boundColumnSeparatorMoveEnd);
1560
+ document.addEventListener("touchmove", this._boundColumnSeparatorMove);
1561
+ } else {
1562
+ document.addEventListener("mouseup", this._boundColumnSeparatorMoveEnd);
1563
+ document.addEventListener("mousemove", this._boundColumnSeparatorMove);
1564
+ }
1565
+ };
1566
+
1567
+ FlexibleColumnLayout.prototype._exitInteractiveResizeMode = function () {
1568
+ this._$overlay.css("display", "");
1569
+ this._oDragInfo.separator.style.visibility = "";
1570
+ this._oDragInfo.separator.focus();
1571
+ this._ignoreMouse = false;
1572
+ this._ignoreTouch = false;
1573
+ this._oDragInfo = null;
1574
+ document.removeEventListener("mouseup", this._boundColumnSeparatorMoveEnd);
1575
+ document.removeEventListener("mousemove", this._boundColumnSeparatorMove);
1576
+ document.removeEventListener("touchend", this._boundColumnSeparatorMoveEnd);
1577
+ document.removeEventListener("touchmove", this._boundColumnSeparatorMove);
1578
+ };
1579
+
1580
+ FlexibleColumnLayout.prototype._previewResizedColumnsOnDrag = function (cursorX, bIsResizeEnd) {
1581
+ var getPositionOffset = function (iOldCursorX) {
1582
+ var iOffset = cursorX - iOldCursorX;
1583
+ return this._oDragInfo.rtl ? -iOffset : iOffset;
1584
+ }.bind(this);
1585
+
1586
+ this._oDragInfo.offsetFromPreviousPosition = getPositionOffset(this._oDragInfo.cursorX);
1587
+ this._oDragInfo.offsetFromStartPosition = getPositionOffset(this._oDragInfo.cursorStartX);
1588
+ this._oDragInfo.cursorX = cursorX;
1589
+
1590
+ if (!this._oDragInfo.offsetFromStartPosition) {
1591
+ return;
1592
+ }
1593
+
1594
+ if (!this._oDragInfo.offsetFromPreviousPosition && !bIsResizeEnd) {
1595
+ return;
1596
+ }
1597
+
1598
+ var aResizedColumns = getInteractivelyResizedColumns(this._oDragInfo.separator, this._oDragInfo.layout, this.getMaxColumnsCount()),
1599
+ sSeparator = getSeparatorName(this._oDragInfo.separator),
1600
+ bForwardResizeDirection = this._oDragInfo.offsetFromStartPosition > 0,
1601
+ sColumnEnlargedByDragging = aResizedColumns[bForwardResizeDirection ? 0 : 1],
1602
+ iSeparatorsCount = this._getVisibleColumnSeparatorsCount(),
1603
+ iSeparatorsCountDiff = 0,
1604
+ iOffsetOnSeparatorsCountChange = 0,
1605
+ iOffsetOnColumnWidthNormalization,
1606
+ sPreviousLayout = this._oDragInfo.layout,
1607
+ sLayout,
1608
+ bLayoutChange,
1609
+ oNewColumnWidths,
1610
+ bResizeWithPinning;
1611
+
1612
+ this._oDragInfo.columnWidths[aResizedColumns[0]] += this._oDragInfo.offsetFromPreviousPosition;
1613
+ this._oDragInfo.columnWidths[aResizedColumns[1]] -= this._oDragInfo.offsetFromPreviousPosition;
1614
+ this._oDragInfo.columnEnlargedByDragging = sColumnEnlargedByDragging;
1615
+
1616
+ oNewColumnWidths = merge({}, this._oDragInfo.columnWidths);
1617
+
1618
+ // if some column is below min allowed width => expand it
1619
+ this._normalizeColumnWidths(oNewColumnWidths, aResizedColumns);
1620
+
1621
+ // if normalization led to width change of some column => the column separator will be offset
1622
+ iOffsetOnColumnWidthNormalization = this._oDragInfo.columnWidths[aResizedColumns[1]] - oNewColumnWidths[aResizedColumns[1]];
1623
+
1624
+ // update the dragged separator to match the new mouse/touch position
1625
+ this._offsetDraggedColumnSeparator(this._oDragInfo.offsetFromPreviousPosition + iOffsetOnColumnWidthNormalization);
1626
+
1627
+ // if the user drags to expand a hidden column, show its content
1628
+ this._toggleColumnVisibility(sColumnEnlargedByDragging, true);
1629
+
1630
+ sLayout = this._getNextLayoutOnResizeByDrag(oNewColumnWidths, sPreviousLayout, sSeparator, bForwardResizeDirection, bIsResizeEnd);
1631
+ bLayoutChange = sLayout !== sPreviousLayout;
1632
+
1633
+ if (bLayoutChange) {
1634
+ this._hideShowColumnSeparators(sLayout);
1635
+ iSeparatorsCountDiff = iSeparatorsCount - this._getRequiredColumnSeparatorsForLayout(sLayout).length;
1636
+ if (iSeparatorsCountDiff) {
1637
+ iOffsetOnSeparatorsCountChange = FlexibleColumnLayout.COLUMN_SEPARATOR_WIDTH * iSeparatorsCountDiff;
1638
+ oNewColumnWidths.mid += iOffsetOnSeparatorsCountChange;
1639
+ }
1640
+
1641
+ bResizeWithPinning = FlexibleColumnLayout.COLUMN_ORDER.some(function(sColumnName) {
1642
+ return this._shouldRevealColumn(sColumnName, sLayout, sPreviousLayout)
1643
+ || this._shouldConcealColumn(sColumnName, sLayout, sPreviousLayout);
1644
+ }, this);
1645
+
1646
+ oNewColumnWidths = this._mergeColumnWidthsOnInteractiveLayoutChange({
1647
+ oldWidths: this._getAllColumnSizesForLayout(sLayout, true),
1648
+ newWidths: {
1649
+ [aResizedColumns[0]]: oNewColumnWidths[aResizedColumns[0]],
1650
+ [aResizedColumns[1]]: oNewColumnWidths[aResizedColumns[1]]
1651
+ },
1652
+ layout: sLayout,
1653
+ columnEnlargedByDragging: sColumnEnlargedByDragging
1654
+ });
1655
+
1656
+ this._oDragInfo.layout = sLayout;
1657
+ // allow compute dragging direction relative to the last layout
1658
+ this._oDragInfo.cursorStartX = cursorX;
1659
+ }
1660
+
1661
+ this._oDragInfo.columnWidths = oNewColumnWidths;
1662
+
1663
+ if (bResizeWithPinning) {
1664
+ // call the dedicated function in order to resize with reveal/conceal effect
1665
+ this._resizeColumns({
1666
+ columnWidths: oNewColumnWidths,
1667
+ layout: sLayout,
1668
+ previousLayout: sPreviousLayout,
1669
+ updateContextualSettings: false,
1670
+ updateMediaCSSClases: false,
1671
+ updateDetailedActiveClasses: false,
1672
+ restoreFocusOnBackNavigation: false
1673
+ });
1674
+ } else {
1675
+ // only offset the rendered columns
1676
+ // skip mid column as it has width: 100% by default (to allow the mid column
1677
+ // take the space that remains after sizing its sibling columns)
1678
+ this._$columns.begin.css("width", this._oDragInfo.columnWidths.begin + "px");
1679
+ this._$columns.end.css("width", this._oDragInfo.columnWidths.end + "px");
1680
+ }
1681
+ };
1682
+
1683
+ /**
1684
+ * Merges the default (or previously saved) column widths [for the given layout]
1685
+ * with the updated column widths upon interactive resize [when the user dragged
1686
+ * the column separators]
1687
+ * @param {object} oOptions the oprions
1688
+ * @param {Object<string,number>} oOptions.oldWidths the default (or previously saved) column widths
1689
+ * for the given layout
1690
+ * @param {Object<string,number>} oOptions.newWidths the new column widths produced
1691
+ * upon interactive resize, when the user dragged the column separators
1692
+ * @param {sap.f.LayoutType} oOptions.sLayout the layout
1693
+ * @param {"begin"|"mid"|"end"} oOptions.columnEnlargedByDragging the name of the column
1694
+ * enlarged during interactive resize
1695
+ * @returns {Object<string,number>} the merged widths
1696
+ */
1697
+ FlexibleColumnLayout.prototype._mergeColumnWidthsOnInteractiveLayoutChange = function (oOptions) {
1698
+ var oOldWidths = oOptions.oldWidths,
1699
+ oNewWidths = oOptions.newWidths,
1700
+ sLayout = oOptions.layout,
1701
+ sColumnEnlargedByDragging = oOptions.columnEnlargedByDragging,
1702
+ aResizedColumnNames = Object.keys(oNewWidths),
1703
+ iAvailableWidth = this._getTotalColumnsWidth(sLayout),
1704
+ isFullyVisible = function(sColumn) {
1705
+ return oNewWidths[sColumn] >= FlexibleColumnLayout.COLUMN_MIN_WIDTH;
1706
+ },
1707
+ autosizeMid = function(oColumnWidths) {
1708
+ // the mid column takes the remaining space after begin and end are sized
1709
+ oColumnWidths.mid = iAvailableWidth - oColumnWidths.begin - oColumnWidths.end;
1710
+ return oColumnWidths;
1711
+ },
1712
+ sColumnToUpdate;
1713
+
1714
+ if (aResizedColumnNames.indexOf("mid") > -1) {
1715
+ // the other resized column is either 'begin' or 'end' =>
1716
+ // to reflect the update in the widths, it is enough to
1717
+ // merge the width of the column closer to the edge ('begin' or 'end')
1718
+ // and allow the size of the 'mid' column be the space that is left by the other two columns
1719
+ sColumnToUpdate = aResizedColumnNames.find((sColumn) => sColumn !== "mid");
1720
+ } else {
1721
+ sColumnToUpdate = sColumnEnlargedByDragging; // covers the known cases
1722
+ }
1723
+
1724
+ if (!isFullyVisible(sColumnToUpdate)) {
1725
+ // this is the case where the user is revealing a column by dragging,
1726
+ // but stopped dragging before the full size of the column was reached
1727
+ // => complete the user action => render that column in its required width
1728
+ // using its previously saved width
1729
+ return oOldWidths;
1730
+ }
1731
+
1732
+ return autosizeMid(merge(oOldWidths, {
1733
+ [sColumnToUpdate]: oNewWidths[sColumnToUpdate]
1734
+ }));
1735
+ };
1736
+
1737
+ FlexibleColumnLayout.prototype._offsetDraggedColumnSeparator = function (iOffset) {
1738
+ this._oDragInfo.separatorPosition.x += iOffset;
1739
+ this._$overlaySeparator.css(this._oDragInfo.separatorPosition.direction,
1740
+ this._oDragInfo.separatorPosition.x);
1741
+ };
1742
+
1743
+ FlexibleColumnLayout.prototype._toggleColumnVisibility = function (sColumn, bShow) {
1744
+ this._$columns[sColumn].toggleClass("sapFFCLColumnHidden", !bShow);
1745
+ this._$columns[sColumn].toggleClass("sapFFCLColumnActive", bShow);
1746
+ };
1747
+
1748
+ /**
1749
+ * Applies predefined contraints to the column widths.
1750
+ * Currently checks if the <code>FlexibleColumnLayout.COLUMN_MIN_WIDTH</code>
1751
+ * constraint is satisfied and corrects the width if not satisfied.
1752
+ * @param {Object<string,number>} oColumnWidths the column widths
1753
+ * @param {array} aVisibleColumns the names of the visible columns
1754
+ */
1755
+ FlexibleColumnLayout.prototype._normalizeColumnWidths = function (oColumnWidths, aVisibleColumns) {
1756
+ var iVisibleColumnsCount = aVisibleColumns.length;
1757
+ if (iVisibleColumnsCount < 2) { // fullscreen case
1758
+ return;
1759
+ }
1760
+
1761
+ var fnNormalizeColumnWidth = function (sColumn) {
1762
+ if (this._isColumnAllowedToHaveBelowMinWidth(sColumn)) {
1763
+ return;
1764
+ }
1765
+
1766
+ var iOffset = oColumnWidths[sColumn] - FlexibleColumnLayout.COLUMN_MIN_WIDTH,
1767
+ sSiblingColumn,
1768
+ iSiblingColumnWidth;
1769
+ if (iOffset < 0) { // column is smaller than min-width
1770
+ oColumnWidths[sColumn] = FlexibleColumnLayout.COLUMN_MIN_WIDTH;
1771
+ sSiblingColumn = getSiblingColumn(sColumn);
1772
+ iSiblingColumnWidth = oColumnWidths[sSiblingColumn];
1773
+ oColumnWidths[sSiblingColumn] = iSiblingColumnWidth - Math.abs(iOffset);
1774
+ }
1775
+ }.bind(this);
1776
+
1777
+ function getSiblingColumn(sColumn) {
1778
+ if (iVisibleColumnsCount === 2) {
1779
+ return aVisibleColumns.find(function(sNextColumn) {
1780
+ return sNextColumn !== sColumn;
1781
+ });
1782
+ }
1783
+ // all three columns are visible
1784
+ if (["begin", "end"].indexOf(sColumn) > -1) {
1785
+ return "mid";
1786
+ }
1787
+ // get sibling for 'mid'
1788
+ return (oColumnWidths.begin > oColumnWidths.end) ? "begin" : "end";
1789
+ }
1790
+
1791
+ aVisibleColumns.forEach(fnNormalizeColumnWidth);
1792
+ };
1793
+
1794
+ /**
1795
+ * Checks if the column is allowed to be displayed with a width smaller then
1796
+ * the minimal required by <code>FlexibleColumnLayout.COLUMN_MIN_WIDTH</code>.
1371
1797
  *
1372
- * @param {string} sColumn the column name
1373
- * @param {object} oOptions the resize options
1374
- * @private
1798
+ * This is needed only during interactive resize, when a column can temporarily
1799
+ * have a smaller width while the user drags and before the user releases the mouse.
1800
+ * @param {"begin"|"mid"|"end"} sColumn the column name
1801
+ * @returns {boolean} the flag
1375
1802
  */
1376
- FlexibleColumnLayout.prototype._afterColumnResize = function (sColumn, oOptions) {
1377
- var oColumn = this._$columns[sColumn],
1378
- bShouldConcealColumn = oOptions.shouldConcealColumn,
1379
- iNewWidth = oOptions.iNewWidth,
1380
- bShouldRestoreFocus = oOptions.shouldRestoreFocus;
1803
+ FlexibleColumnLayout.prototype._isColumnAllowedToHaveBelowMinWidth = function (sColumn) {
1804
+ if (!this._oDragInfo) {
1805
+ // outside interactive resize the min-width restriction should always be valid
1806
+ return false;
1807
+ }
1381
1808
 
1382
- oColumn.toggleClass(FlexibleColumnLayout.PINNED_COLUMN_CLASS_NAME, false);
1809
+ if (sColumn === this._oDragInfo.columnEnlargedByDragging) {
1810
+ // the user us revealing a hidden column by dragging
1811
+ // its ajacent separator => do not yet expand the column to min-width
1812
+ // untill the user stops dragging, to prevent undesired visual jump
1813
+ return true;
1814
+ }
1383
1815
 
1384
- if (bShouldConcealColumn) {
1385
- // The column does not show anything anymore, so we can remove the active class
1386
- oColumn.removeClass("sapFFCLColumnActive");
1816
+ // allow a column NOT adjacent to the dragged column-separator
1817
+ // to be indirectly shrinked (needed on tablet upon shifts
1818
+ // between ThreeColumnsMidExpanded and ThreeColumnsEndExpanded)
1819
+ return !this._isColumnAdjacentToDraggedSeparator(sColumn);
1820
+ };
1821
+
1822
+ FlexibleColumnLayout.prototype._convertColumnPercentWidthToPx = function (iPercentWidth, sLayout) {
1823
+ if (!iPercentWidth) {
1824
+ return 0;
1387
1825
  }
1388
1826
 
1389
- //BCP: 1980006195
1390
- oColumn.toggleClass("sapFFCLColumnHidden", iNewWidth === 0);
1827
+ // Calculate the width available for the columns
1828
+ var iAvailableWidth = this._getTotalColumnsWidth(sLayout);
1391
1829
 
1392
- this._cacheColumnWidth(sColumn, iNewWidth);
1393
- if (bShouldRestoreFocus) {
1394
- this._restoreFocusToColumn(sColumn);
1830
+ return Math.round(iAvailableWidth * iPercentWidth / 100);
1831
+ };
1832
+
1833
+ FlexibleColumnLayout.prototype._convertColumnPxWidthToPercent = function (vPx, sLayout) {
1834
+ if (!vPx) {
1835
+ return 0;
1395
1836
  }
1837
+
1838
+ var iAvailableWidth = this._getTotalColumnsWidth(sLayout),
1839
+ fnConvert = function(vPx) {
1840
+ return vPx / iAvailableWidth * 100;
1841
+ };
1842
+
1843
+ if (typeof vPx === "number") {
1844
+ return fnConvert(vPx);
1845
+ }
1846
+
1847
+ if (typeof vPx === "object") {
1848
+ var oColumnPercentWidths = Object.assign({}, vPx);
1849
+ Object.keys(oColumnPercentWidths).forEach(function(sColumnName) {
1850
+ var iColumnWidth = oColumnPercentWidths[sColumnName];
1851
+ if (iColumnWidth) {
1852
+ oColumnPercentWidths[sColumnName] = fnConvert(iColumnWidth);
1853
+ }
1854
+ }, this);
1855
+ return oColumnPercentWidths;
1856
+ }
1857
+ return null;
1858
+ };
1859
+
1860
+ FlexibleColumnLayout.prototype._isValidWidthDistributionForLayout = function(sNewWidthsDistribution, sLayout) {
1861
+ var aPercentWidths = sNewWidthsDistribution.split("/").map((x) => parseFloat(x)),
1862
+ iSum = aPercentWidths.reduce(function(i, sum) {
1863
+ return parseFloat(i) + sum;
1864
+ }),
1865
+ aPxWidths;
1866
+
1867
+ if (Math.round(iSum) !== 100) {
1868
+ return false;
1869
+ }
1870
+
1871
+ aPxWidths = aPercentWidths.map(function(iPercentWidth) {
1872
+ return this._convertColumnPercentWidthToPx(iPercentWidth, sLayout);
1873
+ }, this);
1874
+
1875
+ if (aPxWidths.some(function(iPxWidth) {
1876
+ return (iPxWidth > 0) && (iPxWidth < FlexibleColumnLayout.COLUMN_MIN_WIDTH);
1877
+ })) {
1878
+ return false;
1879
+ }
1880
+
1881
+ return this._verifyColumnWidthsMatchLayout({
1882
+ begin: aPxWidths[0],
1883
+ mid: aPxWidths[1],
1884
+ end: aPxWidths[2]
1885
+ }, sLayout);
1886
+ };
1887
+
1888
+ FlexibleColumnLayout.prototype._saveResizedColumWidths = function() {
1889
+ var sNewLayout = this._oDragInfo.layout,
1890
+ oColumnPercentWidths = this._convertColumnPxWidthToPercent(this._oDragInfo.columnWidths, sNewLayout),
1891
+ sNewWidthsDistribution = Object.values(oColumnPercentWidths).join("/");
1892
+
1893
+ if (this._isValidWidthDistributionForLayout(sNewWidthsDistribution, sNewLayout)) {
1894
+ this._getLocalStorage().put(sNewLayout, sNewWidthsDistribution);
1895
+ }
1896
+ };
1897
+
1898
+ FlexibleColumnLayout.prototype._getNextLayoutOnResizeByDrag = function (oColumnWidths,
1899
+ sPreviousLayout, sSeparator, bForwardDirection, bResizeEnd) {
1900
+ function dragged(oOptions) {
1901
+ return oOptions.from === sPreviousLayout &&
1902
+ oOptions.separator === sSeparator &&
1903
+ oOptions.forward === bForwardDirection;
1904
+ }
1905
+
1906
+ var iBeginWidth = oColumnWidths.begin,
1907
+ iBeginPercentWidth = Math.ceil(this._convertColumnPxWidthToPercent(iBeginWidth, sPreviousLayout)),
1908
+ iMaxColumnsCount = this.getMaxColumnsCount(),
1909
+ bTablet = iMaxColumnsCount === 2;
1910
+
1911
+ if (dragged({
1912
+ from: LT.TwoColumnsMidExpanded,
1913
+ separator: "begin",
1914
+ forward: true
1915
+ }) && (oColumnWidths.begin >= oColumnWidths.mid)) {
1916
+ return LT.TwoColumnsBeginExpanded;
1917
+ }
1918
+
1919
+ if (dragged({
1920
+ from: LT.TwoColumnsBeginExpanded,
1921
+ separator: "begin",
1922
+ forward: false
1923
+ }) && (oColumnWidths.begin < oColumnWidths.mid)) {
1924
+ return LT.TwoColumnsMidExpanded;
1925
+ }
1926
+
1927
+ if (dragged({
1928
+ from: LT.ThreeColumnsMidExpanded,
1929
+ separator: "begin",
1930
+ forward: true
1931
+ }) && iBeginPercentWidth >= 33) {
1932
+ return LT.ThreeColumnsMidExpandedEndHidden;
1933
+ }
1934
+
1935
+ if (dragged({
1936
+ from: LT.ThreeColumnsMidExpandedEndHidden,
1937
+ separator: "begin",
1938
+ forward: false
1939
+ }) && iBeginPercentWidth < 33) {
1940
+ return LT.ThreeColumnsMidExpanded;
1941
+ }
1942
+
1943
+ if (dragged({
1944
+ from: LT.ThreeColumnsMidExpandedEndHidden,
1945
+ separator: "end",
1946
+ forward: false
1947
+ }) && ((oColumnWidths.end >= FlexibleColumnLayout.COLUMN_MIN_WIDTH) || bResizeEnd)) {
1948
+ return LT.ThreeColumnsMidExpanded;
1949
+ }
1950
+
1951
+ if (dragged({
1952
+ from: LT.ThreeColumnsMidExpanded,
1953
+ separator: "end",
1954
+ forward: false
1955
+ }) && oColumnWidths.mid < oColumnWidths.end) {
1956
+ return LT.ThreeColumnsEndExpanded;
1957
+ }
1958
+
1959
+ if (dragged({
1960
+ from: LT.ThreeColumnsEndExpanded,
1961
+ separator: "end",
1962
+ forward: true
1963
+ }) && oColumnWidths.mid >= oColumnWidths.end) {
1964
+ return LT.ThreeColumnsMidExpanded;
1965
+ }
1966
+
1967
+ if (dragged({
1968
+ from: LT.ThreeColumnsMidExpandedEndHidden,
1969
+ separator: "begin",
1970
+ forward: true
1971
+ }) && oColumnWidths.begin >= oColumnWidths.mid) {
1972
+ return LT.ThreeColumnsBeginExpandedEndHidden;
1973
+ }
1974
+
1975
+ if (dragged({
1976
+ from: LT.ThreeColumnsBeginExpandedEndHidden,
1977
+ separator: "begin",
1978
+ forward: false
1979
+ }) && oColumnWidths.begin < oColumnWidths.mid) {
1980
+ return LT.ThreeColumnsMidExpandedEndHidden;
1981
+ }
1982
+
1983
+ if (dragged({
1984
+ from: LT.ThreeColumnsMidExpanded,
1985
+ separator: "begin",
1986
+ forward: true
1987
+ }) && bTablet && ((iBeginWidth >= FlexibleColumnLayout.COLUMN_MIN_WIDTH) || bResizeEnd)) {
1988
+ return LT.ThreeColumnsMidExpandedEndHidden;
1989
+ }
1990
+
1991
+ if (dragged({
1992
+ from: LT.TwoColumnsMidExpandedEndHidden,
1993
+ separator: "end",
1994
+ forward: false
1995
+ }) && bTablet && ((oColumnWidths.end >= FlexibleColumnLayout.COLUMN_MIN_WIDTH) || bResizeEnd)) {
1996
+ return LT.ThreeColumnsMidExpanded;
1997
+ }
1998
+
1999
+ return sPreviousLayout; // no layout change
2000
+ };
2001
+
2002
+ FlexibleColumnLayout.prototype._verifyColumnWidthsMatchLayout = function (oColumnWidths, sLayout) {
2003
+ var iMaxColumnsCount = this.getMaxColumnsCount(),
2004
+ iBeginWidth = oColumnWidths.begin,
2005
+ iBeginPercentWidth = Math.ceil(this._convertColumnPxWidthToPercent(iBeginWidth, sLayout)),
2006
+ oLayoutMatchers = {
2007
+ [LT.TwoColumnsBeginExpanded]: function() {
2008
+ return oColumnWidths.begin >= oColumnWidths.mid;
2009
+ },
2010
+ [LT.TwoColumnsMidExpanded]: function() {
2011
+ return oColumnWidths.mid > oColumnWidths.begin;
2012
+ },
2013
+ [LT.ThreeColumnsEndExpanded]: function() {
2014
+ return (oColumnWidths.end > oColumnWidths.mid) && (iBeginPercentWidth < 33);
2015
+ },
2016
+ [LT.ThreeColumnsBeginExpandedEndHidden]: function() {
2017
+ return (oColumnWidths.begin >= oColumnWidths.mid) && oColumnWidths.end === 0;
2018
+ },
2019
+ [LT.ThreeColumnsMidExpanded]: function() {
2020
+ return (oColumnWidths.mid >= oColumnWidths.end) &&
2021
+ (((iMaxColumnsCount === 3) && iBeginPercentWidth < 33) // desktop
2022
+ || ((iMaxColumnsCount === 2) && iBeginPercentWidth === 0)); // tablet
2023
+ },
2024
+ [LT.ThreeColumnsMidExpandedEndHidden]: function() {
2025
+ return (oColumnWidths.mid > oColumnWidths.begin) &&
2026
+ oColumnWidths.end === 0 &&
2027
+ ((iMaxColumnsCount === 3 && iBeginPercentWidth >= 33)
2028
+ || (iMaxColumnsCount === 2 && iBeginWidth >= FlexibleColumnLayout.COLUMN_MIN_WIDTH));
2029
+ }
2030
+ };
2031
+ return oLayoutMatchers[sLayout]();
1396
2032
  };
1397
2033
 
1398
2034
  /**
@@ -1447,68 +2083,112 @@ sap.ui.define([
1447
2083
  };
1448
2084
 
1449
2085
  /**
1450
- * Stores information from the last columns' resizing.
1451
- *
1452
- * @param iVisibleColumnsCount
1453
- * @param sLastVisibleColumn
1454
- * @private
2086
+ * Returns the name of the last visible column for the given layout
2087
+ * @param {sap.f.LayoutType} sLayout the layout
2088
+ * @returns {string} the column name
1455
2089
  */
1456
- FlexibleColumnLayout.prototype._storePreviousResizingInfo = function (iVisibleColumnsCount, sLastVisibleColumn) {
1457
- var oCurrentLayout = this.getLayout();
1458
-
1459
- this._iPreviousVisibleColumnsCount = iVisibleColumnsCount;
1460
- this._bWasFullScreen = oCurrentLayout === LT.MidColumnFullScreen || oCurrentLayout === LT.EndColumnFullScreen;
1461
- this._sPreviuosLastVisibleColumn = sLastVisibleColumn;
2090
+ FlexibleColumnLayout.prototype._getLastVisibleColumnForLayout = function (sLayout) {
2091
+ var aColumns = FlexibleColumnLayout.COLUMN_ORDER.slice(),
2092
+ iVisibleColumnsCount = this._getMaxColumnsCountForLayout(sLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT);
2093
+ if (iVisibleColumnsCount > 1) {
2094
+ return aColumns[iVisibleColumnsCount - 1];
2095
+ }
2096
+ if (sLayout === LT.OneColumn) {
2097
+ return "begin";
2098
+ }
2099
+ if (sLayout === LT.MidColumnFullScreen) {
2100
+ return "mid";
2101
+ }
2102
+ if (sLayout === LT.EndColumnFullScreen) {
2103
+ return "end";
2104
+ }
1462
2105
  };
1463
2106
 
1464
- FlexibleColumnLayout.prototype._isNavigatingBackward = function (sLastVisibleColumn) {
1465
- return this._bWasFullScreen ||
1466
- FlexibleColumnLayout.COLUMN_ORDER.indexOf(this._sPreviuosLastVisibleColumn) >
1467
- FlexibleColumnLayout.COLUMN_ORDER.indexOf(sLastVisibleColumn);
2107
+ FlexibleColumnLayout.prototype._isNavigatingBackward = function (sLayout, sPreviousLayout) {
2108
+ return ([LT.MidColumnFullScreen, LT.EndColumnFullScreen].indexOf(sPreviousLayout) > -1) ||
2109
+ FlexibleColumnLayout.COLUMN_ORDER.indexOf(this._getLastVisibleColumnForLayout(sPreviousLayout)) >
2110
+ FlexibleColumnLayout.COLUMN_ORDER.indexOf(this._getLastVisibleColumnForLayout(sLayout));
1468
2111
  };
1469
2112
 
1470
2113
  /**
1471
2114
  * Decides whether or not a given column should be revealed - another column slide out on top of it).
1472
2115
  *
1473
- * @param iVisibleColumnsCount
1474
- * @param bIsLastColumn
1475
- * @returns {boolean|*}
2116
+ * @param {"begin"|"mid"|"end"} sColumn the column name
2117
+ * @param {sap.f.LayoutType} sLayout the new layout
2118
+ * @param {sap.f.LayoutType} sPreviousLayout the previous layout
2119
+ * @returns {boolean} the flag
1476
2120
  * @private
1477
2121
  */
1478
- FlexibleColumnLayout.prototype._shouldRevealColumn = function (iVisibleColumnsCount, bIsLastColumn) {
1479
- return (iVisibleColumnsCount > this._iPreviousVisibleColumnsCount) && !this._bWasFullScreen && bIsLastColumn;
2122
+ FlexibleColumnLayout.prototype._shouldRevealColumn = function (sColumn, sLayout, sPreviousLayout) {
2123
+ var iVisibleColumnsCount = this._getMaxColumnsCountForLayout(sLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT),
2124
+ sLastVisibleColumn = this._getLastVisibleColumnForLayout(sLayout),
2125
+ bIsLastColumn = sColumn === sLastVisibleColumn,
2126
+ iPreviousVisibleColumnsCount = this._getMaxColumnsCountForLayout(sPreviousLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT),
2127
+ bWasFullScreen = (sPreviousLayout === LT.MidColumnFullScreen || sPreviousLayout === LT.EndColumnFullScreen);
2128
+
2129
+ return (iVisibleColumnsCount > iPreviousVisibleColumnsCount) &&
2130
+ !bWasFullScreen &&
2131
+ bIsLastColumn;
2132
+ };
2133
+
2134
+ FlexibleColumnLayout.prototype._isInteractivelyResizedColumn = function (sColumn) {
2135
+ return this._oDragInfo && this._isColumnAdjacentToDraggedSeparator(sColumn);
2136
+ };
2137
+
2138
+ FlexibleColumnLayout.prototype._isColumnAdjacentToDraggedSeparator = function (sColumn) {
2139
+ return this._oDragInfo &&
2140
+ this._oDragInfo.separator &&
2141
+ (this._$columns[sColumn][0] === this._oDragInfo.separator.previousElementSibling ||
2142
+ this._$columns[sColumn][0] === this._oDragInfo.separator.nextElementSibling);
1480
2143
  };
1481
2144
 
1482
2145
  /**
1483
2146
  * Decides whether or not a given column should be concealed - another column should slide in on top of it.
1484
2147
  *
1485
- * @param iVisibleColumnsCount
1486
- * @param sColumn
1487
- * @returns {boolean|*}
2148
+ * @param {"begin"|"mid"|"end"} sColumn the column name
2149
+ * @param {sap.f.LayoutType} sLayout the new layout
2150
+ * @param {sap.f.LayoutType} sPreviousLayout the previous layout
2151
+ * @returns {boolean} the flag
1488
2152
  * @private
1489
2153
  */
1490
- FlexibleColumnLayout.prototype._shouldConcealColumn = function(iVisibleColumnsCount, sColumn) {
1491
- return (iVisibleColumnsCount < this._iPreviousVisibleColumnsCount && sColumn === this._sPreviuosLastVisibleColumn
1492
- && !this._bWasFullScreen && this._getColumnSize(sColumn) === 0);
2154
+ FlexibleColumnLayout.prototype._shouldConcealColumn = function (sColumn, sLayout, sPreviousLayout) {
2155
+ var iVisibleColumnsCount = this._getMaxColumnsCountForLayout(sLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT),
2156
+ iPreviousVisibleColumnsCount = this._getMaxColumnsCountForLayout(sPreviousLayout, FlexibleColumnLayout.DESKTOP_BREAKPOINT),
2157
+ sPreviousLastVisibleColumn = this._getLastVisibleColumnForLayout(sPreviousLayout),
2158
+ bWasFullScreen = (sPreviousLayout === LT.MidColumnFullScreen || sPreviousLayout === LT.EndColumnFullScreen);
2159
+
2160
+ return (iVisibleColumnsCount < iPreviousVisibleColumnsCount
2161
+ && sColumn === sPreviousLastVisibleColumn
2162
+ && !bWasFullScreen
2163
+ && this._getColumnSizeForLayout(sColumn, sLayout) === 0);
1493
2164
  };
1494
2165
 
1495
2166
  /**
1496
2167
  * Checks if a column can be resized with an animation
1497
2168
  *
1498
- * @param {string} sColumn the column name
2169
+ * @param {"begin"|"mid"|"end"} sColumn the column name
1499
2170
  * @param {object} oOptions the column resize options
1500
- * @returns {boolean|*}
2171
+ * @param {number} oOptions.width the column width in px
2172
+ * @param {boolean} oOptions.hasAnimations if animations are enabled
2173
+ * @param {boolean} oOptions.hidden if the column has 0 width (as it is not required
2174
+ * to be shown by the current layout)
2175
+ * @param {boolean} oOptions.previousAnimationCompleted if the previous resize animation
2176
+ * fuly completed before staring the current one
2177
+ * @returns {boolean} the flag
1501
2178
  * @private
1502
2179
  */
1503
2180
  FlexibleColumnLayout.prototype._canResizeColumnWithAnimation = function(sColumn, oOptions) {
1504
- var oColumn, bFirstRendering,
1505
- iNewWidth = oOptions.iNewWidth,
2181
+ var oColumn,
2182
+ iNewWidth = oOptions.width,
1506
2183
  bHasAnimations = oOptions.hasAnimations,
1507
- bPinned = oOptions.pinned,
1508
2184
  bHidden = oOptions.hidden,
1509
2185
  bWasPartiallyResized = !oOptions.previousAnimationCompleted;
1510
2186
 
1511
- if (!bHasAnimations || bPinned || bHidden) {
2187
+ if (!bHasAnimations || bHidden) {
2188
+ return false;
2189
+ }
2190
+
2191
+ if (this._isInteractivelyResizedColumn(sColumn)) { // user is dragging to resize it
1512
2192
  return false;
1513
2193
  }
1514
2194
 
@@ -1517,9 +2197,8 @@ sap.ui.define([
1517
2197
  return oColumn.width() !== iNewWidth;
1518
2198
  }
1519
2199
 
1520
- bFirstRendering = !oColumn.get(0).style.width;
1521
- if (bFirstRendering) {
1522
- return false; // no animation on initial rendering of the column
2200
+ if (this._bNeverRendered || oOptions.autoSize) {
2201
+ return false; // initial rendering or autosized
1523
2202
  }
1524
2203
 
1525
2204
  return this._getColumnWidth(sColumn) !== iNewWidth;
@@ -1569,13 +2248,13 @@ sap.ui.define([
1569
2248
 
1570
2249
  /**
1571
2250
  * Gets the size (in %) of a column based on the current layout
1572
- * @param {string} sColumn - string: begin/mid/end
1573
- * @returns {*}
2251
+ * @param {"begin"|"mid"|"end"} sColumn - string: begin/mid/end
2252
+ * @param {sap.f.LayoutType} sLayout the layout
2253
+ * @returns {number} the size
1574
2254
  * @private
1575
2255
  */
1576
- FlexibleColumnLayout.prototype._getColumnSize = function (sColumn) {
1577
- var sLayout = this.getLayout(),
1578
- sColumnWidthDistribution = this._getColumnWidthDistributionForLayout(sLayout),
2256
+ FlexibleColumnLayout.prototype._getColumnSizeForLayout = function (sColumn, sLayout) {
2257
+ var sColumnWidthDistribution = this._getColumnWidthDistributionForLayout(sLayout),
1579
2258
  aSizes = sColumnWidthDistribution.split("/"),
1580
2259
  aMap = {
1581
2260
  begin: 0,
@@ -1584,7 +2263,7 @@ sap.ui.define([
1584
2263
  },
1585
2264
  sSize = aSizes[aMap[sColumn]];
1586
2265
 
1587
- return parseInt(sSize);
2266
+ return parseFloat(sSize);
1588
2267
  };
1589
2268
 
1590
2269
 
@@ -1622,9 +2301,9 @@ sap.ui.define([
1622
2301
 
1623
2302
  /**
1624
2303
  * Returns the maximum number of columns that can be displayed for given layout and control width.
1625
- * @param {string} sLayout the layout
1626
- * @param {int} iWidth
1627
- * @returns {number}
2304
+ * @param {sap.f.LayoutType} sLayout the layout
2305
+ * @param {int} iWidth the <code>sap.f.FlexibleColumnLayout</code> control width
2306
+ * @returns {number} the count
1628
2307
  * @private
1629
2308
  */
1630
2309
  FlexibleColumnLayout.prototype._getMaxColumnsCountForLayout = function (sLayout, iWidth) {
@@ -1672,7 +2351,6 @@ sap.ui.define([
1672
2351
 
1673
2352
  // Only update the arrows and fire the event if the maximum number of columns that can be shown has changed
1674
2353
  if (iMaxColumnsCount !== iOldMaxColumnsCount) {
1675
- this._hideShowArrows();
1676
2354
  this._fireStateChange(false, true);
1677
2355
  }
1678
2356
  };
@@ -1699,38 +2377,46 @@ sap.ui.define([
1699
2377
  };
1700
2378
 
1701
2379
  /**
1702
- * Called when the layout arrows were clicked.
1703
- * @param {string} sShiftDirection - left/right (direction of the arrow)
2380
+ * Obtains the names of the required column separators for the given layout.
2381
+ * @param {string} sLayout the layout
2382
+ * @returns {array} the names of the required separators
1704
2383
  * @private
1705
2384
  */
1706
- FlexibleColumnLayout.prototype._onArrowClick = function (sShiftDirection) {
1707
- var sCurrentLayout = this.getLayout(),
1708
- bIsLayoutValid = typeof FlexibleColumnLayout.SHIFT_TARGETS[sCurrentLayout] !== "undefined" && typeof FlexibleColumnLayout.SHIFT_TARGETS[sCurrentLayout][sShiftDirection] !== "undefined",
1709
- sNewLayout;
2385
+ FlexibleColumnLayout.prototype._getRequiredColumnSeparatorsForLayout = function (sLayout) {
2386
+ var oMap = {},
2387
+ aNeededSeparators = [],
2388
+ iMaxColumnsCount;
1710
2389
 
1711
- assert(bIsLayoutValid, "An invalid layout was used for determining arrow behavior");
1712
- sNewLayout = bIsLayoutValid ? FlexibleColumnLayout.SHIFT_TARGETS[sCurrentLayout][sShiftDirection] : LT.OneColumn;
2390
+ if (Device.system.phone) {
2391
+ return [];
2392
+ }
1713
2393
 
1714
- this.setLayout(sNewLayout);
2394
+ iMaxColumnsCount = this.getMaxColumnsCount();
1715
2395
 
1716
- // If the same arrow is hidden in the new layout, focus on the opposite one in it
1717
- if (FlexibleColumnLayout.ARROWS_NAMES[sNewLayout][sShiftDirection] !== FlexibleColumnLayout.ARROWS_NAMES[sCurrentLayout][sShiftDirection] && bIsLayoutValid) {
1718
- var sOppositeShiftDirection = sShiftDirection === 'right' ? 'left' : 'right';
2396
+ // Only show arrows if 2 or 3 columns can be displayed at a time
2397
+ if (iMaxColumnsCount > 1) {
2398
+ oMap[LT.TwoColumnsBeginExpanded] = ["begin"];
2399
+ oMap[LT.TwoColumnsMidExpanded] = ["begin"];
2400
+ oMap[LT.ThreeColumnsMidExpanded] = ["begin", "end"];
2401
+ oMap[LT.ThreeColumnsEndExpanded] = ["end"];
2402
+ oMap[LT.ThreeColumnsMidExpandedEndHidden] = ["begin", "end"];
2403
+ oMap[LT.ThreeColumnsBeginExpandedEndHidden] = ["begin"];
1719
2404
 
1720
- this._oColumnSeparatorArrows[FlexibleColumnLayout.ARROWS_NAMES[sNewLayout][sOppositeShiftDirection]].trigger("focus");
2405
+ if (typeof oMap[sLayout] === "object") {
2406
+ aNeededSeparators = oMap[sLayout];
2407
+ }
1721
2408
  }
1722
- this._fireStateChange(true, false);
2409
+
2410
+ return aNeededSeparators;
1723
2411
  };
1724
2412
 
1725
2413
  /**
1726
- * Updates the visibility of the layout arrows according to the current layout.
2414
+ * Updates the visibility of the column separators according to the given layout.
2415
+ * @param {string} [sLayout] the layout. If not provided, the current layout is taken
1727
2416
  * @private
1728
2417
  */
1729
- FlexibleColumnLayout.prototype._hideShowArrows = function () {
1730
- var sLayout = this.getLayout(),
1731
- oMap = {},
1732
- aNeededArrows = [],
1733
- iMaxColumnsCount,
2418
+ FlexibleColumnLayout.prototype._hideShowColumnSeparators = function (sLayout) {
2419
+ var aNeededSeparators = [],
1734
2420
  bIsNavContainersContentRendered;
1735
2421
 
1736
2422
  // Stop here if the control isn't rendered yet or in phone mode, where arrows aren't necessary
@@ -1738,42 +2424,29 @@ sap.ui.define([
1738
2424
  return;
1739
2425
  }
1740
2426
 
1741
- iMaxColumnsCount = this.getMaxColumnsCount();
1742
-
1743
- // Only show arrows if 2 or 3 columns can be displayed at a time
1744
- if (iMaxColumnsCount > 1) {
1745
- oMap[LT.TwoColumnsBeginExpanded] = ["beginBack"];
1746
- oMap[LT.TwoColumnsMidExpanded] = ["midForward"];
1747
- oMap[LT.ThreeColumnsMidExpanded] = ["midForward", "midBack"];
1748
- oMap[LT.ThreeColumnsEndExpanded] = ["endForward"];
1749
- oMap[LT.ThreeColumnsMidExpandedEndHidden] = ["midForward", "midBack"];
1750
- oMap[LT.ThreeColumnsBeginExpandedEndHidden] = ["beginBack"];
2427
+ sLayout || (sLayout = this.getLayout());
1751
2428
 
1752
- if (typeof oMap[sLayout] === "object") {
1753
- aNeededArrows = oMap[sLayout];
1754
- }
1755
- }
2429
+ aNeededSeparators = this._getRequiredColumnSeparatorsForLayout(sLayout);
1756
2430
 
1757
2431
  bIsNavContainersContentRendered = this._hasAnyColumnPagesRendered();
1758
2432
 
1759
- Object.keys(this._oColumnSeparatorArrows).forEach(function (key) {
1760
- this._toggleButton(key, aNeededArrows.indexOf(key) !== -1, bIsNavContainersContentRendered);
2433
+ Object.keys(this._oColumnSeparators).forEach(function (key) {
2434
+ this._toggleSeparator(key, aNeededSeparators.indexOf(key) !== -1, bIsNavContainersContentRendered);
1761
2435
  }, this);
1762
2436
  };
1763
2437
 
1764
2438
  /**
1765
- * Changes the visibility of a navigation button.
1766
- * @param {string} sButton
2439
+ * Changes the visibility of a separator.
2440
+ * @param {string} sKey, the separator name
1767
2441
  * @param {boolean} bShow
2442
+ * @param {boolean} bReveal
1768
2443
  * @private
1769
2444
  */
1770
- FlexibleColumnLayout.prototype._toggleButton = function (sButton, bShow, bReveal) {
1771
-
1772
- this._oColumnSeparatorArrows[sButton].toggle(bShow && bReveal);
1773
- this._oColumnSeparatorArrows[sButton].data("visible", bShow);
2445
+ FlexibleColumnLayout.prototype._toggleSeparator = function (sKey, bShow, bReveal) {
2446
+ this._oColumnSeparators[sKey].toggle(bShow && bReveal);
2447
+ this._oColumnSeparators[sKey].data("visible", bShow);
1774
2448
  };
1775
2449
 
1776
-
1777
2450
  FlexibleColumnLayout.prototype._fireStateChange = function (bIsNavigationArrow, bIsResize) {
1778
2451
 
1779
2452
  // The event should not be fired if the control has zero width as all relevant layout calculations are size-based
@@ -2179,12 +2852,14 @@ sap.ui.define([
2179
2852
  * Returns a string, representing the relative percentage sizes of the columns for the given layout in the format "begin/mid/end" (f.e. "33/67/0")
2180
2853
  * @param {string} sLayout - the layout
2181
2854
  * @param {boolean} bAsArray - return an array in the format [33, 67, 0] instead of a string "33/67/0"
2855
+ * @param {number} [iMaxColumnsCount] the maximun number of columns. If not provided, the result of
2856
+ * <code>getMaxColumnsCount</code> will be taken
2182
2857
  * @returns {string|array}
2183
2858
  * @private
2184
2859
  * @ui5-restricted sap.f.FlexibleColumnLayoutSemanticHelper
2185
2860
  */
2186
2861
  FlexibleColumnLayout.prototype._getColumnWidthDistributionForLayout = function (sLayout, bAsArray, iMaxColumnsCount) {
2187
- var oMap = {},
2862
+ var sColumnWidthDistribution = this._getLocalStorage(iMaxColumnsCount).get(sLayout),
2188
2863
  vResult;
2189
2864
 
2190
2865
  iMaxColumnsCount || (iMaxColumnsCount = this.getMaxColumnsCount());
@@ -2193,44 +2868,74 @@ sap.ui.define([
2193
2868
 
2194
2869
  vResult = "0/0/0";
2195
2870
 
2871
+ } else if (iMaxColumnsCount > 1
2872
+ && sColumnWidthDistribution) {
2873
+ vResult = sColumnWidthDistribution;
2196
2874
  } else {
2875
+ vResult = this._getDefaultColumnWidthDistributionForLayout(sLayout, iMaxColumnsCount);
2876
+ }
2877
+
2878
+ if (bAsArray) {
2879
+ vResult = vResult.split("/").map(function (sColumnWidth) {
2880
+ return parseInt(sColumnWidth);
2881
+ });
2882
+ }
2197
2883
 
2198
- // Layouts with the same distribution for all cases
2199
- oMap[LT.OneColumn] = "100/0/0";
2200
- oMap[LT.MidColumnFullScreen] = "0/100/0";
2201
- oMap[LT.EndColumnFullScreen] = "0/0/100";
2884
+ return vResult;
2885
+ };
2202
2886
 
2203
- if (iMaxColumnsCount === 1) {
2887
+ /**
2888
+ * Returns a string, representing the default relative percentage sizes of the columns
2889
+ * for the given layout
2890
+ * @param {sap.f.LayoutType} sLayout the layout
2891
+ * @param {number} iMaxColumnsCount the maximun available number of columns
2892
+ * @returns {string} a representation in the format "begin/mid/end" (f.e. "33/67/0")
2893
+ */
2894
+ FlexibleColumnLayout.prototype._getDefaultColumnWidthDistributionForLayout = function (sLayout, iMaxColumnsCount) {
2895
+ var oMap = {};
2896
+ // Layouts with the same distribution for all cases
2897
+ oMap[LT.OneColumn] = "100/0/0";
2898
+ oMap[LT.MidColumnFullScreen] = "0/100/0";
2899
+ oMap[LT.EndColumnFullScreen] = "0/0/100";
2204
2900
 
2205
- // On 1 column, all have fullscreen mapping
2206
- oMap[LT.TwoColumnsBeginExpanded] = "0/100/0";
2207
- oMap[LT.TwoColumnsMidExpanded] = "0/100/0";
2208
- oMap[LT.ThreeColumnsMidExpanded] = "0/0/100";
2209
- oMap[LT.ThreeColumnsEndExpanded] = "0/0/100";
2210
- oMap[LT.ThreeColumnsMidExpandedEndHidden] = "0/0/100";
2211
- oMap[LT.ThreeColumnsBeginExpandedEndHidden] = "0/0/100";
2901
+ if (iMaxColumnsCount === 1) {
2212
2902
 
2213
- } else {
2903
+ // On 1 column, all have fullscreen mapping
2904
+ oMap[LT.TwoColumnsBeginExpanded] = "0/100/0";
2905
+ oMap[LT.TwoColumnsMidExpanded] = "0/100/0";
2906
+ oMap[LT.ThreeColumnsMidExpanded] = "0/0/100";
2907
+ oMap[LT.ThreeColumnsEndExpanded] = "0/0/100";
2908
+ oMap[LT.ThreeColumnsMidExpandedEndHidden] = "0/0/100";
2909
+ oMap[LT.ThreeColumnsBeginExpandedEndHidden] = "0/0/100";
2214
2910
 
2215
- // On 2 and 3 columns, the only difference is in the modes where all 3 columns are visible
2216
- oMap[LT.TwoColumnsBeginExpanded] = "67/33/0";
2217
- oMap[LT.TwoColumnsMidExpanded] = "33/67/0";
2218
- oMap[LT.ThreeColumnsMidExpanded] = iMaxColumnsCount === 2 ? "0/67/33" : "25/50/25";
2219
- oMap[LT.ThreeColumnsEndExpanded] = iMaxColumnsCount === 2 ? "0/33/67" : "25/25/50";
2220
- oMap[LT.ThreeColumnsMidExpandedEndHidden] = "33/67/0";
2221
- oMap[LT.ThreeColumnsBeginExpandedEndHidden] = "67/33/0";
2222
- }
2911
+ } else {
2223
2912
 
2224
- vResult = oMap[sLayout];
2913
+ // On 2 and 3 columns, the only difference is in the modes where all 3 columns are visible
2914
+ oMap[LT.TwoColumnsBeginExpanded] = "67/33/0";
2915
+ oMap[LT.TwoColumnsMidExpanded] = "33/67/0";
2916
+ oMap[LT.ThreeColumnsMidExpanded] = iMaxColumnsCount === 2 ? "0/67/33" : "25/50/25";
2917
+ oMap[LT.ThreeColumnsEndExpanded] = iMaxColumnsCount === 2 ? "0/33/67" : "25/25/50";
2918
+ oMap[LT.ThreeColumnsMidExpandedEndHidden] = "33/67/0";
2919
+ oMap[LT.ThreeColumnsBeginExpandedEndHidden] = "67/33/0";
2225
2920
  }
2226
2921
 
2227
- if (bAsArray) {
2228
- vResult = vResult.split("/").map(function (sColumnWidth) {
2229
- return parseInt(sColumnWidth);
2922
+ return oMap[sLayout];
2923
+ };
2924
+
2925
+ FlexibleColumnLayout.prototype._attachAfterColumnResizedOnce = function (sColumn, fnSuccessCallback, fnErrorCallback) {
2926
+ this._oAnimationEndListener.waitForColumnResizeEnd(this._$columns[sColumn])
2927
+ .then(fnSuccessCallback)
2928
+ .catch(function() {
2929
+ fnErrorCallback && fnErrorCallback();
2230
2930
  });
2231
- }
2931
+ };
2232
2932
 
2233
- return vResult;
2933
+ FlexibleColumnLayout.prototype._attachAfterAllColumnsResizedOnce = function (fnSuccessCallback, fnErrorCallback) {
2934
+ this._oAnimationEndListener.waitForAllColumnsResizeEnd()
2935
+ .then(fnSuccessCallback)
2936
+ .catch(function() {
2937
+ fnErrorCallback && fnErrorCallback();
2938
+ });
2234
2939
  };
2235
2940
 
2236
2941
 
@@ -2242,29 +2947,10 @@ sap.ui.define([
2242
2947
  // The width above which (inclusive) we are in tablet mode
2243
2948
  FlexibleColumnLayout.TABLET_BREAKPOINT = 960;
2244
2949
 
2245
- // Arrows names for each shift position in a given layout
2246
- FlexibleColumnLayout.ARROWS_NAMES = {
2247
- TwoColumnsBeginExpanded: {
2248
- "left": "beginBack"
2249
- },
2250
- TwoColumnsMidExpanded: {
2251
- "right": "midForward"
2252
- },
2253
- ThreeColumnsMidExpanded: {
2254
- "left": "midBack",
2255
- "right": "midForward"
2256
- },
2257
- ThreeColumnsEndExpanded: {
2258
- "right": "endForward"
2259
- },
2260
- ThreeColumnsMidExpandedEndHidden: {
2261
- "left": "midBack",
2262
- "right": "midForward"
2263
- },
2264
- ThreeColumnsBeginExpandedEndHidden: {
2265
- "left": "beginBack"
2266
- }
2267
- };
2950
+ FlexibleColumnLayout.COLUMN_MIN_WIDTH = 312; // px, obtained as 25% of (DESKTOP_BREAKPOINT - 2 * COLUMN_SEPARATOR_WIDTH)
2951
+
2952
+ FlexibleColumnLayout.STORAGE_PREFIX_TABLET = "sap-f-fcl-tablet-column-width-distributions";
2953
+ FlexibleColumnLayout.STORAGE_PREFIX_DESKTOP = "sap-f-fcl-desktop-column-width-distributions";
2268
2954
 
2269
2955
  /**
2270
2956
  * Retrieves the resource bundle for the <code>sap.f</code> library.
@@ -2276,29 +2962,6 @@ sap.ui.define([
2276
2962
  return sap.ui.getCore().getLibraryResourceBundle("sap.f");
2277
2963
  };
2278
2964
 
2279
- // Resulting layouts, after shifting in a given direction from a specific layout
2280
- FlexibleColumnLayout.SHIFT_TARGETS = {
2281
- TwoColumnsBeginExpanded: {
2282
- "left": LT.TwoColumnsMidExpanded
2283
- },
2284
- TwoColumnsMidExpanded: {
2285
- "right": LT.TwoColumnsBeginExpanded
2286
- },
2287
- ThreeColumnsMidExpanded: {
2288
- "left": LT.ThreeColumnsEndExpanded,
2289
- "right": LT.ThreeColumnsMidExpandedEndHidden
2290
- },
2291
- ThreeColumnsEndExpanded: {
2292
- "right": LT.ThreeColumnsMidExpanded
2293
- },
2294
- ThreeColumnsMidExpandedEndHidden: {
2295
- "left": LT.ThreeColumnsMidExpanded,
2296
- "right": LT.ThreeColumnsBeginExpandedEndHidden
2297
- },
2298
- ThreeColumnsBeginExpandedEndHidden: {
2299
- "left": LT.ThreeColumnsMidExpandedEndHidden
2300
- }
2301
- };
2302
2965
 
2303
2966
  /**
2304
2967
  * Shows the placeholder on the corresponding column for the provided aggregation name.
@@ -2310,7 +2973,9 @@ sap.ui.define([
2310
2973
  * @since 1.91
2311
2974
  */
2312
2975
  FlexibleColumnLayout.prototype.showPlaceholder = function(mSettings) {
2313
- if (!Configuration.getPlaceholder()) {
2976
+ var Placeholder = sap.ui.require("sap/ui/core/Placeholder");
2977
+
2978
+ if (!Placeholder || !Placeholder.isEnabled()) {
2314
2979
  return;
2315
2980
  }
2316
2981
 
@@ -2395,6 +3060,20 @@ sap.ui.define([
2395
3060
  }
2396
3061
  };
2397
3062
 
3063
+ /**
3064
+ * Retrieves the etry at the given index
3065
+ * @param {*} iIndex ihe index
3066
+ * @param {*} bRecentFirst if the history should be ordered from the most recent to the most old
3067
+ * @returns {string} the entry at the given index
3068
+ */
3069
+ LayoutHistory.prototype.getEntry = function (iIndex, bRecentFirst) {
3070
+ var aHistory = this._aLayoutHistory;
3071
+ if (bRecentFirst) {
3072
+ aHistory = this._aLayoutHistory.toReversed();
3073
+ }
3074
+ return aHistory[iIndex];
3075
+ };
3076
+
2398
3077
  /**
2399
3078
  * Searches the history for the most recent layout that matches any of the aLayouts entries
2400
3079
  * @param aLayouts - a list of layouts
@@ -2549,6 +3228,43 @@ sap.ui.define([
2549
3228
  }
2550
3229
  };
2551
3230
 
3231
+ //utils
3232
+ function convertPxToCSSSizeString(iPxSize, iTotalPzSize, bIsInsetColumn) {
3233
+ var iContentSize;
3234
+ if (iPxSize === iTotalPzSize) {
3235
+ return "100%";
3236
+ }
3237
+ iContentSize = bIsInsetColumn ? (iPxSize - FlexibleColumnLayout.COLUMN_SEPARATOR_WIDTH) : iPxSize;
3238
+
3239
+ return iContentSize + "px";
3240
+ }
3241
+
3242
+ function getSeparatorName(oColumnSeparator) {
3243
+ return oColumnSeparator.classList.contains("sapFFCLColumnSeparatorBegin") ?
3244
+ "begin" : "end";
3245
+ }
3246
+
3247
+ function getInteractivelyResizedColumns(oColumnSeparator, sLayout, iMaxColumnsCount) {
3248
+ var bIsBeginSeparator = oColumnSeparator.classList.contains("sapFFCLColumnSeparatorBegin");
3249
+
3250
+ if (iMaxColumnsCount === 2 && sLayout == LT.ThreeColumnsMidExpandedEndHidden) {
3251
+ return (bIsBeginSeparator) ? ["begin", "mid"] : ["begin", "end"];
3252
+ }
3253
+
3254
+ if (iMaxColumnsCount === 2 && sLayout == LT.ThreeColumnsMidExpanded) {
3255
+ return (bIsBeginSeparator) ? ["begin", "end"] : ["mid", "end"];
3256
+ }
3257
+ return (bIsBeginSeparator) ? ["begin", "mid"] : ["mid", "end"];
3258
+ }
3259
+
3260
+ function getCursorPositionX (oEvent) {
3261
+ var oConfig = oEvent;
3262
+ if (oEvent.changedTouches && oEvent.changedTouches[0]) {
3263
+ oConfig = oConfig.changedTouches[0];
3264
+ }
3265
+ return oConfig.pageX;
3266
+ }
3267
+
2552
3268
  return FlexibleColumnLayout;
2553
3269
 
2554
3270
  });