UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

228 lines (214 loc) 8.77 kB
/*! * OpenUI5 * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides class sap.ui.core.ComponentSupport sap.ui.define([ 'sap/ui/base/DataType', 'sap/ui/core/ComponentContainer', 'sap/ui/core/library', "sap/base/Log", "sap/base/util/ObjectPath", "sap/base/strings/camelize" ], function( DataType, ComponentContainer, library, Log, ObjectPath, camelize ) { "use strict"; var ComponentLifecycle = library.ComponentLifecycle; var ComponentContainerMetadata = ComponentContainer.getMetadata(); /** * The module <code>sap/ui/core/ComponentSupport</code> provides functionality * which is used to find declared Components in the HTML page and to create * the Component instances which will be put into a {@link sap.ui.core.ComponentContainer}. * * The {@link module:sap/ui/core/ComponentSupport.run} function is called automatically once the module has been required. * This allows declarative support for components. * * <h3>Usage</h3> * To enable the <code>sap/ui/core/ComponentSupport</code> include it as the <code>oninit</code> module in the bootstrap: * <pre> * &lt;script id="sap-ui-bootstrap" * src="/resources/sap-ui-core.js" * ... * data-sap-ui-oninit="module:sap/ui/core/ComponentSupport" * ...> * &lt;/script> * </pre> * * To load and render components inside the HTML page, a special data attribute has to be specified * on the respective DOM elements: <code>data-sap-ui-component</code>. * All DOM elements marked with this data attribute will be regarded as container elements for the created * <code>ComponentContainer</code> instances. * * <pre> * &lt;body id="content" class="sapUiBody sapUiSizeCompact"> * ... * &lt;div data-sap-ui-component * data-id="container" * data-name="sap.ui.core.samples.formatting" * ... * data-handle-validation="true" * ...> * &lt;/div> * ... * &lt;/body> * </pre> * * <h3>Configuration</h3> * All configuration settings for the <code>ComponentContainer</code> have to be defined as <code>data</code> * attributes on the respective HTML tags. * Each data attribute will be interpreted as a setting and parsed considering * the data type of the matching property in the <code>ComponentContainer</code>. * * As HTML is case-insensitive, in order to define a property with upper-case characters, you have to "escape" them * with a dash character, similar to CSS attributes. * The following code gives an example: * * <pre> * &lt;div data-sap-ui-component ... data-handle-validation="true" ...>&lt;/div> * </pre> * * <b>Beware:</b> * * The <code>ComponentSupport</code> module enforces asynchronous loading of the * respective component and its library dependencies. * This is done by applying default settings for the following properties of the <code>ComponentContainer</code>: * * <ul> * <li><code>async</code> {boolean} (<b>forced to <code>true</code></b>)</li> * <li><code>manifest</code> {boolean|string} (<b>forced to <code>true</code> if no string is provided to ensure manifest first</b>)</li> * <li><code>lifecycle</code> {sap.ui.core.ComponentLifecycle} (defaults to <code>Container</code>)</li> * <li><code>autoPrefixId</code> {boolean} (defaults to <code>true</code>)</li> * </ul> * * See {@link topic:82a0fcecc3cb427c91469bc537ebdddf Declarative API for Initial Components}. * * @author SAP SE * @public * @since 1.58.0 * @version 1.87.1 * @namespace * @alias module:sap/ui/core/ComponentSupport */ var ComponentSupport = function() { }; /** * Find all DOM elements with the attribute <code>data-sap-ui-component</code> * and parse the attributes from these DOM elements for the settings of the * <code>ComponentContainer</code> which will be placed into these DOM elements. * * This function is called automatically once the module has been required. * * @public */ ComponentSupport.run = function() { var aElements = ComponentSupport._find(); for (var i = 0, l = aElements.length; i < l; i++) { var oElement = aElements[i]; Log.debug("Parsing element " + oElement.outerHTML, "", "sap/ui/core/ComponentSupport"); var mSettings = ComponentSupport._parse(oElement); ComponentSupport._applyDefaultSettings(mSettings); Log.debug("Creating ComponentContainer with the following settings", JSON.stringify(mSettings, 0, 2), "sap/ui/core/ComponentSupport"); new ComponentContainer(mSettings).placeAt(oElement); // Remove marker so that the element won't be processed again in case "run" is called again oElement.removeAttribute("data-sap-ui-component"); } }; /** * Find all DOM elements with the attribute <code>data-sap-ui-component</code> * and parse the attributes from these DOM elements for the settings of the * <code>ComponentContainer</code> which will be placed into these DOM elements. * * @returns {NodeList} array of <code>Node</code>s * @private */ ComponentSupport._find = function() { return document.querySelectorAll("[data-sap-ui-component]"); }; /** * Parses the attributes of the given DOM element and creates a settings * map. Each attribute starting with <code>data-</code> will be interpret * as setting and be parsed by considering the data type of the matching * property in the <code>ComponentContainer</code>. As HTML is case-insensitive * camel cased properties have to be written in dashed form, e.g. * <code>componentCreated</code> as <code>data-component-created</code>. * * @param {Node} oElement the DOM element to be parsed * @returns {object} settings map * @private */ ComponentSupport._parse = function(oElement) { var mSettings = {}; for (var i = 0, l = oElement.attributes.length; i < l; i++) { var oAttribute = oElement.attributes[i]; // parse every data- property besides data-sap-ui-component var oParsedAttributeName = /^data-((?!sap-ui-component).+)/g.exec(oAttribute.name); if (oParsedAttributeName) { var sKey = camelize(oParsedAttributeName[1]); var oValue = oAttribute.value; // special handling for id property if (sKey !== "id") { var oProperty = ComponentContainerMetadata.getProperty(sKey); var oEvent = !oProperty && ComponentContainerMetadata.getEvent(sKey); if (!oProperty && !oEvent) { Log.warning("Property or event \"" + sKey + "\" will be ignored as it does not exist in sap.ui.core.ComponentContainer"); continue; } if (oProperty) { var oType = DataType.getType(oProperty.type); if (!oType) { throw new Error("Property \"" + oProperty.name + "\" has no known type"); } oValue = oType.parseValue(oValue); } else if (oEvent) { var fnCallback = ObjectPath.get(oValue); if (typeof fnCallback !== "function") { throw new Error("Callback handler for event \"" + oEvent.name + "\" not found"); } oValue = fnCallback; } } mSettings[sKey] = oValue; } } return mSettings; }; /** * Applies the default settings for the <code>ComponentContainer</code> * for some properties such as: * <ul> * <li><code>async</code> {boolean} (<b>forced to <code>true</code></b>)</li> * <li><code>manifest</code> {boolean|string} (<b>forced to <code>true</code> if no string is provided to ensure manifest first</b>)</li> * <li><code>lifecycle</code> {sap.ui.core.ComponentLifecycle} (defaults to <code>Container</code>)</li> * <li><code>autoPrefixId</code> {boolean} (defaults to <code>true</code>)</li> * </ul> * * @param {object} mSettings settings map to be adopted * @private */ ComponentSupport._applyDefaultSettings = function(mSettings) { // force async loading behavior mSettings.async = true; // ignore boolean values for manifest property and force manifest first if (mSettings.manifest === undefined || mSettings.manifest === "true") { mSettings.manifest = true; } else if (mSettings.manifest === "false") { Log.error("Ignoring \"manifest=false\" for ComponentContainer of component \"" + mSettings.name + "\" as it is not supported by ComponentSupport. " + "Forcing \"manifest=true\"", "", "sap/ui/core/ComponentSupport"); mSettings.manifest = true; } // different default value behavior for declarative components mSettings.lifecycle = mSettings.lifecycle === undefined ? ComponentLifecycle.Container : mSettings.lifecycle; mSettings.autoPrefixId = mSettings.autoPrefixId === undefined ? true : mSettings.autoPrefixId; }; // Automatically run once ComponentSupport.run(); return ComponentSupport; });