text: /*!
   * SAP UI development toolkit for HTML5 (SAPUI5/OpenUI5)
   * (c) Copyright 2009-2015 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  // Provides class sap.ui.core.DeclarativeSupport
  sap.ui.define(['jquery.sap.global', 'sap/ui/base/DataType', 'sap/ui/base/ManagedObject', './Control', './CustomData', './HTML', './mvc/View'],
  	function(jQuery, DataType, ManagedObject, Control, CustomData, HTML, View) {
  	"use strict";
  
  
  	/**
  	 * @class Static class for enabling declarative UI support.  
  	 *
  	 * @author Peter Muessig, Tino Butz
  	 * @version 1.28.10
  	 * @since 1.7.0
  	 * @public
  	 * @alias sap.ui.core.DeclarativeSupport
  	 */
  	var DeclarativeSupport = {
  	};
  
  
  	/**
  	 * Defines the attributes of an element that should be handled differently.
  	 * Set key/value pairs. The key indicates the attribute. The value can be of type <code>Boolean</code> or <code>Function</code>.
  	 * When the value is of type <code>Function</code> it will receive three arguments: 
  	 * <code>sValue</code> the value of the attribute,
  	 * <code>mSettings</code> the settings of the control
  	 * <code>fnClass</code> the control class
  	 * @private
  	 */
  	DeclarativeSupport.attributes = {
  		"data-sap-ui-type" : true,
  		"data-sap-ui-id" : true,
  		"data-sap-ui-aggregation" : true,
  		"data-sap-ui-default-aggregation" : true,
  		"data-sap-ui-binding" : function(sValue, mSettings) {
  			var oBindingInfo = ManagedObject.bindingParser(sValue);
  			// TODO reject complex bindings, types, formatters; enable 'parameters'? 
  			mSettings.objectBindings = mSettings.objectBindings || {};
  			mSettings.objectBindings[oBindingInfo.model || undefined] = oBindingInfo;
  		},
  		"data-tooltip" : function(sValue, mSettings) {
  			// special handling for tooltip (which is an aggregation)
  			// but can also be applied as property
  			mSettings["tooltip"] = sValue;
  		},
  		"tooltip" : function(sValue, mSettings, fnClass) {
  			// TODO: Remove this key / value when deprecation is removed
  			mSettings["tooltip"] = sValue;
  			jQuery.sap.log.warning('[Deprecated] Control "' + mSettings.id + '": The attribute "tooltip" is not prefixed with "data-*". Future version of declarative support will only suppport attributes with "data-*" prefix.');
  		},
  		"class":true,
  		"style" : true,
  		"id" : true
  	};
  
  
  	/**
  	 * Enhances the given DOM element by parsing the Control and Elements info and creating
  	 * the SAPUI5 controls for them.
  	 * 
  	 * @param {Element} oElement the DOM element to compile
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use
  	 * @param {boolean} [isRecursive] Whether the call of the function is recursive.
  	 * @public
  	 */
  	DeclarativeSupport.compile = function(oElement, oView, isRecursive) {
  		// Find all defined classes
  		var that = this;
  		jQuery(oElement).find("[data-sap-ui-type]").filter(function() {
  			return jQuery(this).parents("[data-sap-ui-type]").length === 0;
  		}).each(function() {
  			that._compile(this, oView, isRecursive);
  		});
  	};
  
  
  
  	/**
  	 * Enhances the given element by parsing the attributes and child elements.
  	 * 
  	 * @param {Element} oElement the element to compile
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use
  	 * @param {boolean} [isRecursive] Whether the call of the function is recursive.
  	 * @private
  	 */
  	DeclarativeSupport._compile = function(oElement, oView, isRecursive) {
  		var $element = jQuery(oElement);
  
  		var sType = $element.attr("data-sap-ui-type");
  		var aControls = [];
  		var bIsUIArea = sType === "sap.ui.core.UIArea";
  
  		if (bIsUIArea) {
  			// use a UIArea / better performance when rendering multiple controls
  			// parse and create the controls / children of element
  			var that = this;
  			$element.children().each(function() {
  				var oControl = that._createControl(this, oView);
  				if (oControl) {
  					aControls.push(oControl);
  				}
  			});
  		} else {
  			var oControl = this._createControl(oElement, oView);
  			if (oControl) {
  				aControls.push(oControl);
  			}
  		}
  
  		// remove the old content
  		$element.empty();
  
  		// in case of the root control is not a UIArea we remove all HTML attributes
  		// for a UIArea we remove only the data HTML attributes and keep the others
  		// also marks the control as parsed (by removing data-sap-ui-type) 
  		var aAttr = [];
  		jQuery.each(oElement.attributes, function(iIndex, oAttr) {
  			var sName = oAttr.name;
  			if (!bIsUIArea || bIsUIArea && /^data-/g.test(sName.toLowerCase())) {
  				aAttr.push(sName);
  			}
  		});
  		if (aAttr.length > 0) {
  			$element.removeAttr(aAttr.join(" "));
  		}
  
  		// add the controls
  		jQuery.each(aControls, function(vKey, oControl) {
  			if (oControl instanceof Control) {
  				if (oView && !isRecursive) {
  					oView.addContent(oControl);
  				} else {
  					oControl.placeAt(oElement);
  					if (oView) {
  						// Remember the unassociated control so that it can be destroyed on exit of the view
  						oView.connectControl(oControl);
  					}
  				}
  			}
  		});
  	};
  
  
  
  	/**
  	 * Parses a given DOM ref and converts it into a Control.
  	 * @param {Element} oElement reference to a DOM element
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use.
  	 * @return {sap.ui.core.Control} reference to a Control
  	 * @private
  	 */
  	DeclarativeSupport._createControl = function(oElement, oView) {
  		var $element = jQuery(oElement);
  
  		var oControl = null;
  
  		var sType = $element.attr("data-sap-ui-type");
  		if (sType) {
  			jQuery.sap.require(sType); // make sure fnClass.getMatadata() is available
  			var fnClass = jQuery.sap.getObject(sType);
  			jQuery.sap.assert(typeof fnClass !== "undefined", "Class not found: " + sType);
  
  
  			var mSettings = {};
  			mSettings.id = this._getId($element, oView);
  			this._addSettingsForAttributes(mSettings, fnClass, oElement, oView);
  			this._addSettingsForAggregations(mSettings, fnClass, oElement, oView);
  
  			var oControl;
  			if (View.prototype.isPrototypeOf(fnClass.prototype) && typeof fnClass._sType === "string") {
  				// for views having a factory function defined we use the factory function!
  				oControl = sap.ui.view(mSettings, undefined, fnClass._sType);
  			} else {
  				oControl = new fnClass(mSettings);
  			}
  
  			if (oElement.className) {
  				oControl.addStyleClass(oElement.className);
  			}
  
  			// mark control as parsed
  			$element.removeAttr("data-sap-ui-type");
  
  		} else {
  			oControl = this._createHtmlControl(oElement, oView);
  		}
  
  		return oControl;
  	};
  
  
  	/**
  	 * Parses a given DOM ref and converts it into a HTMLControl.
  	 * @param {Element} oElement reference to a DOM element
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use.
  	 * @return {sap.ui.core.HTML} reference to a Control
  	 * @private
  	 */
  	DeclarativeSupport._createHtmlControl = function(oElement, oView) {
  		//include HTML content
  		var oHTML = new HTML();
  		oHTML.setDOMContent(oElement);
  		// check for declarative content
  		this.compile(oElement, oView, true);
  		return oHTML;
  	};
  
  
  	/**
  	 * Adds all defined attributes to the settings object of a control.
  	 * 
  	 * @param {object} mSettings reference of the settings of the control
  	 * @param {function} fnClass reference to a Class
  	 * @param {Element} oElement reference to a DOM element
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use.
  	 * @return {object} the settings of the control.
  	 * @throws {Error} if an attribute is not supported
  	 * @private
  	 */
  	DeclarativeSupport._addSettingsForAttributes = function(mSettings, fnClass, oElement, oView) {
  		var that = this;
  		var oSpecialAttributes = DeclarativeSupport.attributes;
  		var fnBindingParser = ManagedObject.bindingParser;
  		var aCustomData = [];
  		var reCustomData = /^data-custom-data:(.+)/i;
  
  		jQuery.each(oElement.attributes, function(iIndex, oAttr) {
  			var sName = oAttr.name;
  			var sValue = oAttr.value;
  
  			if (!reCustomData.test(sName)) {
  
  				// no custom data attribute:
  
  				if (typeof oSpecialAttributes[sName] === "undefined") {
  					sName = that.convertAttributeToSettingName(sName, mSettings.id);
  					var oProperty = that._getProperty(fnClass, sName);
  					if (oProperty) {
  						var oBindingInfo = fnBindingParser(sValue, oView && oView.getController(), true );
  						if ( oBindingInfo && typeof oBindingInfo === "object" ) {
  							mSettings[sName] = oBindingInfo;
  						} else {
  							mSettings[sName] = that.convertValueToType(that.getPropertyDataType(oProperty), oBindingInfo || sValue);
  						}
  					} else if (that._getAssociation(fnClass, sName)) {
  						var oAssociation = that._getAssociation(fnClass, sName);
  						if (oAssociation.multiple) {
  							// we support "," and " " to split between IDs
  							sValue = sValue.replace(/\s*,\s*|\s+/g, ","); // normalize strings: "id1  ,    id2    id3" to "id1,id2,id3"
  							var aId = sValue.split(","); // split array for all ","
  							jQuery.each(aId, function(iIndex, sId) {
  								aId[iIndex] = oView ? oView.createId(sId) : sId;
  							});
  							mSettings[sName] = aId;
  						} else {
  							mSettings[sName] = oView ? oView.createId(sValue) : sValue; // use the value as ID
  						}
  					} else if (that._getAggregation(fnClass, sName)) {
  						var oAggregation = that._getAggregation(fnClass, sName);
  						if (oAggregation.multiple) {
  							var oBindingInfo = fnBindingParser(sValue, oView && oView.getController());
  							if (oBindingInfo) {
  								mSettings[sName] = oBindingInfo;
  							} else {
  								throw new Error("Aggregation " + sName + " with cardinality 0..n only allows binding paths as attribute value");
  							}
  						} else if (oAggregation.altTypes) {
  							var oBindingInfo = fnBindingParser(sValue, oView && oView.getController(), true);
  							if ( oBindingInfo && typeof oBindingInfo === "object" ) {
  								mSettings[sName] = oBindingInfo;
  							} else {
  								mSettings[sName] = that.convertValueToType(oAggregation.altTypes[0], oBindingInfo || sValue);
  							}
  						} else {
  							throw new Error("Aggregation " + sName + " not supported");
  						}
  					} else if (that._getEvent(fnClass, sName)) {
  						var oController = oView && (oView._oContainingView || oView).getController();
  						var vHandler = View._resolveEventHandler(sValue, oController);
  						if ( vHandler ) {
  							mSettings[sName] = vHandler;
  						} else {
  							throw new Error('Control "' + mSettings.id + '": The function "' + sValue + '" for the event "' + sName + '" is not defined');
  						}
  					} else {
  						jQuery.sap.assert((sName === "id"), "DeclarativeSupport encountered unknown setting '" + sName + "' for class '" + fnClass.getMetadata().getName() + "' (value:'" + sValue + "')");
  					}
  				} else if (typeof oSpecialAttributes[sName] === "function") {
  					oSpecialAttributes[sName](sValue, mSettings, fnClass);
  				}
  
  			} else {
  
  				// custom data handling:
  
  				// determine the key of the custom data entry
  				sName = jQuery.sap.camelCase(reCustomData.exec(sName)[1]);
  
  				// create a binding info object if necessary
  				var oBindingInfo = fnBindingParser(sValue, oView && oView.getController());
  
  				// create the custom data object
  				aCustomData.push(new CustomData({
  					key: sName,
  					value: oBindingInfo || sValue
  				}));
  
  			}
  
  		});
  
  		if (aCustomData.length > 0) {
  			mSettings.customData = aCustomData;
  		}
  
  		return mSettings;
  	};
  
  
  	/**
  	 * Adds all defined aggregations to the settings object of a control.
  	 * 
  	 * @param {object} mSettings reference of the settings of the control
  	 * @param {function} fnClass reference to a Class
  	 * @param {Element} oElement reference to a DOM element
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use.
  	 * @return {object} the settings of the control.
  	 * @private
  	 */
  	DeclarativeSupport._addSettingsForAggregations = function(mSettings, fnClass, oElement, oView) {
  		var $element = jQuery(oElement);
  
  		var sDefaultAggregation = this._getDefaultAggregation(fnClass, oElement);
  
  		var that = this;
  		var oAggregations = fnClass.getMetadata().getAllAggregations();
  
  		$element.children().each(function() {
  			// check for an aggregation tag of in case of a sepcifiying the
  			// aggregration on the parent control this will be used in case
  			// of no meta tag was found
  			var $child = jQuery(this);
  			var sAggregation = $child.attr("data-sap-ui-aggregation");
  			var sType = $child.attr("data-sap-ui-type");
  
  			var bUseDefault = false;
  			if (!sAggregation) {
  				bUseDefault = true;
  				sAggregation = sDefaultAggregation;
  			}
  
  			// add the child to the aggregation
  			if (sAggregation && oAggregations[sAggregation]) {
  				var bMultiple = oAggregations[sAggregation].multiple;
  
  				var addControl = function(oChildElement) {
  					var oControl = that._createControl(oChildElement, oView);
  					if (oControl) {
  						if (bMultiple) {
  							// 1..n AGGREGATION
  							if (!mSettings[sAggregation]) {
  								mSettings[sAggregation] = [];
  							}
  							if ( typeof mSettings[sAggregation].path === "string" ) {
  								jQuery.sap.assert(!mSettings[sAggregation].template, "list bindings support only a single template object");
  								mSettings[sAggregation].template = oControl;
  							} else {
  								mSettings[sAggregation].push(oControl);
  							}
  
  						} else {
  							// 1..1 AGGREGATION
  							mSettings[sAggregation] = oControl;
  						}
  					}
  				};
  
  				if (bUseDefault || (sType && !bUseDefault)) {
  					addControl(this);
  				} else {
  					$child.children().each(function() {
  						addControl(this);
  					});
  				}
  			}
  
  			$child.removeAttr("data-sap-ui-aggregation");
  			$child.removeAttr("data-sap-ui-type");
  		});
  		return mSettings;
  
  	};
  
  
  	/**
  	 * Returns the id of the element.
  	 *
  	 * @param {Element} oElement reference to a DOM element
  	 * @param {sap.ui.core.mvc.HTMLView} [oView] The view instance to use.
  	 * @return {string} the id of the element
  	 * @private
  	 */
  	DeclarativeSupport._getId = function(oElement, oView) {
  		var $element = jQuery(oElement);
  		var sId = $element.attr("id");
  		if (sId) {
  			if (oView) {
  				sId = oView.createId(sId);
  				// Remember the id for the HTMLView rendering method. This is needed to replace the placeholder div with the actual
  				// control HTML (Do not use ID as Firefox even finds detached IDs)
  				$element.attr("data-sap-ui-id", sId);
  			}
  			// in case of having an ID retrieve it and clear it in the placeholder
  			// DOM element to avoid double IDs
  			$element.attr("id", "");
  		}
  		return sId;
  	};
  
  
  	/**
  	 * Returns the property of a given class and property name.
  	 *
  	 * @param {function} fnClass reference to a Class
  	 * @param {string} sName the name of the property
  	 * @return {object} reference to the property object
  	 * @private
  	 */
  	DeclarativeSupport._getProperty = function(fnClass, sName) {
  		return fnClass.getMetadata().getProperty(sName);
  	};
  
  
  	/**
  	 * Converts a given value to the right property type.
  	 *
  	 * @param {object} oType the type of the value
  	 * @param {string} sValue the value to convert
  	 * @return {string} the converted value
  	 * @private
  	 */
  	DeclarativeSupport.convertValueToType = function(oType, sValue) {
  		if (oType instanceof DataType) {
  			sValue = oType.parseValue(sValue);
  		}
  		// else return original sValue (e.g. for enums)
  		// Note: to avoid double resolution of binding expressions, we have to escape string values once again 
  		return typeof sValue === "string" ? ManagedObject.bindingParser.escape(sValue) : sValue;
  	};
  
  
  	/**
  	 * Returns the data type object for a certain property.
  	 *
  	 * @param {object} oProperty reference to the property object
  	 * @return {object} the type of the property
  	 * @throws {Error} if no type for the property is found
  	 * @private
  	 */
  	DeclarativeSupport.getPropertyDataType = function(oProperty) {
  		var oType = DataType.getType(oProperty.type);
  		if (!oType) {
  			throw new Error("Property " + oProperty.name + " has no known type");
  		}
  		return oType;
  	};
  
  
  
  	/**
  	 * Returns the settings name for a given html attribute (converts data-my-setting to mySetting)
  	 *
  	 * @param {string} sAttribute the name of the attribute
  	 * @param {string} sId the id of the control
  	 * @param {boolean} bDeprecationWarning whether to show a deprecation warning or not
  	 * @return {string} the settings name
  	 * @private
  	 */
  	DeclarativeSupport.convertAttributeToSettingName = function(sAttribute, sId, bDeprecationWarning) {
  		if (sAttribute.indexOf("data-") === 0) {
  			sAttribute = sAttribute.substr(5);
  		} else if (bDeprecationWarning) {
  			jQuery.sap.log.warning('[Deprecated] Control "' + sId + '": The attribute "' + sAttribute + '" is not prefixed with "data-*". Future version of declarative support will only suppport attributes with "data-*" prefix.');
  		} else {
  			throw new Error('Control "' + sId + '": The attribute "' + sAttribute + '" is not prefixed with "data-*".');
  		}
  		return jQuery.sap.camelCase(sAttribute);
  	};
  
  
  	/**
  	 * Returns the association of a given class and association name.
  	 *
  	 * @param {function} fnClass reference to a Class
  	 * @param {string} sName the name of the association
  	 * @return {object} reference to the association object
  	 * @private
  	 */
  	DeclarativeSupport._getAssociation = function(fnClass, sName) {
  		return fnClass.getMetadata().getAssociation(sName);
  	};
  
  	/**
  	 * Returns the aggregations of a given class and aggregation name.
  	 *
  	 * @param {function} fnClass reference to a Class
  	 * @param {string} sName the name of the association
  	 * @return {object} reference to the association object
  	 * @private
  	 */
  	DeclarativeSupport._getAggregation = function(fnClass, sName) {
  		return fnClass.getMetadata().getAggregation(sName);
  	};
  
  
  	/**
  	 * Returns the event of a given class and event name.
  	 *
  	 * @param {function} fnClass reference to a Class
  	 * @param {string} sName the name of the event
  	 * @return {object} reference to the event object
  	 * @private
  	 */
  	DeclarativeSupport._getEvent = function(fnClass, sName) {
  		return fnClass.getMetadata().getEvent(sName);
  	};
  
  
  	/**
  	 * Returns the default aggregation of the control.
  	 *
  	 * @param {function} fnClass reference to a Class
  	 * @param {Element} oElement reference to a DOM element
  	 * @return {string} the default aggregation
  	 * @private
  	 */
  	DeclarativeSupport._getDefaultAggregation = function(fnClass, oElement) {
  		var $element = jQuery(oElement);
  		var sDefaultAggregation = $element.attr("data-sap-ui-default-aggregation") || fnClass.getMetadata().getDefaultAggregationName();
  		$element.removeAttr("data-sap-ui-default-aggregation");
  		return sDefaultAggregation;
  	};
  
  
  	return DeclarativeSupport;
  
  }, /* bExport= */ true);
  