/*! * UI development toolkit for HTML5 (OpenUI5) * (c) Copyright 2009-2018 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ "./library", "./FlexibleColumnLayout", "sap/base/assert" ], function (library, FlexibleColumnLayout, assert) { "use strict"; // shortcut for sap.f.LayoutType var LT = library.LayoutType; /** * Constructor for an sap.f.FlexibleColumnLayoutSemanticHelper. * * @class * Helper class, facilitating the implementation of the recommended UX design of a sap.f.FlexibleColumnLayout-based app. * * Note: Using this class is not mandatory in order to build an app with sap.f.FlexibleColumnLayout, but exists for convenience only. * * * * Sample usage of the class: * *
	 * 
	 *  var helper = sap.f.FlexibleColumnLayoutSemanticHelper.getInstanceFor(myFlexibleColumnLayout);
	 *  helper.getCurrentUIState();
	 *  helper.getNextUIState(2);
	 *  helper.getNextUIState(0);
	 * 
	 * 
* * Calling getCurrentUIState() will return information which action buttons (Close, FullScreen, ExitFullScreen) * must be currently shown in which column, according to UX guidelines, as well as to what layout clicking them should lead. * * Calling getNextUIState(2) will return information about the expected layout and action buttons if the * application should display three views (master-detail-detail), based on the current state. * * Similarly, calling getNextUIState(0) will return information about the expected layout and action buttons * if the application should display the initial view only (master), based on the current state. * * For more information, see {@link sap.f.FlexibleColumnLayoutSemanticHelper#getCurrentUIState} and {@link sap.f.FlexibleColumnLayoutSemanticHelper#getNextUIState} * * @version 1.60.23 * @param {sap.f.FlexibleColumnLayout} oFlexibleColumnLayout * The sap.f.FlexibleColumnLayout object whose state will be manipulated. * * @param {object} oSettings Determines the rules that will be used by the helper. * * @param {sap.f.LayoutType} oSettings.defaultTwoColumnLayoutType * Determines what two-column layout type will be suggested by default: * sap.f.LayoutType.TwoColumnsBeginExpanded (default) or sap.f.LayoutType.TwoColumnsMidExpanded. * * @param {sap.f.LayoutType} oSettings.defaultThreeColumnLayoutType * Determines what three-column layout type will be suggested by default: * sap.f.LayoutType.ThreeColumnsMidExpanded (default) or sap.f.LayoutType.ThreeColumnsEndExpanded. * * @param {int} oSettings.maxColumnsCount * Determines the maximum number of columns that will be displayed side by side. * * * * @param {int} oSettings.initialColumnsCount * Determines whether a single-column or a 2-column layout will be suggested * for logical level 0. * * * * @param {string} oSettings.mode * Deprecated as of version 1.50, use maxColumnsCount param * instead. * * Determines the suggested layout types: Normal (3-column layouts), * MasterDetail (2-column layouts for the first two pages, all other * pages will open in fullscreen), and SingleColumn (one page at a * time only). * * @public * @since 1.46.0 * @alias sap.f.FlexibleColumnLayoutSemanticHelper */ var FlexibleColumnLayoutSemanticHelper = function (oFlexibleColumnLayout, oSettings) { var oModeToMaxColumnsCountMapping = { Normal: 3, MasterDetail: 2, SingleColumn: 1 }, iInitial, iMax; oSettings || (oSettings = {}); this._oFCL = oFlexibleColumnLayout; // Layout types this._defaultLayoutType = LT.OneColumn; this._defaultTwoColumnLayoutType = [LT.TwoColumnsBeginExpanded, LT.TwoColumnsMidExpanded].indexOf(oSettings.defaultTwoColumnLayoutType) !== -1 ? oSettings.defaultTwoColumnLayoutType : LT.TwoColumnsBeginExpanded; this._defaultThreeColumnLayoutType = [LT.ThreeColumnsMidExpanded, LT.ThreeColumnsEndExpanded].indexOf(oSettings.defaultThreeColumnLayoutType) !== -1 ? oSettings.defaultThreeColumnLayoutType : LT.ThreeColumnsMidExpanded; // Maximum number of columns and mode (deprecated) if (["Normal", "MasterDetail", "SingleColumn"].indexOf(oSettings.mode) !== -1 && !oSettings.maxColumnsCount) { iMax = oModeToMaxColumnsCountMapping[oSettings.mode]; } else { iMax = oSettings.maxColumnsCount ? parseInt(oSettings.maxColumnsCount, 10) : 3; if (iMax < 1 || iMax > 3) { iMax = 3; } } this._maxColumnsCount = iMax; // Initial number of columns (1 by default, can be set to 2 for MasterDetail or Normal modes only) iInitial = oSettings.initialColumnsCount ? parseInt(oSettings.initialColumnsCount, 10) : 1; if (iInitial < 1 || iInitial > 2 || this._maxColumnsCount === 1) { iInitial = 1; } this._initialColumnsCount = iInitial; }; /** * Instances of the class per flexible column layout object. * * @type {{}} * @private */ FlexibleColumnLayoutSemanticHelper._oInstances = {}; /** * Returns an instance of the sap.f.FlexibleColumnLayoutSemanticHelper class for a given sap.f.FlexibleColumnLayout object. * * @param {sap.f.FlexibleColumnLayout} oFlexibleColumnLayout The sap.f.FlexibleColumnLayout object to get a semantic helper instance for * @param {object} [oSettings] An optional settings object to be used when creating the instance. * Note: will be considered only for the first getInstanceFor call for the given sap.f.FlexibleColumnLayout object. * * @public * @static * @returns {sap.f.FlexibleColumnLayoutSemanticHelper} The sap.f.FlexibleColumnLayoutSemanticHelper instance */ FlexibleColumnLayoutSemanticHelper.getInstanceFor = function (oFlexibleColumnLayout, oSettings) { assert(oFlexibleColumnLayout instanceof FlexibleColumnLayout, "Passed control is not FlexibleColumnLayout"); var sId = oFlexibleColumnLayout.getId(); if (typeof FlexibleColumnLayoutSemanticHelper._oInstances[sId] === "undefined") { FlexibleColumnLayoutSemanticHelper._oInstances[sId] = new FlexibleColumnLayoutSemanticHelper(oFlexibleColumnLayout, oSettings); var oDelegate = { onDestroy: function() { delete FlexibleColumnLayoutSemanticHelper._oInstances[sId]; } }; oFlexibleColumnLayout.addEventDelegate(oDelegate); } return FlexibleColumnLayoutSemanticHelper._oInstances[sId]; }; /** * Returns an object, describing the current state of the control and the expected action buttons for each column. * * * * Example value: * *
	 *  
	 *  {
	 *	   "layout":"ThreeColumnsMidExpanded",
	 *	   "maxColumnsCount":3,
	 *	   "columnsSizes":{
	 *		  "beginColumn":25,
	 *		  "midColumn":50,
	 *		  "endColumn":25
	 *	   },
	 *	   "columnsVisibility":{
	 *		  "beginColumn":true,
	 *		  "midColumn":true,
	 *		  "endColumn":true
	 *	   },
	 *	   "isFullScreen":false,
	 *	   "isLogicallyFullScreen":false,
	 *	   "actionButtonsInfo":{
	 *		  "midColumn":{
	 *			 "fullScreen":null,
	 *			 "exitFullScreen":null,
	 *			 "closeColumn":null
	 *		  },
	 *		  "endColumn":{
	 *			 "fullScreen":"EndColumnFullScreen",
	 *			 "exitFullScreen":null,
	 *			 "closeColumn":"TwoColumnsBeginExpanded"
	 *		  }
	 *	   }
	 *	}
	 *  
	 *  
* @public * @returns {Object} The object describing the current UI state */ FlexibleColumnLayoutSemanticHelper.prototype.getCurrentUIState = function () { var sCurrentLayout = this._oFCL.getLayout(); return this._getUIStateForLayout(sCurrentLayout); }; /** * Returns an object, describing the state that the control will have after navigating to a different view level. * * About the format of return value, see: {@link sap.f.FlexibleColumnLayoutSemanticHelper#getCurrentUIState} * * @param {int} iNextLevel - the view level that should be represented. 0 means initial (master only), 1 - master-detail, * 2 - master-detail-detail, 3 and above - subsequent views * * @public * @returns {Object} The object describing the next UI state */ FlexibleColumnLayoutSemanticHelper.prototype.getNextUIState = function (iNextLevel) { var sCurrentLayout = this._oFCL.getLayout(), iInitial = this._initialColumnsCount, sNextLayout; // Level 0 - the first page if (iNextLevel === 0) { // From any layout, going to level 0 is always showing the begin column only, unless initialColumnsCount=2. Then a 2-column layout is suggested even for level 0 // However, a 2-column layout should only be suggested if there is enough space for 2 columns, hence the additional check if (iInitial === 2 && this._canShowTwoColumns()) { sNextLayout = this._defaultTwoColumnLayoutType; } else { sNextLayout = LT.OneColumn; } } // Level 1 - the second page if (iNextLevel === 1) { if (this._maxColumnsCount === 1) { sNextLayout = LT.MidColumnFullScreen; } else { if ([LT.TwoColumnsBeginExpanded, LT.TwoColumnsMidExpanded].indexOf(sCurrentLayout) !== -1) { // From a 2-column layout - preserve sNextLayout = sCurrentLayout; } else if ([LT.MidColumnFullScreen, LT.EndColumnFullScreen].indexOf(sCurrentLayout) !== -1) { // From any fullscreen layout - should go to mid fullscreen sNextLayout = LT.MidColumnFullScreen; } else { // From 1-column layout or any 3-column layout - default 2-column layout sNextLayout = this._defaultTwoColumnLayoutType; } } } // Level 2 - the third page if (iNextLevel === 2) { if (this._maxColumnsCount < 3) { // Clicking the mid column when in 2-column layout should open the third column in fullscreen mode sNextLayout = LT.EndColumnFullScreen; } else { if ([LT.ThreeColumnsMidExpandedEndHidden, LT.ThreeColumnsBeginExpandedEndHidden].indexOf(sCurrentLayout) !== -1) { // From a 3-column layout where end column is hidden, should reveal the end column again sNextLayout = this._defaultThreeColumnLayoutType; } else if ([LT.ThreeColumnsMidExpanded, LT.ThreeColumnsEndExpanded].indexOf(sCurrentLayout) !== -1) { // From a 3-column layout where end column is visible, should preserve the current layout sNextLayout = sCurrentLayout; } else if ([LT.MidColumnFullScreen, LT.EndColumnFullScreen].indexOf(sCurrentLayout) !== -1) { // From any fullscreen layout, should go to end fullscreen sNextLayout = LT.EndColumnFullScreen; } else { // From 1-column layout or any 2-column layout - should go to default 3-column layout sNextLayout = this._defaultThreeColumnLayoutType; } } } // Level 3 and above - further pages if (iNextLevel > 2) { // Any level above 2 is unconditionally shown in end fullscreen sNextLayout = LT.EndColumnFullScreen; } return this._getUIStateForLayout(sNextLayout); }; /** * Returns information about the current layout * @param {sap.f.LayoutType} sLayout * @returns {{layout: string, maxColumnsCount: number, columnsSizes: {beginColumn, midColumn, endColumn}, columnsVisibility: {beginColumn, midColumn, endColumn}, isFullScreen, isLogicallyFullScreen, actionButtonsInfo: {midColumn, endColumn}}} * @private */ FlexibleColumnLayoutSemanticHelper.prototype._getUIStateForLayout = function (sLayout) { var aSizes = this._oFCL._getColumnWidthDistributionForLayout(sLayout, true), sColumnWidthDistribution = aSizes.join("/"), iMaxColumnsCount = this._oFCL.getMaxColumnsCount(); return { layout: sLayout, maxColumnsCount: iMaxColumnsCount, columnsSizes: this._getColumnsSizes(aSizes), columnsVisibility: this._getColumnsVisibility(aSizes), isFullScreen: this._getIsFullScreen(aSizes), isLogicallyFullScreen: this._getIsLogicallyFullScreen(sLayout), actionButtonsInfo: this._getActionButtonsInfo(sColumnWidthDistribution, iMaxColumnsCount) }; }; FlexibleColumnLayoutSemanticHelper.prototype._getColumnsSizes = function (aSizes) { return { beginColumn: aSizes[0], midColumn: aSizes[1], endColumn: aSizes[2] }; }; FlexibleColumnLayoutSemanticHelper.prototype._getColumnsVisibility = function (aSizes) { return { beginColumn: aSizes[0] !== 0, midColumn: aSizes[1] !== 0, endColumn: aSizes[2] !== 0 }; }; FlexibleColumnLayoutSemanticHelper.prototype._getIsFullScreen = function (aSizes) { return aSizes.indexOf(100) !== -1; }; FlexibleColumnLayoutSemanticHelper.prototype._getIsLogicallyFullScreen = function (sLayout) { return [LT.OneColumn, LT.MidColumnFullScreen, LT.EndColumnFullScreen].indexOf(sLayout) !== -1; }; FlexibleColumnLayoutSemanticHelper.prototype._getActionButtonsInfo = function (sColumnWidthDistribution, iMaxColumnsCount) { var oMidColumn = { fullScreen: null, exitFullScreen: null, closeColumn: null }, oEndColumn = { fullScreen: null, exitFullScreen: null, closeColumn: null }, aEligibleLayouts, sExitFullScreen; if (this._maxColumnsCount === 1) { return { midColumn: oMidColumn, endColumn: oEndColumn }; } if (iMaxColumnsCount === 1) { oMidColumn.closeColumn = this._defaultLayoutType; oEndColumn.closeColumn = this._defaultTwoColumnLayoutType; } else { if (sColumnWidthDistribution === "67/33/0" || sColumnWidthDistribution === "33/67/0") { oMidColumn.fullScreen = LT.MidColumnFullScreen; oMidColumn.closeColumn = this._defaultLayoutType; } if (sColumnWidthDistribution === "25/50/25" || sColumnWidthDistribution === "25/25/50" || sColumnWidthDistribution === "0/67/33" || sColumnWidthDistribution === "0/33/67") { oEndColumn.fullScreen = LT.EndColumnFullScreen; oEndColumn.closeColumn = this._defaultTwoColumnLayoutType; } if (sColumnWidthDistribution === "0/100/0") { aEligibleLayouts = [LT.TwoColumnsBeginExpanded, LT.TwoColumnsMidExpanded, LT.ThreeColumnsBeginExpandedEndHidden, LT.ThreeColumnsMidExpandedEndHidden]; sExitFullScreen = this._oFCL._getLayoutHistory().getClosestEntryThatMatches(aEligibleLayouts) || this._defaultTwoColumnLayoutType; oMidColumn.exitFullScreen = sExitFullScreen; oMidColumn.closeColumn = this._defaultLayoutType; } if (sColumnWidthDistribution === "0/0/100") { if (this._maxColumnsCount !== 2) { aEligibleLayouts = [LT.ThreeColumnsMidExpanded, LT.ThreeColumnsEndExpanded]; sExitFullScreen = this._oFCL._getLayoutHistory().getClosestEntryThatMatches(aEligibleLayouts) || this._defaultThreeColumnLayoutType; oEndColumn.exitFullScreen = sExitFullScreen; oEndColumn.closeColumn = this._defaultTwoColumnLayoutType; } } } return { midColumn: oMidColumn, endColumn: oEndColumn }; }; /** * Returns the default layout types for the different numbers of columns. * * * * @public * @returns {Object} The object describing the default layout types for the different numbers of columns */ FlexibleColumnLayoutSemanticHelper.prototype.getDefaultLayouts = function () { return { defaultLayoutType: this._defaultLayoutType, defaultTwoColumnLayoutType: this._defaultTwoColumnLayoutType, defaultThreeColumnLayoutType: this._defaultThreeColumnLayoutType }; }; /** * Determines whether the FCL can display 2 columns side by side. * This check can only be performed reliably if the control is rendered (so that its width can be measured). * Otherwise, only a best guess can be made, based on the window size, instead. * * @returns {boolean} * @private */ FlexibleColumnLayoutSemanticHelper.prototype._canShowTwoColumns = function () { var iControlWidth = this._oFCL._getControlWidth(), iMaxColumnsCount = this._oFCL._getMaxColumnsCountForWidth( iControlWidth || window.innerWidth); return iMaxColumnsCount > 1; }; return FlexibleColumnLayoutSemanticHelper; }, /* bExport= */ true);