text: /*!
   * OpenUI5
   * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  // Provides control sap.m.ColorPalette
  sap.ui.define([
  	'sap/ui/core/Control',
  	'sap/ui/Device',
  	'sap/ui/base/DataType',
  	'sap/ui/core/library',
  	'sap/ui/core/delegate/ItemNavigation',
  	'./Button',
  	'./Dialog',
  	'./library',
  	'./ColorPaletteRenderer',
  	"sap/ui/dom/containsOrEquals",
  	"sap/ui/events/KeyCodes",
  	"sap/ui/thirdparty/jquery",
  	"sap/ui/unified/library",
  	"sap/ui/unified/ColorPickerDisplayMode",
  	"sap/ui/unified/ColorPicker"
  ], function(
  	Control,
  	Device,
  	DataType,
  	coreLibrary,
  	ItemNavigation,
  	Button,
  	Dialog,
  	library,
  	ColorPaletteRenderer,
  	containsOrEquals,
  	KeyCodes,
  	jQuery,
  	unifiedLibrary,
  	ColorPickerDisplayMode,
  	ColorPicker
  ) {
  		"use strict";
  
  		// shortcut to CSSColor of the core library
  		var CSSColor = coreLibrary.CSSColor;
  
  		// shortcut to ColorPickerMode
  		var ColorPickerMode = unifiedLibrary.ColorPickerMode;
  
  		// shortcut to the ButtonType enumeration
  		var ButtonType = library.ButtonType;
  
  		// reference to the boolean data type in the core
  		var BooleanType = DataType.getType("boolean");
  
  		// The name of the class, corresponding to a single color item
  		var CSS_CLASS_SWATCH = "sapMColorPaletteSquare";
  
  		// Defines the exact count of swatches per row
  		var SWATCHES_PER_ROW = 5;
  
  		// Min amount of swatches when app.developer sets colors
  		var MIN_COLORS = 2;
  
  		// Max amount of swatches when app.developer sets colors
  		var MAX_COLORS = 15;
  
  		// get resource translation bundle;
  		var oLibraryResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m");
  
  		/**
  		 * Constructor for a new <code>ColorPalette</code>.
  		 *
  		 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
  		 * @param {object} [mSettings] Initial settings for the new control
  		 *
  		 * @class
  		 * Represents a predefined range of colors for easier selection.
  		 *
  		 * <h3>Overview</h3>
  		 * The <code>ColorPalette</code> provides the users with a range of predefined colors.
  		 *
  		 * You can customize them with the use of the <code>colors</code> property.
  		 * You can specify a <code>defaultColor</code> and display a "Default color" button
  		 * for the user to choose directly. You can display a "More colors..." button
  		 * that opens an additional color picker for the user to choose specific colors
  		 * that are not present in the predefined range.
  		 *
  		 * <h3>Usage</h3>
  		 *
  		 * The palette is intended for users, who don't want to check and remember the
  		 * different values of the colors and spend large amount of time to configure the
  		 * right color through the color picker.
  		 *
  		 * The control can be embedded in a form or can be opened as popover (by use of thin
  		 * wrapper control <code>sap.m.ColorPalettePopover</code>).
  		 * @see {@link sap.m.ColorPalettePopover}
  		 *
  		 * <b>Note:</b> The application developers should add dependency to <code>sap.ui.unified</code> library
  		 * on application level to ensure that the library is loaded before the module dependencies will be required.
  		 * The {@link sap.ui.unified.ColorPicker} is used internally only if the <code>ColorPicker</code>
  		 * is opened (not used for the initial rendering). If the <code>sap.ui.unified</code> library is not loaded
  		 * before the <code>ColorPicker</code> is opened, it will be loaded upon opening. This could lead to CSP compliance
  		 * issues and adds an additional waiting time when the <code>ColorPicker</code> is opened for the first time.
  		 * To prevent this, apps using the <code>ColorPalette</code> should also load the <code>sap.ui.unified</code> library in advance.
  		 *
  		 * @extends sap.ui.core.Control
  		 * @version 1.96.7
  		 *
  		 * @constructor
  		 * @public
  		 * @since 1.54
  		 * @alias sap.m.ColorPalette
  		 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
  		 */
  		var ColorPalette = Control.extend("sap.m.ColorPalette", /** @lends sap.m.ColorPalette.prototype */ {
  			metadata: {
  				library: "sap.m",
  				properties: {
  					/**
  					 * Defines the List of colors displayed in the palette. Minimum is 2 colors, maximum is 15 colors.
  					 */
  					colors: {
  						type: "sap.ui.core.CSSColor[]", group: "Appearance",
  						defaultValue: [
  							"gold",
  							"darkorange",
  							"indianred",
  							"darkmagenta",
  							"cornflowerblue",
  							"deepskyblue",
  							"darkcyan",
  							"olivedrab",
  							"darkslategray",
  							"azure",
  							"white",
  							"lightgray",
  							"darkgray",
  							"dimgray",
  							"black"
  						]
  					}
  				},
  
  				aggregations: {
  					/* Reference to an optional button for activating default color. For private use. */
  					_defaultColorButton: {type: "sap.m.Button", multiple: false, visibility: "hidden"},
  
  					/* Reference to an optional button for activating more color selection. For private use. */
  					_moreColorsButton: {type: "sap.m.Button", multiple: false, visibility: "hidden"}
  				},
  
  				events: {
  					/**
  					 * Fired when the user selects a color.
  					 */
  					colorSelect: {
  						parameters: {
  							/**
  							 * The color that is returned when user chooses the "Default color" button.
  							 */
  							"value": {type: "sap.ui.core.CSSColor"},
  							/**
  							 * Denotes if the color has been chosen by selecting the "Default Color" button (true or false)
  							 */
  							"defaultAction": {type: "boolean"}
  						}
  					},
  					/**
  					 * Fired when the value is changed by user interaction in the internal ColorPicker
  					 *
  					 * @since 1.85
  					 */
  					liveChange: {
  						parameters : {
  
  							/**
  							 * Parameter containing the RED value (0-255).
  							 */
  							r : {type: "int"},
  
  							/**
  							 * Parameter containing the GREEN value (0-255).
  							 */
  							g : {type: "int"},
  
  							/**
  							 * Parameter containing the BLUE value (0-255).
  							 */
  							b : {type: "int"},
  
  							/**
  							 * Parameter containing the HUE value (0-360).
  							 */
  							h : {type: "int"},
  
  							/**
  							 * Parameter containing the SATURATION value (0-100).
  							 */
  							s : {type: "int"},
  
  							/**
  							 * Parameter containing the VALUE value (0-100).
  							 */
  							v : {type: "int"},
  
  							/**
  							 * Parameter containing the LIGHTNESS value (0-100).
  							 */
  							l : {type: "int"},
  
  							/**
  							 * Parameter containing the Hexadecimal string (#FFFFFF).
  							 */
  							hex : {type: "string"},
  
  							/**
  							 * Parameter containing the alpha value (transparency).
  							 */
  							alpha : {type: "string"}
  						}
  					}
  				}
  			}
  		});
  
  		ColorPalette.prototype.init = function () {
  
  			// The default color. Private API. Allowed consumer is ColorPaletteAPI.
  			this._oDefaultColor = null;
  
  			// If the "Default color" button should be shown. Private API. Allowed consumer is ColorPaletteAPI.
  			this._bShowDefaultColorButton = false;
  
  			// If the "More colors" button should be shown. Private API. Allowed consumer is ColorPaletteAPI.
  			this._bShowMoreColorsButton = false;
  
  			// If the "Recent colors" section should be shown. Private API. Allowed consumer is ColorPaletteAPI
  			this._bShowRecentColorsSection = false;
  
  			// Display mode. Private API. Allowed consumer is ColorPaletteAPI.
  			this._oDisplayMode = ColorPickerDisplayMode.Default;
  
  			// Reference to the dialog containing the internal "Color Picker". For private use.
  			this._oMoreColorsDialog = null;
  
  			// Reference to the palette color section item navigation
  			this._oPaletteColorItemNavigation = null;
  
  			// Reference to the recent color section item navigation
  			this._oRecentColorItemNavigation = null;
  
  			// Queue of recently used colors
  			this._recentColors = [];
  		};
  
  		ColorPalette.prototype.exit = function () {
  			if (this._oMoreColorsDialog) {
  				this._oMoreColorsDialog.destroy();
  				delete this._oMoreColorsDialog;
  			}
  
  			if (this._oPaletteColorItemNavigation) {
  				this.removeDelegate(this._oPaletteColorItemNavigation);
  				this._oPaletteColorItemNavigation.destroy();
  				delete this._oPaletteColorItemNavigation;
  			}
  
  			if (this._oRecentColorItemNavigation) {
  				this.removeDelegate(this._oRecentColorItemNavigation);
  				this._oRecentColorItemNavigation.destroy();
  				delete this._oRecentColorItemNavigation;
  			}
  		};
  
  		ColorPalette.prototype.setColors = function (aColors) {
  			aColors = this.validateProperty("colors", aColors);
  
  			if (aColors.length < MIN_COLORS || aColors.length > MAX_COLORS) {
  				throw new Error("Cannot set property 'colors' - array must has minimum 2 and maximum 15 elements");
  			}
  			return this.setProperty("colors", aColors);
  		};
  
  		/**
  		 * Sets a default displayMode.
  		 * @param {sap.ui.unified.ColorPickerDisplayMode} oDisplayMode the color
  		 * @private
  		 * @return {this} <code>this</code> for method chaining
  		 */
  		ColorPalette.prototype._setDisplayMode = function (oDisplayMode) {
  			var oColorPicker = this._getColorPicker();
  			oColorPicker.setDisplayMode(oDisplayMode);
  			this._oDisplayMode = oDisplayMode;
  
  			return this;
  		};
  
  		// Display mode
  		ColorPalette.prototype._getDisplayMode = function () {
  			return this._oDisplayMode;
  		};
  
  		ColorPalette.prototype._getColorPicker = function () {
  			return this._ensureMoreColorsDialog()._oColorPicker;
  		};
  
  		ColorPalette.prototype.ontap = function (oEvent) {
  			var $Target = jQuery(oEvent.target),
  				sColor,
  				$Swatch;
  
  			$Swatch = $Target.closest("." + CSS_CLASS_SWATCH);
  			if (!$Swatch.length) {
  				return;
  			}
  
  			sColor = $Swatch.attr("data-sap-ui-color");
  			this._fireColorSelect(sColor, false, oEvent);
  		};
  
  		ColorPalette.prototype.onsaptabnext = ColorPalette.prototype.onsaptabprevious = function (oEvent) {
  			var oElementInfo = this._getElementInfo(oEvent.target);
  
  			if (oElementInfo.bIsMoreColorsButton) {
  				this.fireEvent("_colorNotSelected", {_originalEvent: oEvent});
  				return;
  			}
  
  			if (oElementInfo.bIsDefaultColorButton) {
  				this._fireColorSelect(this._getDefaultColor(), true, oEvent);
  				return;
  			}
  
  			ColorPalette.prototype.ontap.apply(this, arguments);
  		};
  
  		ColorPalette.prototype.onsapenter = ColorPalette.prototype.ontap;
  
  		ColorPalette.prototype.onsapspace = function (oEvent) {
  			oEvent.preventDefault();
  		};
  
  		ColorPalette.prototype.onkeyup = function (oEvent) {
  			if (oEvent.which === KeyCodes.SPACE) {
  				oEvent.preventDefault();
  				ColorPalette.prototype.ontap.apply(this, arguments);
  			}
  		};
  
  		ColorPalette.prototype.onAfterRendering = function () {
  			this._ensureItemNavigation();
  		};
  
  		ColorPalette.prototype.pushToRecentColors = function (sColor) {
  			var iIndexOfColor = this._recentColors.indexOf(sColor);
  
  			if (iIndexOfColor > -1){
  				this._recentColors.splice(iIndexOfColor,1);
  			} else if (this._recentColors.length === 5) {
  				this._recentColors.pop();
  			}
  
  			this._recentColors.unshift(sColor);
  
  			this.invalidate();
  		};
  
  		/**
  		 * Sets a selected color for the ColorPicker control.
  		 * @param {sap.ui.core.CSSColor} color the selected color
  		 * @public
  		 * @return {this} <code>this</code> for method chaining
  		 */
  		ColorPalette.prototype.setColorPickerSelectedColor = function (color) {
  			if (!CSSColor.isValid(color)) {
  				throw new Error("Cannot set the selected color - invalid value: " + color);
  			}
  			this._getColorPicker().setColorString(color);
  			return this;
  		};
  
  		// Private methods -------------------------------------------------------------------------------------------
  		ColorPalette.prototype._createDefaultColorButton = function () {
  			return new Button(this.getId() + "-btnDefaultColor", {
  				width: "100%",
  				type: ButtonType.Transparent,
  				text: oLibraryResourceBundle.getText("COLOR_PALETTE_DEFAULT_COLOR"),
  				visible: this._getShowDefaultColorButton(),
  				press: function (oEvent) {
  					this._fireColorSelect(this._getDefaultColor(), true, oEvent);
  				}.bind(this)
  			});
  		};
  
  		// Default color
  		ColorPalette.prototype._getDefaultColor = function () {
  			return this._oDefaultColor;
  		};
  
  		/**
  		 * Sets a default color.
  		 * @param {sap.ui.core.CSSColor} color the color
  		 * @private
  		 * @return {this} <code>this</code> for method chaining
  		 */
  		ColorPalette.prototype._setDefaultColor = function (color) {
  			if (!CSSColor.isValid(color)) {
  				throw new Error("Cannot set internal property '_defaultColor' - invalid value: " + color);
  			}
  			this._oDefaultColor = color;
  			return this;
  		};
  
  
  		ColorPalette.prototype._getShowDefaultColorButton = function () {
  			return this._bShowDefaultColorButton;
  		};
  
  
  		ColorPalette.prototype._setShowDefaultColorButton = function (bValue) {
  			if (!BooleanType.isValid(bValue)) {
  				throw new Error("Cannot set internal property 'showDefaultColorButton' - invalid value: " + bValue);
  			}
  			this._bShowDefaultColorButton = bValue;
  
  			//lazy loading check
  			if (bValue && !this._getDefaultColorButton()) {
  				this.setAggregation("_defaultColorButton", this._createDefaultColorButton());
  			}
  
  			if (this._getDefaultColorButton()) { /* still button may not be there */
  				this._getDefaultColorButton().setVisible(bValue);
  			}
  			return this;
  		};
  
  		ColorPalette.prototype._getDefaultColorButton = function () {
  			return this.getAggregation("_defaultColorButton");
  		};
  
  		// More Colors...
  		ColorPalette.prototype._createMoreColorsButton = function () {
  			return new Button(this.getId() + "-btnMoreColors", {
  				width: "100%",
  				type: ButtonType.Transparent,
  				text: oLibraryResourceBundle.getText("COLOR_PALETTE_MORE_COLORS"),
  				visible: this._getShowMoreColorsButton(),
  				press: this._openColorPicker.bind(this)
  			});
  		};
  
  		ColorPalette.prototype._getShowMoreColorsButton = function () {
  			return this._bShowMoreColorsButton;
  		};
  
  		ColorPalette.prototype._getShowRecentColorsSection = function () {
  			return this._bShowRecentColorsSection;
  		};
  
  		ColorPalette.prototype._getRecentColors = function () {
  			return this._recentColors;
  		};
  
  		ColorPalette.prototype._setShowRecentColorsSection = function (bValue) {
  			if (!BooleanType.isValid(bValue)) {
  				throw new Error("Cannot set internal property 'showRecentColorsSection' - invalid value: " + bValue);
  			}
  			this._bShowRecentColorsSection = bValue;
  
  			return this;
  		};
  
  		ColorPalette.prototype._setShowMoreColorsButton = function (bValue) {
  			if (!BooleanType.isValid(bValue)) {
  				throw new Error("Cannot set internal property 'showMoreColorsButton' - invalid value: " + bValue);
  			}
  			this._bShowMoreColorsButton = bValue;
  
  			//lazy loading check
  			if (bValue && !this._getMoreColorsButton()) {
  				this.setAggregation("_moreColorsButton", this._createMoreColorsButton());
  			}
  
  			if (this._getMoreColorsButton()) { /* still button may not be there */
  				this._getMoreColorsButton().setVisible(bValue);
  			}
  			return this;
  		};
  
  		ColorPalette.prototype._getMoreColorsButton = function () {
  			return this.getAggregation("_moreColorsButton");
  		};
  
  		/**
  		 * Opens a color picker in a Dialog.
  		 * The function assumes that there is a "more colors.." button visible.
  		 * @return void
  		 * @private
  		 */
  		ColorPalette.prototype._openColorPicker = function () {
  			this.fireEvent("_beforeOpenColorPicker"); //hook for program consumers (i.e. ColorPalettePopover)
  			this._ensureMoreColorsDialog().open();
  		};
  
  		/**
  		 * Ensure a dialog wrapping the ColorPicker exists (creates new if is not created yet).
  		 * @return {sap.m.Dialog} the dialog.
  		 * @private
  		 */
  		ColorPalette.prototype._ensureMoreColorsDialog = function () {
  			if (!this._oMoreColorsDialog) {
  				this._oMoreColorsDialog = this._createMoreColorsDialog();
  			}
  
  			return this._oMoreColorsDialog;
  		};
  
  		/**
  		 * Creates a dialog that wraps the ColorPicker
  		 * @return {sap.m.Dialog} the dialog containing the ColorPicker
  		 * @private
  		 */
  		ColorPalette.prototype._createMoreColorsDialog = function () {
  			var oDialog = new Dialog(this.getId() + "-moreColorsDialog", {
  				stretch: !!Device.system.phone,
  				title: oLibraryResourceBundle.getText("COLOR_PALETTE_MORE_COLORS_TITLE")
  			}).addStyleClass("CPDialog");
  
  			// keep explicit reference to the picker attached to the parent dialog
  			oDialog.addContent(oDialog._oColorPicker = new ColorPicker({
  				mode: ColorPickerMode.HSL,
  				displayMode: this._oDisplayMode,
  				liveChange: function (oEvent) {
  					this.fireLiveChange(oEvent.getParameters());
  				}.bind(this)
  			}));
  
  			// OK button
  			oDialog.setBeginButton(new Button({
  				text: oLibraryResourceBundle.getText("COLOR_PALETTE_MORE_COLORS_CONFIRM"),
  				press: function (oEvent) {
  					oDialog.close();
  					if (oDialog._oColorPicker.getColorString()) {
  						this._fireColorSelect(oDialog._oColorPicker.getColorString(), false, oEvent);
  					}
  				}.bind(this)
  			}));
  
  			// Cancel button
  			oDialog.setEndButton(new Button({
  				text: oLibraryResourceBundle.getText("COLOR_PALETTE_MORE_COLORS_CANCEL"),
  				press: function () {
  					oDialog.close();
  				}
  			}));
  
  			return oDialog;
  		};
  
  		// Other
  		/**
  		 * Focuses the first available element in the palette.
  		 * @private
  		 */
  		ColorPalette.prototype._focusFirstElement = function () {
  			var oFirstSwatchElement = this._getShowDefaultColorButton() ? this._getDefaultColorButton().getDomRef() : this._getAllPaletteColorSwatches()[0];
  
  			oFirstSwatchElement.focus();
  		};
  
  		/**
  		 * Helper function to fire the event "colorSelect"
  		 * @param {sap.ui.core.CSSColor} color the color
  		 * @param {boolean} [defaultAction=false] if the selection is performed via "Default color" button
  		 * @param {jQuery.Event} oOriginalEvent original event
  		 * @private
  		 */
  		ColorPalette.prototype._fireColorSelect = function (color, defaultAction, oOriginalEvent) {
  			this.fireColorSelect({value: color, defaultAction: defaultAction, _originalEvent: oOriginalEvent});
  			this.pushToRecentColors(color);
  		};
  
  		/**
  		 * Handles creation or update of the ItemNavigation.
  		 * @private
  		 */
  		ColorPalette.prototype._ensureItemNavigation = function () {
  			var aPaletteColorsDomRefs = [],
  				aRecentColorsDomRefs = [];
  
  			if (!this._oPaletteColorItemNavigation) {
  				this._oPaletteColorItemNavigation = new ItemNavigationHomeEnd(this);
  				this._oPaletteColorItemNavigation.setColumns(SWATCHES_PER_ROW);
  				this._oPaletteColorItemNavigation.setCycling(false);
  				this.addDelegate(this._oPaletteColorItemNavigation);
  				this._oPaletteColorItemNavigation.attachEvent(ItemNavigation.Events.BorderReached, this._onSwatchContainerBorderReached, this);
  			}
  
  			if (!this._oRecentColorItemNavigation) {
  				this._oRecentColorItemNavigation = new ItemNavigationHomeEnd(this);
  				this._oRecentColorItemNavigation.setColumns(SWATCHES_PER_ROW);
  				this._oRecentColorItemNavigation.setCycling(false);
  				this.addDelegate(this._oRecentColorItemNavigation);
  				this._oRecentColorItemNavigation.attachEvent(ItemNavigation.Events.BorderReached, this._onSwatchContainerBorderReached, this);
  			}
  
  			// all currently available swatches
  			aPaletteColorsDomRefs = aPaletteColorsDomRefs.concat(this._getAllPaletteColorSwatches());
  			aRecentColorsDomRefs = aRecentColorsDomRefs.concat(this._getAllRecentColorSwatches());
  			aRecentColorsDomRefs = aRecentColorsDomRefs.slice(0, this._getRecentColors().length);
  
  
  			this._oPaletteColorItemNavigation.setRootDomRef(this.getDomRef("swatchCont-paletteColor"));
  			this._oPaletteColorItemNavigation.setItemDomRefs(aPaletteColorsDomRefs);
  
  			this._oRecentColorItemNavigation.setRootDomRef(this.getDomRef("swatchCont-recentColors"));
  			this._oRecentColorItemNavigation.setItemDomRefs(aRecentColorsDomRefs);
  		};
  
  		/**
  		 * Handles navigation from within the swatch container to the outside where the end-user navigates through the
  		 * swatch container and reaches its border (<code>ItemNavigationHomeEnd.BorderReachedDirectionBackward</code> or
  		 * <code>ItemNavigationHomeEnd.BorderReachedDirectionForward</code>).
  		 *
  		 * The buttons Default Color and More colors are handled as color palette items, these are also part of the
  		 * arrow key navigation.
  		 *
  		 * If the user is on the last swatch item and presses [Down] or [Right] keyboard key
  		 * (<code>ItemNavigationHomeEnd.BorderReachedDirectionForward</code>), the focus should go into one of the
  		 * following elements (in the provided order):
  		 * <ol>
  		 *	<li>More Colors button if such is available. If not, the focus should go to</li>
  		 *	<li>Default color button if such is available. If not, the focus should go to</li>
  		 *	<li>The first swatch item in the swatch container (there is always such)</li>
  		 * </ol>
  		 *
  		 * If the user is on the first swatch item inside the swatch container and presses [Up] or [Down] keyboard keys
  		 * (<code>ItemNavigationHomeEnd.BorderReachedDirectionBackward</code>) the focus should go into one of the
  		 * following elements (in the provided order):
  		 * <ol>
  		 *	<li>Default color button if such is available. If not, the focus should go to</li>
  		 *	<li>More Colors button if such is available. If not, the focus should go to</li>
  		 *  <li>The first swatch item in the last row of the swatch container (there is always such)</li>
  		 * </ol>
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 * @return {Element|sap.m.Button} the element that the focus has been moved on.
  		 * @private
  		 */
  		ColorPalette.prototype._onSwatchContainerBorderReached = function(oEvent) {
  			var vNextElement,
  				aSwatches,
  				bHomeOrEnd = ["saphome","sapend"].indexOf(oEvent.getParameter("event").type) > -1,
  				bIsRecentColorSwatch = this._getAllRecentColorSwatches()[0] ? this._getElementInfo(oEvent.mParameters.event.target).bIsRecentColorSwatch : false;
  
  			if (oEvent.getParameter(ItemNavigationHomeEnd.BorderReachedDirection) === ItemNavigationHomeEnd.BorderReachedDirectionForward) {
  				if (this._getShowMoreColorsButton() && !bIsRecentColorSwatch) {
  					vNextElement = this._getMoreColorsButton();
  				} else if (!bHomeOrEnd && this._bShowRecentColorsSection && !bIsRecentColorSwatch && this._getRecentColors().length > 0) {
  					vNextElement = this._getAllRecentColorSwatches()[0];
  				} else if (!bHomeOrEnd && this._getShowDefaultColorButton()) {// Default Color, but excluding "home" and "end"
  					vNextElement = this._getDefaultColorButton();
  				}  else if (!bHomeOrEnd) { // swatch, but not due to "home" and "end" keys
  					vNextElement = this._getAllPaletteColorSwatches()[0];
  				}
  			} else { // Backward
  				if (this._getShowDefaultColorButton() && !bIsRecentColorSwatch) {
  					vNextElement = this._getDefaultColorButton();
  				} else if (!bHomeOrEnd && this._bShowRecentColorsSection && !bIsRecentColorSwatch && this._getRecentColors().length > 0) {
  					vNextElement = this._getAllRecentColorSwatches()[0];
  				} else if (!bHomeOrEnd && this._getShowMoreColorsButton()) {// More Colors, but excluding "home" and "end"
  					vNextElement = this._getMoreColorsButton();
  				} else if (!bHomeOrEnd && !this._getShowDefaultColorButton()) { // swatch, but not due to "home" and "end" keys
  					aSwatches = this._getAllPaletteColorSwatches();
  					vNextElement = aSwatches[aSwatches.length - 1];
  				} else if (!bHomeOrEnd) { // swatch, but not due to "home" and "end" keys
  					aSwatches = this._getAllPaletteColorSwatches();
  					vNextElement = aSwatches[this._oPaletteColorItemNavigation._getIndexOfTheFirstItemInLastRow()];
  				}
  			}
  
  			if (vNextElement) {
  				vNextElement.focus();
  			}
  
  			return vNextElement;
  		};
  
  		/**
  		 * Handles forward navigation when the user is either on Default Color or More Colors buttons.
  		 *
  		 * If the user is on Default Color, focus should go to the first item in the swatch container.
  		 * If the user is on More Colors, focus should go on the Default Color button if such exists, otherwise on the
  		 * the first item in the swatch container.
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ColorPalette.prototype.onsapnext = function (oEvent) {
  			var vNextElement,
  				oElementInfo = this._getElementInfo(oEvent.target);
  
  			if (!(oElementInfo.bIsDefaultColorButton || oElementInfo.bIsMoreColorsButton)) {
  				return;
  			}
  
  			oEvent.preventDefault();
  			oEvent.stopImmediatePropagation(true); //also prevents ItemNavigation handler
  
  			if (oElementInfo.bIsDefaultColorButton) {
  				vNextElement = this._getAllPaletteColorSwatches()[0];
  			} else if (this._getRecentColors().length > 0 && !oElementInfo.bIsRecentColorSwatch && this._bShowRecentColorsSection){
  				vNextElement = this._getAllRecentColorSwatches()[0];
  			} else {
  				vNextElement = this._getShowDefaultColorButton() ? this._getDefaultColorButton() : this._getAllPaletteColorSwatches()[0];
  			}
  
  			vNextElement.focus();
  		};
  
  		/**
  		 * Handles backward navigation when user is either on Default Color or More Colors buttons.
  		 *
  		 * If the user is on Default Color, focus should go to the More Colors button if such exists, otherwise,
  		 * on the first item in the last row of the swatch container.
  		 * If user is on More Colors, focus should go on:
  		 *  - the first item in the last row of the swatch container if <code>sapprevious</code> is fired due to
  		 * [Up] key, otherwise
  		 *  - the last item in the swatch container (the possible keycodes is: [Left] (in ltr) or [Right] (rtl).
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ColorPalette.prototype.onsapprevious = function (oEvent) {
  			var vNextElement,
  				oFocusInfo = this._getElementInfo(oEvent.target),
  				aAllSwatches;
  
  			if (!(oFocusInfo.bIsDefaultColorButton || oFocusInfo.bIsMoreColorsButton || oEvent.target === this._getAllRecentColorSwatches()[0])) {
  				return;
  			}
  
  			oEvent.preventDefault();
  			oEvent.stopImmediatePropagation(true);//also prevents ItemNavigation handler
  
  			aAllSwatches = this._getAllPaletteColorSwatches();
  
  			if (oFocusInfo.bIsMoreColorsButton || (!oFocusInfo.bIsMoreColorsButton && this.bIsRecentColorSwatch)) {
  				vNextElement = oEvent.keyCode === KeyCodes.ARROW_UP ?
  					aAllSwatches[this._oPaletteColorItemNavigation._getIndexOfTheFirstItemInLastRow()] : aAllSwatches[aAllSwatches.length - 1];
  			} else if (oFocusInfo.bIsRecentColorSwatch && !this._bShowMoreColorsButton && !this._bShowDefaultColorButton) {
  				aAllSwatches = this._getAllPaletteColorSwatches();
  				vNextElement = aAllSwatches[this._oPaletteColorItemNavigation._getIndexOfTheFirstItemInLastRow()];
  			} else if (this._getRecentColors().length > 0 && !oFocusInfo.bIsRecentColorSwatch && this._bShowRecentColorsSection){
  				vNextElement = this._getAllRecentColorSwatches()[0];
  			} else if (this._getShowMoreColorsButton()){
  				vNextElement = this._getMoreColorsButton();
  			} else {
  				vNextElement = aAllSwatches[this._oPaletteColorItemNavigation._getIndexOfTheFirstItemInLastRow()];
  			}
  
  			vNextElement.focus();
  		};
  
  		/**
  		 * Handles backward navigation when the user is either on Default Color or More Colors buttons.
  		 *
  		 * If the user is on Default Color, focus shouldn't chage.
  		 * If the user is on More Colors, focus should go on the Default Color button if such exists,
  		 * otherwise the focus shouldn't change.
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ColorPalette.prototype.onsaphome = function(oEvent) {
  			// Home and End keys on ColorPalette buttons should do nothing. If event occurs on the swatch, see ItemNavigationHomeEnd).
  			var oElementInfo = this._getElementInfo(oEvent.target);
  
  			if (!oElementInfo.bIsMoreColorsButton) {
  				return;
  			}
  
  			if (this._getShowDefaultColorButton()) {
  				this._getDefaultColorButton().focus();
  			}
  
  			oEvent.preventDefault();
  			oEvent.stopImmediatePropagation(true); // does not allow the ItemNavigationHomeEnd delegate to receive it
  		};
  
  		/**
  		 * Handles forward navigation when the user is either on Default Color or More Colors buttons.
  		 *
  		 * If the user is on More Colors, focus shouldn't chage.
  		 * If the user is on Default Color, focus should go on the More Colors button if such exists,
  		 * otherwise the focus shouldn't change.
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ColorPalette.prototype.onsapend = function(oEvent) {
  			var oElementInfo = this._getElementInfo(oEvent.target);
  
  			if (!oElementInfo.bIsDefaultColorButton) {
  				return;
  			}
  
  			if (this._getShowMoreColorsButton()) {
  				this._getMoreColorsButton().focus();
  			}
  
  			oEvent.preventDefault();
  			oEvent.stopImmediatePropagation(true); // does not allow the ItemNavigationHomeEnd delegate to receive it
  		};
  
  		// DOM related private helpers
  
  		/**
  		 * Returns all palette swatches/squares
  		 * @return {Element[]} returns all swatch container items in an array of DOM elements.
  		 * @private
  		 */
  		ColorPalette.prototype._getAllPaletteColorSwatches = function () {
  			return this.$().find("." + CSS_CLASS_SWATCH).get().slice(0, this.getColors().length);
  		};
  
  		/**
  		 * Returns all swatches/squares in recent color section
  		 * @return {Element[]} returns all swatch container items in an array of DOM elements.
  		 * @private
  		 */
  		ColorPalette.prototype._getAllRecentColorSwatches = function () {
  			return this.$().find("." + CSS_CLASS_SWATCH).get().slice(this.getColors().length);
  		};
  
  		/**
  		 * Analyzes if given DOM element is one of the <code>ColorPalette</code> artifacts (Default Color, More Colors,
  		 * swatch color).
  		 * @param {Element} oElement DOM Element
  		 * @return {{bIsDefaultColorButton: *, bIsMoreColorsButton: boolean|*, bIsASwatch: boolean|*}} result
  		 * @private
  		 */
  		ColorPalette.prototype._getElementInfo = function (oElement) {
  			var bIsDefaultColorButton = this._getShowDefaultColorButton() && containsOrEquals(oElement,
  					this._getDefaultColorButton().getDomRef()),
  				bIsMoreColorsButton = !bIsDefaultColorButton && this._getShowMoreColorsButton() && containsOrEquals(oElement,
  					this._getMoreColorsButton().getDomRef()),
  				bIsRecentColorSwatch = this._getAllRecentColorSwatches().indexOf(oElement) > -1,
  				bIsASwatch = this._getAllPaletteColorSwatches().indexOf(oElement) > -1;
  
  			return {
  				bIsDefaultColorButton: bIsDefaultColorButton,
  				bIsMoreColorsButton: bIsMoreColorsButton,
  				bIsASwatch: bIsASwatch,
  				bIsRecentColorSwatch: bIsRecentColorSwatch
  			};
  		};
  
  		/**
  		 * Extension of <code>sap.ui.core.delegate.ItemNavigation</code> to support custom keyboard handling for:
  		 * - [Home] (overrides <code>onsaphome</code>,
  		 * - [End] (overrides <code>onsapend</code>),
  		 * - [Up] (overrides <code>onsapprevious</code>),
  		 * - [Down] (overrides <code>onsapnext</code>).
  		 *
  		 * When using [Up] or [Down] keys, the focus moves up one row or down one row.
  		 * If the next row has less items than the currently focused row, and the focus is above whitespace, the use of
  		 * the [Down] arrow key moves the focus to the last item of the next row (-> also changes column). When using [Up] now,
  		 * the focus moves one row up, onto the same column.
  		 *
  		 * <code>ItemNavigation</code>'s event <code>BorderReached</code> is enhanced. It used to be fired by [Right]
  		 * (respectively [Left]) key on the last (respectively the first) item. Now, the same event is fired also when
  		 * [Down] (respectively [Up]) key is used.
  		 *
  		 * If the [Home] key is pressed, it moves the focus according to the following order:
  		 * - to the first item in the current row. If already on it
  		 * - to the first item in the whole container. If already on it
  		 * - fires a <code>BorderReached</code> event
  		 *
  		 * Respectively, if the [End] key is pressed, it moves the focus according to the following order:
  		 * - to the last item in the current row. If already on it
  		 * - to the last item in the whole container. If already on it
  		 * - fires a <code>BorderReached</code> event
  		 *
  		 *  @private
  		 */
  		var ItemNavigationHomeEnd = ItemNavigation.extend("sap.m.ItemNavigationHomeEnd", {
  			constructor: function () {
  				ItemNavigation.apply(this, arguments);
  				this.setHomeEndColumnMode(true);
  
  				// overrides fireEvent in order to enhance it with the parameter 'direction'
  				this.fireEvent = function(sName, oEventParams) {
  					var sDirection;
  
  					if (sName === ItemNavigation.Events.BorderReached) {
  						sDirection = ItemNavigationHomeEnd.BorderReachedDirectionBackward;
  						if (["sapnext", "sapend"].indexOf(oEventParams.event.type) > -1) { // last item
  							sDirection = ItemNavigationHomeEnd.BorderReachedDirectionForward;
  						}
  						oEventParams[ItemNavigationHomeEnd.BorderReachedDirection] = sDirection;
  					}
  					ItemNavigation.prototype.fireEvent.apply(this, arguments);
  				};
  			}
  		});
  
  		// Custom Event Parameter to enhance ItemNavigation.BorderReached event with the direction of reach.
  		ItemNavigationHomeEnd.BorderReachedDirection = "direction";
  		ItemNavigationHomeEnd.BorderReachedDirectionForward = "BorderReachedDirectionForward";
  		ItemNavigationHomeEnd.BorderReachedDirectionBackward = "BorderReachedDirectionBackward";
  
  		/**
  		 * Returns the number of columns defined.
  		 * @return {*}
  		 */
  		ItemNavigationHomeEnd.prototype.getColumns = function() {
  			return this.iColumns;
  		};
  
  		/**
  		 * Handles the backward navigation in case the [Up] key is used on the first swatch item.
  		 * Otherwise, delegates the event to the <code>ItemNavigation</code>.
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ItemNavigationHomeEnd.prototype.onsapprevious = function (oEvent) {
  			var bIsOnItem = containsOrEquals(this.getRootDomRef(), oEvent.target),
  				bArrowUpOnFirstItem = oEvent.keyCode === KeyCodes.ARROW_UP && this.getFocusedIndex() === 0;
  
  			if (!bIsOnItem) {
  				return;
  			}
  
  			if (!bArrowUpOnFirstItem) {
  				ItemNavigation.prototype.onsapprevious.apply(this, arguments);
  				return;
  			}
  
  			oEvent.preventDefault(); // browser's scrolling should be prevented
  
  			this.fireEvent(ItemNavigation.Events.BorderReached, {
  				index: 0,
  				event: oEvent
  			});
  
  		};
  
  		/**
  		 * Handles the forward navigation when the [Down] key is used in the following cases:
  		 * - on the last swatch item
  		 * - on an upper row item when moving on the same column of the next row will hit an empty/whitespace swatch item.
  		 * Otherwise delegates the event to the <code>ItemNavigation</code>.
  		 *
  		 * @param {jQuery.Event} oEvent the keyboard event
  		 */
  		ItemNavigationHomeEnd.prototype.onsapnext = function (oEvent) {
  			var bIsOnItem = containsOrEquals(this.getRootDomRef(), oEvent.target),
  				aItemDomRefs,
  				iCurrentIndex,
  				oItemInfo;
  
  			if (!bIsOnItem) {
  				return;
  			}
  
  			if (oEvent.keyCode !== KeyCodes.ARROW_DOWN) {
  				ItemNavigation.prototype.onsapnext.apply(this, arguments);
  				return;
  			}
  
  			iCurrentIndex = this.getFocusedIndex();
  			oItemInfo = this._getItemInfo(iCurrentIndex);
  
  			if (oItemInfo.bIsLastItem && oItemInfo.bIsInTheLastColumn) {
  				oEvent.preventDefault(); //browser's scrolling should be prevented
  
  				this.fireEvent(ItemNavigation.Events.BorderReached, {// Arrow down on last item should fire the event "BorderReached"
  					index: iCurrentIndex,
  					event: oEvent
  				});
  				return;
  			}
  
  			// Whitespace handler
  			if (oItemInfo.bNextRowExists && !oItemInfo.bItemSameColumnNextRowExists) {
  
  				oEvent.preventDefault(); //browser's scrolling should be prevented
  
  				aItemDomRefs = this.getItemDomRefs();
  				aItemDomRefs[aItemDomRefs.length - 1].focus();
  
  				return;
  			}
  
  			ItemNavigation.prototype.onsapnext.apply(this, arguments);
  		};
  
  		ItemNavigationHomeEnd.prototype.onsaphome = function(oEvent) {
  			var bIsOnItem = containsOrEquals(this.getRootDomRef(), oEvent.target),
  				oItemInfo;
  
  			if (!bIsOnItem) {
  				return;
  			}
  
  			oItemInfo = this._getItemInfo(this.getFocusedIndex());
  
  			if (!oItemInfo.bIsInTheFirstColumn) {
  				// delegate to the parent, which should move the focus to the first item in the row
  				ItemNavigation.prototype.onsaphome.apply(this, arguments);
  				return;
  			}
  
  			oEvent.preventDefault(); // browser's scrolling should be prevented
  
  			if (oItemInfo.bIsFirstItem) {
  				this.fireEvent(ItemNavigation.Events.BorderReached, {
  					index: 0,
  					event: oEvent
  				});
  			} else { //first item in the row, move the focus to the first item in the whole container
  				this.getItemDomRefs()[0].focus();
  			}
  		};
  
  		ItemNavigationHomeEnd.prototype.onsapend = function(oEvent) {
  			var bIsOnItem = containsOrEquals(this.getRootDomRef(), oEvent.target),
  				oItemInfo;
  
  			if (!bIsOnItem) {
  				return;
  			}
  
  			oItemInfo = this._getItemInfo(this.getFocusedIndex());
  
  			if (!(oItemInfo.bIsLastItem || oItemInfo.bIsInTheLastColumn)) {
  				// delegate to the parent, which should move the focus to the last item in the row
  				ItemNavigation.prototype.onsapend.apply(this, arguments);
  				return;
  			}
  
  			oEvent.preventDefault(); // browser's scrolling should be prevented
  
  			if (oItemInfo.bIsLastItem) {
  				this.fireEvent(ItemNavigation.Events.BorderReached, {
  					index: this.getItemDomRefs().length - 1,
  					event: oEvent
  				});
  			} else { // last item in the row, move the focus to the last item in the whole container
  				this.getItemDomRefs()[this.getItemDomRefs().length - 1].focus();
  			}
  		};
  
  		/**
  		 * Analyzes the given item and produces information about its position.
  		 * @param {number} iIndex the item given by its position
  		 * @return {{bIsLastItem: boolean, bIsInTheLastColumn: boolean, bNextRowExists: boolean|*, bItemSameColumnNextRowExists: boolean|*}}
  		 * @private
  		 */
  		ItemNavigationHomeEnd.prototype._getItemInfo = function(iIndex) {
  			var iItemsCount = this.getItemDomRefs().length,
  				bItemIsLast = iIndex === (iItemsCount - 1),
  				iLastVisibleColumn = iItemsCount  > this.getColumns() ? this.getColumns() : iItemsCount,
  				bItemIsInTheFirstColumn = iIndex % this.getColumns() === 0,
  				bItemIsInTheLastColumn = (iIndex + 1) % iLastVisibleColumn === 0,
  				iCurrentRow = Math.floor(iIndex / this.getColumns()) + 1, //1 based
  				bNextRowExists,
  				bItemSameColumnNextRowExists;
  
  			bNextRowExists = iCurrentRow * this.getColumns() < iItemsCount;
  			bItemSameColumnNextRowExists = bNextRowExists && (iIndex + this.getColumns()) < iItemsCount;
  
  			return {
  				bIsFirstItem: iIndex === 0,
  				bIsLastItem: bItemIsLast,
  				bIsInTheLastColumn: bItemIsInTheLastColumn,
  				bIsInTheFirstColumn: bItemIsInTheFirstColumn,
  				bNextRowExists: bNextRowExists,
  				bItemSameColumnNextRowExists: bItemSameColumnNextRowExists
  			};
  		};
  
  		/**
  		 * Calculates the index of the first item in the last row.
  		 * @return {int} the index(zero based) of the first/last item in the row.
  		 * @private
  		 */
  		ItemNavigationHomeEnd.prototype._getIndexOfTheFirstItemInLastRow = function () {
  			return Math.floor((this.getItemDomRefs().length - 1) / this.getColumns()) * this.getColumns();
  		};
  
  
  		/**
  		 * @private
  		 */
  		ColorPalette.prototype._ItemNavigation = ItemNavigationHomeEnd;
  
  		/**
  		 * Private Color map helper
  		 * @private
  		 */
  		ColorPalette.prototype._ColorsHelper = {
  			RGB_TO_NAMED_COLORS_MAP: {
  				"#FFB200": "gold",
  				"#FF8C00": "darkorange",
  				"#CD5C5C": "indianred",
  				"#8B008B": "darkmagenta",
  				"#6495ED": "cornflowerblue",
  				"#00BFFF": "deepskyblue",
  				"#008B8B": "darkcyan",
  				"#6B8E23": "olivedrab",
  				"#2F4F4F": "darkslategray",
  				"#F0FFFF": "azure",
  				"#FFFFFF": "white",
  				"#D3D3D3": "lightgray",
  				"#A9A9A9": "darkgray",
  				"#696969": "dimgray",
  				"#000000": "black"
  			},
  			NAME_COLORS_TO_RGB_MAP: {
  				"gold": "#FFB200",
  				"darkorange": "#FF8C00",
  				"indianred": "#CD5C5C",
  				"darkmagenta": "#8B008B",
  				"cornflowerblue": "#6495ED",
  				"deepskyblue": "#00BFFF",
  				"darkcyan": "#008B8B",
  				"olivedrab": "#6B8E23",
  				"darkslategray": "#2F4F4F",
  				"azure": "#F0FFFF",
  				"white": "#FFFFFF",
  				"lightgray": "#D3D3D3",
  				"darkgray": "#A9A9A9",
  				"dimgray": "#696969",
  				"black": "#000000"
  			},
  
  			/**
  			 * Returns a named color for given color. For example - "gold" for input "#FFB200".
  			 * @param {string} sColor the given color
  			 * @return {string|undefined} The named color, if such can really corresponds to the input color, or undefined otherwise.
  			 */
  			getNamedColor: function (sColor) {
  				var sHexColor = "";
  
  				if (!sColor || sColor.toLowerCase().indexOf("hsl") !== -1) {
  					return undefined;
  				}
  
  				// named color
  				if (sColor.indexOf("#") === -1) {
  					return this.NAME_COLORS_TO_RGB_MAP[sColor.toLowerCase()] ? sColor.toLowerCase() : undefined;
  				}
  
  				//HEX value
  				if (sColor.length === 4) {
  					sHexColor = ["#", sColor[1], sColor[1], sColor[2], sColor[2], sColor[3], sColor[3]].join("");
  				} else {
  					sHexColor = sColor;
  				}
  
  				sHexColor = sHexColor.toUpperCase();
  
  				return this.RGB_TO_NAMED_COLORS_MAP[sHexColor];
  			}
  		};
  
  		return ColorPalette;
  	}
  );