@ui5/webcomponents-base 0.0.0-39bd3067f → 0.0.0-4180fe799
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.
- package/.eslintignore +3 -0
- package/CHANGELOG.md +158 -0
- package/README.md +26 -2
- package/bundle.esm.js +16 -7
- package/dist/AssetRegistry.js +8 -6
- package/dist/Boot.js +43 -0
- package/dist/CSP.js +59 -0
- package/dist/CustomElementsRegistry.js +24 -8
- package/dist/CustomElementsScope.js +108 -0
- package/dist/DOMObserver.js +65 -0
- package/dist/Device.js +62 -778
- package/dist/EventProvider.js +38 -26
- package/dist/FontFace.js +19 -62
- package/dist/InitialConfiguration.js +43 -8
- package/dist/Keys.js +89 -2
- package/dist/ManagedStyles.js +83 -0
- package/dist/MediaRange.js +109 -0
- package/dist/PropertiesFileFormat.js +95 -0
- package/dist/Render.js +175 -0
- package/dist/RenderQueue.js +41 -17
- package/dist/RenderScheduler.js +24 -126
- package/dist/StaticArea.js +1 -39
- package/dist/StaticAreaItem.js +56 -63
- package/dist/SystemCSSVars.js +10 -0
- package/dist/Theming.js +2 -1
- package/dist/UI5Element.js +421 -301
- package/dist/UI5ElementMetadata.js +165 -19
- package/dist/asset-registries/Icons.js +129 -14
- package/dist/asset-registries/Illustrations.js +30 -0
- package/dist/asset-registries/LocaleData.js +99 -65
- package/dist/asset-registries/Themes.js +24 -33
- package/dist/asset-registries/i18n.js +72 -30
- package/dist/assets-meta/IconCollectionsAlias.js +18 -0
- package/dist/config/AnimationMode.js +11 -1
- package/dist/config/Language.js +58 -2
- package/dist/config/Theme.js +14 -0
- package/dist/css/FontFace.css +45 -0
- package/dist/css/OverrideFontFace.css +32 -0
- package/dist/css/SystemCSSVars.css +17 -0
- package/dist/delegate/ItemNavigation.js +244 -171
- package/dist/delegate/ResizeHandler.js +78 -38
- package/dist/delegate/ScrollEnablement.js +49 -20
- package/dist/features/OpenUI5Support.js +42 -7
- package/dist/generated/AssetParameters.js +1 -1
- package/dist/generated/css/FontFace.css.js +5 -0
- package/dist/generated/css/OverrideFontFace.css.js +5 -0
- package/dist/generated/css/SystemCSSVars.css.js +5 -0
- package/dist/getSharedResource.js +30 -0
- package/dist/i18nBundle.js +58 -5
- package/dist/isLegacyBrowser.js +3 -0
- package/dist/locale/RTLAwareRegistry.js +14 -0
- package/dist/locale/applyDirection.js +17 -0
- package/dist/locale/directionChange.js +32 -0
- package/dist/locale/getEffectiveDir.js +28 -0
- package/dist/locale/getLocale.js +12 -2
- package/dist/locale/languageChange.js +22 -0
- package/dist/renderer/LitRenderer.js +26 -7
- package/dist/renderer/directives/style-map.js +72 -0
- package/dist/renderer/executeTemplate.js +17 -0
- package/dist/resources/bundle.esm.js +17 -109
- package/dist/resources/bundle.esm.js.map +1 -1
- package/dist/sap/base/Log.js +241 -0
- package/dist/sap/base/assert.js +8 -0
- package/dist/sap/base/security/URLListValidator.js +148 -0
- package/dist/sap/base/security/sanitizeHTML.js +16 -0
- package/dist/sap/base/util/now.js +7 -0
- package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
- package/dist/test-resources/assets/Themes.js +10 -6
- package/dist/test-resources/elements/Parent.js +6 -2
- package/dist/test-resources/elements/WithStaticArea.js +2 -1
- package/dist/test-resources/pages/AllTestElements.html +3 -3
- package/dist/test-resources/pages/Configuration.html +0 -2
- package/dist/test-resources/pages/ConfigurationScript.html +1 -3
- package/dist/test-resources/pages/assets/messagebundle_de.properties +1 -0
- package/dist/test-resources/pages/assets/messagebundle_en.properties +1 -0
- package/dist/test-resources/pages/assets/messagebundle_es.properties +1 -0
- package/dist/test-resources/pages/assets/messagebundle_fr.properties +1 -0
- package/dist/test-resources/pages/i18n.html +33 -0
- package/dist/test-resources/specs/ConfigurationChange.spec.js +11 -9
- package/dist/test-resources/specs/ConfigurationScript.spec.js +25 -23
- package/dist/test-resources/specs/ConfigurationURL.spec.js +65 -17
- package/dist/test-resources/specs/CustomTheme.spec.js +9 -7
- package/dist/test-resources/specs/EventProvider.spec.js +63 -0
- package/dist/test-resources/specs/StaticArea.spec.js +56 -12
- package/dist/test-resources/specs/Theming.spec.js +12 -10
- package/dist/test-resources/specs/UI5ElementInvalidation.js +54 -70
- package/dist/test-resources/specs/UI5ElementLifecycle.js +19 -14
- package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +25 -51
- package/dist/test-resources/specs/UI5ElementMetadataExt.js +9 -7
- package/dist/test-resources/specs/UI5ElementPropertyValidation.js +7 -5
- package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +37 -35
- package/dist/test-resources/specs/UI5ElementShadowDOM.js +10 -8
- package/dist/test-resources/specs/UI5ElementSlots.js +10 -8
- package/dist/theming/CustomStyle.js +28 -7
- package/dist/theming/ThemeLoaded.js +22 -0
- package/dist/theming/applyTheme.js +7 -13
- package/dist/theming/getConstructableStyle.js +15 -10
- package/dist/theming/getEffectiveLinksHrefs.js +20 -0
- package/dist/theming/getEffectiveStyle.js +23 -8
- package/dist/theming/getStylesString.js +15 -0
- package/dist/theming/getThemeDesignerTheme.js +2 -1
- package/dist/theming/preloadLinks.js +23 -0
- package/dist/types/CSSColor.js +9 -0
- package/dist/types/CalendarType.js +1 -1
- package/dist/types/DataType.js +13 -1
- package/dist/types/Float.js +14 -0
- package/dist/types/Integer.js +4 -0
- package/dist/types/InvisibleMessageMode.js +30 -0
- package/dist/types/ItemNavigationBehavior.js +2 -7
- package/dist/types/NavigationMode.js +1 -0
- package/dist/types/PopupState.js +1 -1
- package/dist/types/ValueState.js +1 -1
- package/dist/updateShadowRoot.js +30 -0
- package/dist/util/AriaLabelHelper.js +41 -0
- package/dist/util/Caret.js +45 -0
- package/dist/util/ColorConversion.js +370 -0
- package/dist/util/FocusableElements.js +25 -8
- package/dist/util/HTMLSanitizer.js +7 -0
- package/dist/util/InvisibleMessage.js +58 -0
- package/dist/util/PopupUtils.js +93 -0
- package/dist/util/SlotsHelper.js +43 -0
- package/dist/util/TabbableElements.js +5 -1
- package/dist/util/arraysAreEqual.js +15 -0
- package/dist/util/clamp.js +12 -0
- package/dist/util/createLinkInHead.js +19 -0
- package/dist/util/debounce.js +17 -0
- package/dist/util/encodeCSS.js +24 -0
- package/dist/util/getActiveElement.js +11 -0
- package/dist/util/getClassCopy.js +10 -0
- package/dist/util/getEffectiveContentDensity.js +5 -0
- package/dist/util/getSingletonElementInstance.js +13 -0
- package/dist/util/isElementInView.js +15 -0
- package/dist/util/isNodeHidden.js +1 -5
- package/dist/util/isNodeTabbable.js +4 -4
- package/dist/util/isValidPropertyName.js +9 -3
- package/dist/util/setToArray.js +10 -0
- package/hash.txt +1 -0
- package/index.js +1 -1
- package/lib/generate-asset-parameters/index.js +0 -1
- package/lib/generate-styles/index.js +18 -0
- package/package-scripts.js +37 -19
- package/package.json +19 -12
- package/src/AssetRegistry.js +8 -6
- package/src/Boot.js +43 -0
- package/src/CSP.js +59 -0
- package/src/CustomElementsRegistry.js +24 -8
- package/src/CustomElementsScope.js +108 -0
- package/src/DOMObserver.js +65 -0
- package/src/Device.js +62 -778
- package/src/EventProvider.js +38 -26
- package/src/FontFace.js +19 -62
- package/src/InitialConfiguration.js +43 -8
- package/src/Keys.js +89 -2
- package/src/ManagedStyles.js +83 -0
- package/src/MediaRange.js +109 -0
- package/src/PropertiesFileFormat.js +95 -0
- package/src/Render.js +175 -0
- package/src/RenderQueue.js +41 -17
- package/src/RenderScheduler.js +24 -126
- package/src/StaticArea.js +1 -39
- package/src/StaticAreaItem.js +56 -63
- package/src/SystemCSSVars.js +10 -0
- package/src/Theming.js +2 -1
- package/src/UI5Element.js +421 -301
- package/src/UI5ElementMetadata.js +165 -19
- package/src/asset-registries/Icons.js +129 -14
- package/src/asset-registries/Illustrations.js +30 -0
- package/src/asset-registries/LocaleData.js +99 -65
- package/src/asset-registries/Themes.js +24 -33
- package/src/asset-registries/i18n.js +72 -30
- package/src/assets-meta/IconCollectionsAlias.js +18 -0
- package/src/config/AnimationMode.js +11 -1
- package/src/config/Language.js +58 -2
- package/src/config/Theme.js +14 -0
- package/src/css/FontFace.css +45 -0
- package/src/css/OverrideFontFace.css +32 -0
- package/src/css/SystemCSSVars.css +17 -0
- package/src/delegate/ItemNavigation.js +244 -171
- package/src/delegate/ResizeHandler.js +78 -38
- package/src/delegate/ScrollEnablement.js +49 -20
- package/src/features/OpenUI5Support.js +42 -7
- package/src/getSharedResource.js +30 -0
- package/src/i18nBundle.js +58 -5
- package/src/isLegacyBrowser.js +3 -0
- package/src/locale/RTLAwareRegistry.js +14 -0
- package/src/locale/applyDirection.js +17 -0
- package/src/locale/directionChange.js +32 -0
- package/src/locale/getEffectiveDir.js +28 -0
- package/src/locale/getLocale.js +12 -2
- package/src/locale/languageChange.js +22 -0
- package/src/renderer/LitRenderer.js +26 -7
- package/src/renderer/directives/style-map.js +72 -0
- package/src/renderer/executeTemplate.js +17 -0
- package/src/theming/CustomStyle.js +28 -7
- package/src/theming/ThemeLoaded.js +22 -0
- package/src/theming/applyTheme.js +7 -13
- package/src/theming/getConstructableStyle.js +15 -10
- package/src/theming/getEffectiveLinksHrefs.js +20 -0
- package/src/theming/getEffectiveStyle.js +23 -8
- package/src/theming/getStylesString.js +15 -0
- package/src/theming/getThemeDesignerTheme.js +2 -1
- package/src/theming/preloadLinks.js +23 -0
- package/src/types/CSSColor.js +9 -0
- package/src/types/CalendarType.js +1 -1
- package/src/types/DataType.js +13 -1
- package/src/types/Float.js +14 -0
- package/src/types/Integer.js +4 -0
- package/src/types/InvisibleMessageMode.js +30 -0
- package/src/types/ItemNavigationBehavior.js +2 -7
- package/src/types/NavigationMode.js +1 -0
- package/src/types/PopupState.js +1 -1
- package/src/types/ValueState.js +1 -1
- package/src/updateShadowRoot.js +30 -0
- package/src/util/AriaLabelHelper.js +41 -0
- package/src/util/Caret.js +45 -0
- package/src/util/ColorConversion.js +370 -0
- package/src/util/FocusableElements.js +25 -8
- package/src/util/HTMLSanitizer.js +7 -0
- package/src/util/InvisibleMessage.js +58 -0
- package/src/util/PopupUtils.js +93 -0
- package/src/util/SlotsHelper.js +43 -0
- package/src/util/TabbableElements.js +5 -1
- package/src/util/arraysAreEqual.js +15 -0
- package/src/util/clamp.js +12 -0
- package/src/util/createLinkInHead.js +19 -0
- package/src/util/debounce.js +17 -0
- package/src/util/encodeCSS.js +24 -0
- package/src/util/getActiveElement.js +11 -0
- package/src/util/getClassCopy.js +10 -0
- package/src/util/getEffectiveContentDensity.js +5 -0
- package/src/util/getSingletonElementInstance.js +13 -0
- package/src/util/isElementInView.js +15 -0
- package/src/util/isNodeHidden.js +1 -5
- package/src/util/isNodeTabbable.js +4 -4
- package/src/util/isValidPropertyName.js +9 -3
- package/src/util/setToArray.js +10 -0
- package/used-modules.txt +7 -0
- package/bundle.es5.js +0 -28
- package/dist/SVGIconRegistry.js +0 -60
- package/dist/boot.js +0 -32
- package/dist/compatibility/DOMObserver.js +0 -62
- package/dist/compatibility/patchNodeValue.js +0 -24
- package/dist/compatibility/whenPolyfillLoaded.js +0 -26
- package/dist/delegate/CustomResize.js +0 -78
- package/dist/delegate/NativeResize.js +0 -44
- package/dist/features/browsersupport/Edge.js +0 -6
- package/dist/features/browsersupport/IE11.js +0 -41
- package/dist/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
- package/dist/renderer/ifDefined.js +0 -21
- package/dist/resources/bundle.es5.js +0 -212
- package/dist/resources/bundle.es5.js.map +0 -1
- package/dist/theming/CSSVarsPonyfill.js +0 -24
- package/dist/theming/adaptCSSForIE.js +0 -90
- package/dist/theming/createComponentStyleTag.js +0 -49
- package/dist/theming/createThemePropertiesStyleTag.js +0 -20
- package/dist/thirdparty/Array.from.js +0 -16
- package/dist/thirdparty/Array.prototype.fill.js +0 -44
- package/dist/thirdparty/Array.prototype.find.js +0 -46
- package/dist/thirdparty/Array.prototype.includes.js +0 -51
- package/dist/thirdparty/Element.prototype.closest.js +0 -11
- package/dist/thirdparty/Element.prototype.matches.js +0 -6
- package/dist/thirdparty/Map.prototype.keys.js +0 -9
- package/dist/thirdparty/Number.isInteger.js +0 -5
- package/dist/thirdparty/Number.isNaN.js +0 -1
- package/dist/thirdparty/Number.parseInt.js +0 -1
- package/dist/thirdparty/Object.assign.js +0 -31
- package/dist/thirdparty/Object.entries.js +0 -11
- package/dist/thirdparty/Symbol.js +0 -2
- package/dist/thirdparty/WeakSet.js +0 -27
- package/dist/thirdparty/es6-string-methods.js +0 -182
- package/dist/thirdparty/events-polyfills.js +0 -89
- package/dist/thirdparty/fetch.js +0 -1
- package/dist/thirdparty/template.js +0 -600
- package/dist/thirdparty/webcomponents-sd-ce-pf.js +0 -318
- package/dist/webcomponentsjs/LICENSE.md +0 -19
- package/dist/webcomponentsjs/README.md +0 -229
- package/dist/webcomponentsjs/bundles/webcomponents-ce.js +0 -63
- package/dist/webcomponentsjs/bundles/webcomponents-ce.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js +0 -297
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js +0 -208
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd.js +0 -166
- package/dist/webcomponentsjs/bundles/webcomponents-sd.js.map +0 -1
- package/dist/webcomponentsjs/custom-elements-es5-adapter.js +0 -15
- package/dist/webcomponentsjs/package.json +0 -46
- package/dist/webcomponentsjs/src/entrypoints/custom-elements-es5-adapter-index.js +0 -16
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-bundle-index.js +0 -53
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-ce-index.js +0 -17
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-index.js +0 -19
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-pf-index.js +0 -28
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-index.js +0 -18
- package/dist/webcomponentsjs/webcomponents-bundle.js +0 -298
- package/dist/webcomponentsjs/webcomponents-bundle.js.map +0 -1
- package/dist/webcomponentsjs/webcomponents-loader.js +0 -185
- package/src/SVGIconRegistry.js +0 -60
- package/src/boot.js +0 -32
- package/src/compatibility/DOMObserver.js +0 -62
- package/src/compatibility/patchNodeValue.js +0 -24
- package/src/compatibility/whenPolyfillLoaded.js +0 -26
- package/src/delegate/CustomResize.js +0 -78
- package/src/delegate/NativeResize.js +0 -44
- package/src/features/browsersupport/Edge.js +0 -6
- package/src/features/browsersupport/IE11.js +0 -41
- package/src/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
- package/src/renderer/ifDefined.js +0 -21
- package/src/theming/CSSVarsPonyfill.js +0 -24
- package/src/theming/adaptCSSForIE.js +0 -90
- package/src/theming/createComponentStyleTag.js +0 -49
- package/src/theming/createThemePropertiesStyleTag.js +0 -20
- package/src/thirdparty/Array.from.js +0 -16
- package/src/thirdparty/Array.prototype.fill.js +0 -44
- package/src/thirdparty/Array.prototype.find.js +0 -46
- package/src/thirdparty/Array.prototype.includes.js +0 -51
- package/src/thirdparty/Element.prototype.closest.js +0 -11
- package/src/thirdparty/Element.prototype.matches.js +0 -6
- package/src/thirdparty/Map.prototype.keys.js +0 -9
- package/src/thirdparty/Number.isInteger.js +0 -5
- package/src/thirdparty/Number.isNaN.js +0 -1
- package/src/thirdparty/Number.parseInt.js +0 -1
- package/src/thirdparty/Object.assign.js +0 -31
- package/src/thirdparty/Object.entries.js +0 -11
- package/src/thirdparty/Symbol.js +0 -2
- package/src/thirdparty/WeakSet.js +0 -27
- package/src/thirdparty/es6-string-methods.js +0 -182
- package/src/thirdparty/events-polyfills.js +0 -89
- package/src/thirdparty/fetch.js +0 -1
- package/src/thirdparty/template.js +0 -600
- package/src/thirdparty/webcomponents-sd-ce-pf.js +0 -318
package/dist/UI5Element.js
CHANGED
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
import merge from "./thirdparty/merge.js";
|
|
2
|
-
import boot from "./
|
|
2
|
+
import { boot } from "./Boot.js";
|
|
3
3
|
import UI5ElementMetadata from "./UI5ElementMetadata.js";
|
|
4
|
+
import EventProvider from "./EventProvider.js";
|
|
5
|
+
import getSingletonElementInstance from "./util/getSingletonElementInstance.js";
|
|
4
6
|
import StaticAreaItem from "./StaticAreaItem.js";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
7
|
+
import updateShadowRoot from "./updateShadowRoot.js";
|
|
8
|
+
import { renderDeferred, renderImmediately, cancelRender } from "./Render.js";
|
|
9
|
+
import { registerTag, isTagRegistered, recordTagRegistrationFailure } from "./CustomElementsRegistry.js";
|
|
10
|
+
import { observeDOMNode, unobserveDOMNode } from "./DOMObserver.js";
|
|
8
11
|
import { skipOriginalEvent } from "./config/NoConflict.js";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import getEffectiveStyle from "./theming/getEffectiveStyle.js";
|
|
12
|
-
import Integer from "./types/Integer.js";
|
|
12
|
+
import getEffectiveDir from "./locale/getEffectiveDir.js";
|
|
13
|
+
import DataType from "./types/DataType.js";
|
|
13
14
|
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js";
|
|
14
15
|
import isValidPropertyName from "./util/isValidPropertyName.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
import isDescendantOf from "./util/isDescendantOf.js";
|
|
17
|
+
import { isSlot, getSlotName, getSlottedElementsList } from "./util/SlotsHelper.js";
|
|
18
|
+
import arraysAreEqual from "./util/arraysAreEqual.js";
|
|
19
|
+
import getClassCopy from "./util/getClassCopy.js";
|
|
20
|
+
import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
|
|
21
|
+
import preloadLinks from "./theming/preloadLinks.js";
|
|
21
22
|
|
|
22
23
|
let autoId = 0;
|
|
23
24
|
|
|
24
25
|
const elementTimeouts = new Map();
|
|
26
|
+
const uniqueDependenciesCache = new Map();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Triggers re-rendering of a UI5Element instance due to state change.
|
|
30
|
+
*
|
|
31
|
+
* @param changeInfo An object with information about the change that caused invalidation.
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
function _invalidate(changeInfo) {
|
|
35
|
+
// Invalidation should be suppressed: 1) before the component is rendered for the first time 2) and during the execution of onBeforeRendering
|
|
36
|
+
// This is necessary not only as an optimization, but also to avoid infinite loops on invalidation between children and parents (when invalidateOnChildChange is used)
|
|
37
|
+
if (this._suppressInvalidation) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Call the onInvalidation hook
|
|
42
|
+
this.onInvalidation(changeInfo);
|
|
43
|
+
|
|
44
|
+
this._changedState.push(changeInfo);
|
|
45
|
+
renderDeferred(this);
|
|
46
|
+
this._eventProvider.fireEvent("invalidate", { ...changeInfo, target: this });
|
|
47
|
+
}
|
|
25
48
|
|
|
26
|
-
const GLOBAL_CONTENT_DENSITY_CSS_VAR = "--_ui5_content_density";
|
|
27
49
|
/**
|
|
28
50
|
* Base class for all UI5 Web Components
|
|
29
51
|
*
|
|
@@ -37,56 +59,40 @@ const GLOBAL_CONTENT_DENSITY_CSS_VAR = "--_ui5_content_density";
|
|
|
37
59
|
class UI5Element extends HTMLElement {
|
|
38
60
|
constructor() {
|
|
39
61
|
super();
|
|
40
|
-
this._generateId();
|
|
41
|
-
this._initializeState();
|
|
42
|
-
this._upgradeAllProperties();
|
|
43
|
-
this._initializeContainers();
|
|
44
|
-
this._upToDate = false;
|
|
45
62
|
|
|
63
|
+
this._changedState = []; // Filled on each invalidation, cleared on re-render (used for debugging)
|
|
64
|
+
this._suppressInvalidation = true; // A flag telling whether all invalidations should be ignored. Initialized with "true" because a UI5Element can not be invalidated until it is rendered for the first time
|
|
65
|
+
this._inDOM = false; // A flag telling whether the UI5Element is currently in the DOM tree of the document or not
|
|
66
|
+
this._fullyConnected = false; // A flag telling whether the UI5Element's onEnterDOM hook was called (since it's possible to have the element removed from DOM before that)
|
|
67
|
+
this._childChangeListeners = new Map(); // used to store lazy listeners per slot for the child change event of every child inside that slot
|
|
68
|
+
this._slotChangeListeners = new Map(); // used to store lazy listeners per slot for the slotchange event of all slot children inside that slot
|
|
69
|
+
this._eventProvider = new EventProvider(); // used by parent components for listening to changes to child components
|
|
46
70
|
let deferredResolve;
|
|
47
71
|
this._domRefReadyPromise = new Promise(resolve => {
|
|
48
72
|
deferredResolve = resolve;
|
|
49
73
|
});
|
|
50
74
|
this._domRefReadyPromise._deferredResolve = deferredResolve;
|
|
51
75
|
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
}
|
|
76
|
+
this._initializeState();
|
|
77
|
+
this._upgradeAllProperties();
|
|
55
78
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_generateId() {
|
|
60
|
-
this._id = `ui5wc_${++autoId}`;
|
|
79
|
+
if (this.constructor._needsShadowDOM()) {
|
|
80
|
+
this.attachShadow({ mode: "open" });
|
|
81
|
+
}
|
|
61
82
|
}
|
|
62
83
|
|
|
63
84
|
/**
|
|
64
|
-
*
|
|
85
|
+
* Returns a unique ID for this UI5 Element
|
|
86
|
+
*
|
|
87
|
+
* @deprecated - This property is not guaranteed in future releases
|
|
88
|
+
* @protected
|
|
65
89
|
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// Init Shadow Root
|
|
71
|
-
if (needsShadowDOM) {
|
|
72
|
-
this.attachShadow({ mode: "open" });
|
|
73
|
-
|
|
74
|
-
// IE11, Edge
|
|
75
|
-
if (window.ShadyDOM) {
|
|
76
|
-
createComponentStyleTag(this.constructor);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Chrome
|
|
80
|
-
if (document.adoptedStyleSheets) {
|
|
81
|
-
const style = getConstructableStyle(this.constructor);
|
|
82
|
-
this.shadowRoot.adoptedStyleSheets = [style];
|
|
83
|
-
}
|
|
90
|
+
get _id() {
|
|
91
|
+
if (!this.__id) {
|
|
92
|
+
this.__id = `ui5wc_${++autoId}`;
|
|
84
93
|
}
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
if (needsStaticArea) {
|
|
88
|
-
this.staticAreaItem = new StaticAreaItem(this);
|
|
89
|
-
}
|
|
95
|
+
return this.__id;
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
/**
|
|
@@ -94,26 +100,27 @@ class UI5Element extends HTMLElement {
|
|
|
94
100
|
* @private
|
|
95
101
|
*/
|
|
96
102
|
async connectedCallback() {
|
|
97
|
-
|
|
103
|
+
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
|
|
104
|
+
|
|
98
105
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
if (needsShadowDOM) {
|
|
102
|
-
if (slotsAreManaged) {
|
|
103
|
-
// always register the observer before yielding control to the main thread (await)
|
|
104
|
-
this._startObservingDOMChildren();
|
|
105
|
-
await this._processChildren();
|
|
106
|
-
}
|
|
107
|
+
this._inDOM = true;
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
if (slotsAreManaged) {
|
|
110
|
+
// always register the observer before yielding control to the main thread (await)
|
|
111
|
+
this._startObservingDOMChildren();
|
|
112
|
+
await this._processChildren();
|
|
113
|
+
}
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
if (!this._inDOM) { // Component removed from DOM while _processChildren was running
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
renderImmediately(this);
|
|
120
|
+
this._domRefReadyPromise._deferredResolve();
|
|
121
|
+
this._fullyConnected = true;
|
|
122
|
+
if (typeof this.onEnterDOM === "function") {
|
|
123
|
+
this.onEnterDOM();
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
|
|
@@ -122,23 +129,26 @@ class UI5Element extends HTMLElement {
|
|
|
122
129
|
* @private
|
|
123
130
|
*/
|
|
124
131
|
disconnectedCallback() {
|
|
125
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
126
|
-
const needsStaticArea = this.constructor._needsStaticArea();
|
|
127
132
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
128
133
|
|
|
129
|
-
|
|
130
|
-
if (slotsAreManaged) {
|
|
131
|
-
this._stopObservingDOMChildren();
|
|
132
|
-
}
|
|
134
|
+
this._inDOM = false;
|
|
133
135
|
|
|
136
|
+
if (slotsAreManaged) {
|
|
137
|
+
this._stopObservingDOMChildren();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (this._fullyConnected) {
|
|
134
141
|
if (typeof this.onExitDOM === "function") {
|
|
135
142
|
this.onExitDOM();
|
|
136
143
|
}
|
|
144
|
+
this._fullyConnected = false;
|
|
137
145
|
}
|
|
138
146
|
|
|
139
|
-
if (
|
|
140
|
-
this.staticAreaItem.
|
|
147
|
+
if (this.staticAreaItem && this.staticAreaItem.parentElement) {
|
|
148
|
+
this.staticAreaItem.parentElement.removeChild(this.staticAreaItem);
|
|
141
149
|
}
|
|
150
|
+
|
|
151
|
+
cancelRender(this);
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
/**
|
|
@@ -154,16 +164,16 @@ class UI5Element extends HTMLElement {
|
|
|
154
164
|
const mutationObserverOptions = {
|
|
155
165
|
childList: true,
|
|
156
166
|
subtree: canSlotText,
|
|
157
|
-
characterData:
|
|
167
|
+
characterData: canSlotText,
|
|
158
168
|
};
|
|
159
|
-
|
|
169
|
+
observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
|
|
160
170
|
}
|
|
161
171
|
|
|
162
172
|
/**
|
|
163
173
|
* @private
|
|
164
174
|
*/
|
|
165
175
|
_stopObservingDOMChildren() {
|
|
166
|
-
|
|
176
|
+
unobserveDOMNode(this);
|
|
167
177
|
}
|
|
168
178
|
|
|
169
179
|
/**
|
|
@@ -185,8 +195,14 @@ class UI5Element extends HTMLElement {
|
|
|
185
195
|
const canSlotText = this.constructor.getMetadata().canSlotText();
|
|
186
196
|
const domChildren = Array.from(canSlotText ? this.childNodes : this.children);
|
|
187
197
|
|
|
188
|
-
//
|
|
198
|
+
const slotsCachedContentMap = new Map(); // Store here the content of each slot before the mutation occurred
|
|
199
|
+
const propertyNameToSlotMap = new Map(); // Used for reverse lookup to determine to which slot the property name corresponds
|
|
200
|
+
|
|
201
|
+
// Init the _state object based on the supported slots and store the previous values
|
|
189
202
|
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
|
|
203
|
+
const propertyName = slotData.propertyName || slotName;
|
|
204
|
+
propertyNameToSlotMap.set(propertyName, slotName);
|
|
205
|
+
slotsCachedContentMap.set(propertyName, [...this._state[propertyName]]);
|
|
190
206
|
this._clearSlot(slotName, slotData);
|
|
191
207
|
}
|
|
192
208
|
|
|
@@ -195,7 +211,7 @@ class UI5Element extends HTMLElement {
|
|
|
195
211
|
|
|
196
212
|
const allChildrenUpgraded = domChildren.map(async (child, idx) => {
|
|
197
213
|
// Determine the type of the child (mainly by the slot attribute)
|
|
198
|
-
const slotName =
|
|
214
|
+
const slotName = getSlotName(child);
|
|
199
215
|
const slotData = slotsMap[slotName];
|
|
200
216
|
|
|
201
217
|
// Check if the slotName is supported
|
|
@@ -233,8 +249,14 @@ class UI5Element extends HTMLElement {
|
|
|
233
249
|
|
|
234
250
|
child = this.constructor.getMetadata().constructor.validateSlotValue(child, slotData);
|
|
235
251
|
|
|
236
|
-
if (
|
|
237
|
-
|
|
252
|
+
// Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
|
|
253
|
+
if (child.isUI5Element && slotData.invalidateOnChildChange) {
|
|
254
|
+
child.attachInvalidate(this._getChildChangeListener(slotName));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Listen for the slotchange event if the child is a slot itself
|
|
258
|
+
if (isSlot(child)) {
|
|
259
|
+
this._attachSlotChange(child, slotName);
|
|
238
260
|
}
|
|
239
261
|
|
|
240
262
|
const propertyName = slotData.propertyName || slotName;
|
|
@@ -250,10 +272,33 @@ class UI5Element extends HTMLElement {
|
|
|
250
272
|
|
|
251
273
|
// Distribute the child in the _state object, keeping the Light DOM order,
|
|
252
274
|
// not the order elements are defined.
|
|
253
|
-
slottedChildrenMap.forEach((children,
|
|
254
|
-
this._state[
|
|
275
|
+
slottedChildrenMap.forEach((children, propertyName) => {
|
|
276
|
+
this._state[propertyName] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
|
|
255
277
|
});
|
|
256
|
-
|
|
278
|
+
|
|
279
|
+
// Compare the content of each slot with the cached values and invalidate for the ones that changed
|
|
280
|
+
let invalidated = false;
|
|
281
|
+
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
|
|
282
|
+
const propertyName = slotData.propertyName || slotName;
|
|
283
|
+
if (!arraysAreEqual(slotsCachedContentMap.get(propertyName), this._state[propertyName])) {
|
|
284
|
+
_invalidate.call(this, {
|
|
285
|
+
type: "slot",
|
|
286
|
+
name: propertyNameToSlotMap.get(propertyName),
|
|
287
|
+
reason: "children",
|
|
288
|
+
});
|
|
289
|
+
invalidated = true;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// If none of the slots had an invalidation due to changes to immediate children,
|
|
294
|
+
// the change is considered to be text content of the default slot
|
|
295
|
+
if (!invalidated) {
|
|
296
|
+
_invalidate.call(this, {
|
|
297
|
+
type: "slot",
|
|
298
|
+
name: "default",
|
|
299
|
+
reason: "textcontent",
|
|
300
|
+
});
|
|
301
|
+
}
|
|
257
302
|
}
|
|
258
303
|
|
|
259
304
|
/**
|
|
@@ -262,20 +307,61 @@ class UI5Element extends HTMLElement {
|
|
|
262
307
|
*/
|
|
263
308
|
_clearSlot(slotName, slotData) {
|
|
264
309
|
const propertyName = slotData.propertyName || slotName;
|
|
265
|
-
|
|
266
|
-
let children = this._state[propertyName];
|
|
267
|
-
if (!Array.isArray(children)) {
|
|
268
|
-
children = [children];
|
|
269
|
-
}
|
|
310
|
+
const children = this._state[propertyName];
|
|
270
311
|
|
|
271
312
|
children.forEach(child => {
|
|
272
313
|
if (child && child.isUI5Element) {
|
|
273
|
-
this.
|
|
314
|
+
child.detachInvalidate(this._getChildChangeListener(slotName));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (isSlot(child)) {
|
|
318
|
+
this._detachSlotChange(child, slotName);
|
|
274
319
|
}
|
|
275
320
|
});
|
|
276
321
|
|
|
277
322
|
this._state[propertyName] = [];
|
|
278
|
-
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Attach a callback that will be executed whenever the component is invalidated
|
|
327
|
+
*
|
|
328
|
+
* @param callback
|
|
329
|
+
* @public
|
|
330
|
+
*/
|
|
331
|
+
attachInvalidate(callback) {
|
|
332
|
+
this._eventProvider.attachEvent("invalidate", callback);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Detach the callback that is executed whenever the component is invalidated
|
|
337
|
+
*
|
|
338
|
+
* @param callback
|
|
339
|
+
* @public
|
|
340
|
+
*/
|
|
341
|
+
detachInvalidate(callback) {
|
|
342
|
+
this._eventProvider.detachEvent("invalidate", callback);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Callback that is executed whenever a monitored child changes its state
|
|
347
|
+
*
|
|
348
|
+
* @param slotName the slot in which a child was invalidated
|
|
349
|
+
* @param childChangeInfo the changeInfo object for the child in the given slot
|
|
350
|
+
* @private
|
|
351
|
+
*/
|
|
352
|
+
_onChildChange(slotName, childChangeInfo) {
|
|
353
|
+
if (!this.constructor.getMetadata().shouldInvalidateOnChildChange(slotName, childChangeInfo.type, childChangeInfo.name)) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// The component should be invalidated as this type of change on the child is listened for
|
|
358
|
+
// However, no matter what changed on the child (property/slot), the invalidation is registered as "type=slot" for the component itself
|
|
359
|
+
_invalidate.call(this, {
|
|
360
|
+
type: "slot",
|
|
361
|
+
name: slotName,
|
|
362
|
+
reason: "childchange",
|
|
363
|
+
child: childChangeInfo.target,
|
|
364
|
+
});
|
|
279
365
|
}
|
|
280
366
|
|
|
281
367
|
/**
|
|
@@ -290,9 +376,8 @@ class UI5Element extends HTMLElement {
|
|
|
290
376
|
const propertyTypeClass = properties[nameInCamelCase].type;
|
|
291
377
|
if (propertyTypeClass === Boolean) {
|
|
292
378
|
newValue = newValue !== null;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
newValue = parseInt(newValue);
|
|
379
|
+
} else if (isDescendantOf(propertyTypeClass, DataType)) {
|
|
380
|
+
newValue = propertyTypeClass.attributeToProperty(newValue);
|
|
296
381
|
}
|
|
297
382
|
this[nameInCamelCase] = newValue;
|
|
298
383
|
}
|
|
@@ -305,22 +390,24 @@ class UI5Element extends HTMLElement {
|
|
|
305
390
|
if (!this.constructor.getMetadata().hasAttribute(name)) {
|
|
306
391
|
return;
|
|
307
392
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
393
|
+
const properties = this.constructor.getMetadata().getProperties();
|
|
394
|
+
const propertyTypeClass = properties[name].type;
|
|
313
395
|
const attrName = camelToKebabCase(name);
|
|
314
396
|
const attrValue = this.getAttribute(attrName);
|
|
315
|
-
|
|
397
|
+
|
|
398
|
+
if (propertyTypeClass === Boolean) {
|
|
316
399
|
if (newValue === true && attrValue === null) {
|
|
317
400
|
this.setAttribute(attrName, "");
|
|
318
401
|
} else if (newValue === false && attrValue !== null) {
|
|
319
402
|
this.removeAttribute(attrName);
|
|
320
403
|
}
|
|
321
|
-
} else if (
|
|
322
|
-
this.setAttribute(attrName, newValue);
|
|
323
|
-
}
|
|
404
|
+
} else if (isDescendantOf(propertyTypeClass, DataType)) {
|
|
405
|
+
this.setAttribute(attrName, propertyTypeClass.propertyToAttribute(newValue));
|
|
406
|
+
} else if (typeof newValue !== "object") {
|
|
407
|
+
if (attrValue !== newValue) {
|
|
408
|
+
this.setAttribute(attrName, newValue);
|
|
409
|
+
}
|
|
410
|
+
} // else { return; } // old object handling
|
|
324
411
|
}
|
|
325
412
|
|
|
326
413
|
/**
|
|
@@ -346,101 +433,96 @@ class UI5Element extends HTMLElement {
|
|
|
346
433
|
* @private
|
|
347
434
|
*/
|
|
348
435
|
_initializeState() {
|
|
349
|
-
|
|
350
|
-
this._state = Object.assign({}, defaultState);
|
|
436
|
+
this._state = { ...this.constructor.getMetadata().getInitialState() };
|
|
351
437
|
}
|
|
352
438
|
|
|
353
439
|
/**
|
|
440
|
+
* Returns a singleton event listener for the "change" event of a child in a given slot
|
|
441
|
+
*
|
|
442
|
+
* @param slotName the name of the slot, where the child is
|
|
443
|
+
* @returns {any}
|
|
354
444
|
* @private
|
|
355
445
|
*/
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
slotName
|
|
359
|
-
childProperties = childMetadata.getProperties();
|
|
360
|
-
|
|
361
|
-
let observedProps = [],
|
|
362
|
-
notObservedProps = [];
|
|
363
|
-
|
|
364
|
-
if (Array.isArray(listenFor)) {
|
|
365
|
-
observedProps = listenFor;
|
|
366
|
-
} else {
|
|
367
|
-
observedProps = Array.isArray(listenFor.props) ? listenFor.props : Object.keys(childProperties);
|
|
368
|
-
notObservedProps = Array.isArray(listenFor.exclude) ? listenFor.exclude : [];
|
|
446
|
+
_getChildChangeListener(slotName) {
|
|
447
|
+
if (!this._childChangeListeners.has(slotName)) {
|
|
448
|
+
this._childChangeListeners.set(slotName, this._onChildChange.bind(this, slotName));
|
|
369
449
|
}
|
|
370
|
-
|
|
371
|
-
if (!this._monitoredChildProps.has(slotName)) {
|
|
372
|
-
this._monitoredChildProps.set(slotName, { observedProps, notObservedProps });
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate);
|
|
376
|
-
child._firePropertyChange = true;
|
|
450
|
+
return this._childChangeListeners.get(slotName);
|
|
377
451
|
}
|
|
378
452
|
|
|
379
453
|
/**
|
|
454
|
+
* Returns a singleton slotchange event listener that invalidates the component due to changes in the given slot
|
|
455
|
+
*
|
|
456
|
+
* @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
|
|
457
|
+
* @returns {any}
|
|
380
458
|
* @private
|
|
381
459
|
*/
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
460
|
+
_getSlotChangeListener(slotName) {
|
|
461
|
+
if (!this._slotChangeListeners.has(slotName)) {
|
|
462
|
+
this._slotChangeListeners.set(slotName, this._onSlotChange.bind(this, slotName));
|
|
463
|
+
}
|
|
464
|
+
return this._slotChangeListeners.get(slotName);
|
|
385
465
|
}
|
|
386
466
|
|
|
387
467
|
/**
|
|
388
468
|
* @private
|
|
389
469
|
*/
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (this._firePropertyChange) {
|
|
394
|
-
this.dispatchEvent(new CustomEvent("_propertyChange", {
|
|
395
|
-
detail: { name, newValue: value },
|
|
396
|
-
composed: false,
|
|
397
|
-
bubbles: true,
|
|
398
|
-
}));
|
|
399
|
-
}
|
|
470
|
+
_attachSlotChange(child, slotName) {
|
|
471
|
+
child.addEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
400
472
|
}
|
|
401
473
|
|
|
402
474
|
/**
|
|
403
475
|
* @private
|
|
404
476
|
*/
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const parentNode = this.parentNode;
|
|
408
|
-
if (!parentNode) {
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
const slotName = parentNode.constructor._getSlotName(this);
|
|
413
|
-
const propsMetadata = parentNode._monitoredChildProps.get(slotName);
|
|
414
|
-
|
|
415
|
-
if (!propsMetadata) {
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
const { observedProps, notObservedProps } = propsMetadata;
|
|
419
|
-
|
|
420
|
-
if (observedProps.includes(prop.detail.name) && !notObservedProps.includes(prop.detail.name)) {
|
|
421
|
-
parentNode._invalidate("_parent_", this);
|
|
422
|
-
}
|
|
477
|
+
_detachSlotChange(child, slotName) {
|
|
478
|
+
child.removeEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
423
479
|
}
|
|
424
480
|
|
|
425
481
|
/**
|
|
426
|
-
*
|
|
482
|
+
* Whenever a slot element is slotted inside a UI5 Web Component, its slotchange event invalidates the component
|
|
483
|
+
*
|
|
484
|
+
* @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
|
|
427
485
|
* @private
|
|
428
486
|
*/
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (this.getDomRef() && !this._suppressInvalidation) {
|
|
436
|
-
this._upToDate = false;
|
|
437
|
-
// console.log("INVAL", this, ...arguments);
|
|
438
|
-
RenderScheduler.renderDeferred(this);
|
|
439
|
-
}
|
|
487
|
+
_onSlotChange(slotName) {
|
|
488
|
+
_invalidate.call(this, {
|
|
489
|
+
type: "slot",
|
|
490
|
+
name: slotName,
|
|
491
|
+
reason: "slotchange",
|
|
492
|
+
});
|
|
440
493
|
}
|
|
441
494
|
|
|
442
495
|
/**
|
|
443
|
-
*
|
|
496
|
+
* A callback that is executed each time an already rendered component is invalidated (scheduled for re-rendering)
|
|
497
|
+
*
|
|
498
|
+
* @param changeInfo An object with information about the change that caused invalidation.
|
|
499
|
+
* The object can have the following properties:
|
|
500
|
+
* - type: (property|slot) tells what caused the invalidation
|
|
501
|
+
* 1) property: a property value was changed either directly or as a result of changing the corresponding attribute
|
|
502
|
+
* 2) slot: a slotted node(nodes) changed in one of several ways (see "reason")
|
|
503
|
+
*
|
|
504
|
+
* - name: the name of the property or slot that caused the invalidation
|
|
505
|
+
*
|
|
506
|
+
* - reason: (children|textcontent|childchange|slotchange) relevant only for type="slot" only and tells exactly what changed in the slot
|
|
507
|
+
* 1) children: immediate children (HTML elements or text nodes) were added, removed or reordered in the slot
|
|
508
|
+
* 2) textcontent: text nodes in the slot changed value (or nested text nodes were added or changed value). Can only trigger for slots of "type: Node"
|
|
509
|
+
* 3) slotchange: a slot element, slotted inside that slot had its "slotchange" event listener called. This practically means that transitively slotted children changed.
|
|
510
|
+
* Can only trigger if the child of a slot is a slot element itself.
|
|
511
|
+
* 4) childchange: indicates that a UI5Element child in that slot was invalidated and in turn invalidated the component.
|
|
512
|
+
* Can only trigger for slots with "invalidateOnChildChange" metadata descriptor
|
|
513
|
+
*
|
|
514
|
+
* - newValue: the new value of the property (for type="property" only)
|
|
515
|
+
*
|
|
516
|
+
* - oldValue: the old value of the property (for type="property" only)
|
|
517
|
+
*
|
|
518
|
+
* - child the child that was changed (for type="slot" and reason="childchange" only)
|
|
519
|
+
*
|
|
520
|
+
* @public
|
|
521
|
+
*/
|
|
522
|
+
onInvalidation(changeInfo) {}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Do not call this method directly, only intended to be called by js
|
|
444
526
|
* @protected
|
|
445
527
|
*/
|
|
446
528
|
_render() {
|
|
@@ -459,15 +541,37 @@ class UI5Element extends HTMLElement {
|
|
|
459
541
|
}
|
|
460
542
|
|
|
461
543
|
// resume normal invalidation handling
|
|
462
|
-
|
|
544
|
+
this._suppressInvalidation = false;
|
|
463
545
|
|
|
464
546
|
// Update the shadow root with the render result
|
|
465
|
-
|
|
466
|
-
this.
|
|
467
|
-
|
|
547
|
+
/*
|
|
548
|
+
if (this._changedState.length) {
|
|
549
|
+
let element = this.localName;
|
|
550
|
+
if (this.id) {
|
|
551
|
+
element = `${element}#${this.id}`;
|
|
552
|
+
}
|
|
553
|
+
console.log("Re-rendering:", element, this._changedState.map(x => { // eslint-disable-line
|
|
554
|
+
let res = `${x.type}`;
|
|
555
|
+
if (x.reason) {
|
|
556
|
+
res = `${res}(${x.reason})`;
|
|
557
|
+
}
|
|
558
|
+
res = `${res}: ${x.name}`;
|
|
559
|
+
if (x.type === "property") {
|
|
560
|
+
res = `${res} ${x.oldValue} => ${x.newValue}`;
|
|
561
|
+
}
|
|
468
562
|
|
|
469
|
-
|
|
470
|
-
|
|
563
|
+
return res;
|
|
564
|
+
}));
|
|
565
|
+
}
|
|
566
|
+
*/
|
|
567
|
+
this._changedState = [];
|
|
568
|
+
|
|
569
|
+
// Update shadow root and static area item
|
|
570
|
+
if (this.constructor._needsShadowDOM()) {
|
|
571
|
+
updateShadowRoot(this);
|
|
572
|
+
}
|
|
573
|
+
if (this.staticAreaItem) {
|
|
574
|
+
this.staticAreaItem.update();
|
|
471
575
|
}
|
|
472
576
|
|
|
473
577
|
// Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM
|
|
@@ -481,23 +585,6 @@ class UI5Element extends HTMLElement {
|
|
|
481
585
|
}
|
|
482
586
|
}
|
|
483
587
|
|
|
484
|
-
/**
|
|
485
|
-
* @private
|
|
486
|
-
*/
|
|
487
|
-
_updateShadowRoot() {
|
|
488
|
-
if (!this.constructor._needsShadowDOM()) {
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
let styleToPrepend;
|
|
493
|
-
const renderResult = this.constructor.template(this);
|
|
494
|
-
|
|
495
|
-
if (!document.adoptedStyleSheets && !window.ShadyDOM) {
|
|
496
|
-
styleToPrepend = getEffectiveStyle(this.constructor);
|
|
497
|
-
}
|
|
498
|
-
this.constructor.render(renderResult, this.shadowRoot, styleToPrepend, { eventContext: this });
|
|
499
|
-
}
|
|
500
|
-
|
|
501
588
|
/**
|
|
502
589
|
* @private
|
|
503
590
|
*/
|
|
@@ -520,16 +607,27 @@ class UI5Element extends HTMLElement {
|
|
|
520
607
|
|
|
521
608
|
/**
|
|
522
609
|
* Returns the DOM Element inside the Shadow Root that corresponds to the opening tag in the UI5 Web Component's template
|
|
610
|
+
* *Note:* For logical (abstract) elements (items, options, etc...), returns the part of the parent's DOM that represents this option
|
|
523
611
|
* Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
|
|
612
|
+
*
|
|
524
613
|
* @public
|
|
525
614
|
*/
|
|
526
615
|
getDomRef() {
|
|
616
|
+
// If a component set _getRealDomRef to its children, use the return value of this function
|
|
617
|
+
if (typeof this._getRealDomRef === "function") {
|
|
618
|
+
return this._getRealDomRef();
|
|
619
|
+
}
|
|
620
|
+
|
|
527
621
|
if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
|
|
528
622
|
return;
|
|
529
623
|
}
|
|
530
624
|
|
|
531
|
-
|
|
532
|
-
|
|
625
|
+
const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
|
|
626
|
+
if (children.length !== 1) {
|
|
627
|
+
console.warn(`The shadow DOM for ${this.constructor.getMetadata().getTag()} does not have a top level element, the getDomRef() method might not work as expected`); // eslint-disable-line
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return children[0];
|
|
533
631
|
}
|
|
534
632
|
|
|
535
633
|
/**
|
|
@@ -545,6 +643,16 @@ class UI5Element extends HTMLElement {
|
|
|
545
643
|
}
|
|
546
644
|
}
|
|
547
645
|
|
|
646
|
+
/**
|
|
647
|
+
* Waits for dom ref and then returns the DOM Element marked with "data-sap-focus-ref" inside the template.
|
|
648
|
+
* This is the element that will receive the focus by default.
|
|
649
|
+
* @public
|
|
650
|
+
*/
|
|
651
|
+
async getFocusDomRefAsync() {
|
|
652
|
+
await this._waitForDomRef();
|
|
653
|
+
return this.getFocusDomRef();
|
|
654
|
+
}
|
|
655
|
+
|
|
548
656
|
/**
|
|
549
657
|
* Set the focus to the element, returned by "getFocusDomRef()" (marked by "data-sap-focus-ref")
|
|
550
658
|
* @public
|
|
@@ -565,37 +673,47 @@ class UI5Element extends HTMLElement {
|
|
|
565
673
|
* @param name - name of the event
|
|
566
674
|
* @param data - additional data for the event
|
|
567
675
|
* @param cancelable - true, if the user can call preventDefault on the event object
|
|
676
|
+
* @param bubbles - true, if the event bubbles
|
|
568
677
|
* @returns {boolean} false, if the event was cancelled (preventDefault called), true otherwise
|
|
569
678
|
*/
|
|
570
|
-
fireEvent(name, data, cancelable) {
|
|
571
|
-
|
|
679
|
+
fireEvent(name, data, cancelable = false, bubbles = true) {
|
|
680
|
+
const eventResult = this._fireEvent(name, data, cancelable, bubbles);
|
|
681
|
+
const camelCaseEventName = kebabToCamelCase(name);
|
|
572
682
|
|
|
683
|
+
if (camelCaseEventName !== name) {
|
|
684
|
+
return eventResult && this._fireEvent(camelCaseEventName, data, cancelable);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return eventResult;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
_fireEvent(name, data, cancelable = false, bubbles = true) {
|
|
573
691
|
const noConflictEvent = new CustomEvent(`ui5-${name}`, {
|
|
574
692
|
detail: data,
|
|
575
693
|
composed: false,
|
|
576
|
-
bubbles
|
|
694
|
+
bubbles,
|
|
577
695
|
cancelable,
|
|
578
696
|
});
|
|
579
697
|
|
|
580
|
-
// This will be false if the
|
|
581
|
-
|
|
698
|
+
// This will be false if the no-conflict event is prevented
|
|
699
|
+
const noConflictEventResult = this.dispatchEvent(noConflictEvent);
|
|
582
700
|
|
|
583
701
|
if (skipOriginalEvent(name)) {
|
|
584
|
-
return
|
|
702
|
+
return noConflictEventResult;
|
|
585
703
|
}
|
|
586
704
|
|
|
587
|
-
const
|
|
705
|
+
const normalEvent = new CustomEvent(name, {
|
|
588
706
|
detail: data,
|
|
589
707
|
composed: false,
|
|
590
|
-
bubbles
|
|
708
|
+
bubbles,
|
|
591
709
|
cancelable,
|
|
592
710
|
});
|
|
593
711
|
|
|
594
712
|
// This will be false if the normal event is prevented
|
|
595
|
-
const normalEventResult = this.dispatchEvent(
|
|
713
|
+
const normalEventResult = this.dispatchEvent(normalEvent);
|
|
596
714
|
|
|
597
715
|
// Return false if any of the two events was prevented (its result was false).
|
|
598
|
-
return normalEventResult &&
|
|
716
|
+
return normalEventResult && noConflictEventResult;
|
|
599
717
|
}
|
|
600
718
|
|
|
601
719
|
/**
|
|
@@ -604,24 +722,19 @@ class UI5Element extends HTMLElement {
|
|
|
604
722
|
* @public
|
|
605
723
|
*/
|
|
606
724
|
getSlottedNodes(slotName) {
|
|
607
|
-
|
|
608
|
-
if (curr.localName !== "slot") {
|
|
609
|
-
return acc.concat([curr]);
|
|
610
|
-
}
|
|
611
|
-
return acc.concat(curr.assignedNodes({ flatten: true }).filter(item => item instanceof HTMLElement));
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
return this[slotName].reduce(reducer, []);
|
|
725
|
+
return getSlottedElementsList(this[slotName]);
|
|
615
726
|
}
|
|
616
727
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
728
|
+
/**
|
|
729
|
+
* Determines whether the component should be rendered in RTL mode or not.
|
|
730
|
+
* Returns: "rtl", "ltr" or undefined
|
|
731
|
+
*
|
|
732
|
+
* @public
|
|
733
|
+
* @returns {String|undefined}
|
|
734
|
+
*/
|
|
735
|
+
get effectiveDir() {
|
|
736
|
+
markAsRtlAware(this.constructor); // if a UI5 Element calls this method, it's considered to be rtl-aware
|
|
737
|
+
return getEffectiveDir(this);
|
|
625
738
|
}
|
|
626
739
|
|
|
627
740
|
/**
|
|
@@ -641,26 +754,6 @@ class UI5Element extends HTMLElement {
|
|
|
641
754
|
return this.getMetadata().getAttributesList();
|
|
642
755
|
}
|
|
643
756
|
|
|
644
|
-
/**
|
|
645
|
-
* @private
|
|
646
|
-
*/
|
|
647
|
-
static _getSlotName(child) {
|
|
648
|
-
// Text nodes can only go to the default slot
|
|
649
|
-
if (!(child instanceof HTMLElement)) {
|
|
650
|
-
return "default";
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
|
|
654
|
-
const slot = child.getAttribute("slot");
|
|
655
|
-
if (slot) {
|
|
656
|
-
const match = slot.match(/^(.+?)-\d+$/);
|
|
657
|
-
return match ? match[1] : slot;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Use default slot as a fallback
|
|
661
|
-
return "default";
|
|
662
|
-
}
|
|
663
|
-
|
|
664
757
|
/**
|
|
665
758
|
* @private
|
|
666
759
|
*/
|
|
@@ -668,70 +761,30 @@ class UI5Element extends HTMLElement {
|
|
|
668
761
|
return !!this.template;
|
|
669
762
|
}
|
|
670
763
|
|
|
671
|
-
_shouldUpdateFragment() {
|
|
672
|
-
return this.constructor._needsStaticArea() && this.staticAreaItem.isRendered();
|
|
673
|
-
}
|
|
674
|
-
|
|
675
764
|
/**
|
|
676
765
|
* @private
|
|
677
766
|
*/
|
|
678
767
|
static _needsStaticArea() {
|
|
679
|
-
return
|
|
768
|
+
return !!this.staticAreaTemplate;
|
|
680
769
|
}
|
|
681
770
|
|
|
682
771
|
/**
|
|
683
772
|
* @public
|
|
684
773
|
*/
|
|
685
774
|
getStaticAreaItemDomRef() {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
/**
|
|
690
|
-
* @private
|
|
691
|
-
*/
|
|
692
|
-
static _getDefaultState() {
|
|
693
|
-
if (this._defaultState) {
|
|
694
|
-
return this._defaultState;
|
|
775
|
+
if (!this.constructor._needsStaticArea()) {
|
|
776
|
+
throw new Error("This component does not use the static area");
|
|
695
777
|
}
|
|
696
778
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
// Initialize properties
|
|
702
|
-
const props = MetadataClass.getProperties();
|
|
703
|
-
for (const propName in props) { // eslint-disable-line
|
|
704
|
-
const propType = props[propName].type;
|
|
705
|
-
const propDefaultValue = props[propName].defaultValue;
|
|
706
|
-
|
|
707
|
-
if (propType === Boolean) {
|
|
708
|
-
defaultState[propName] = false;
|
|
709
|
-
|
|
710
|
-
if (propDefaultValue !== undefined) {
|
|
711
|
-
console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line
|
|
712
|
-
}
|
|
713
|
-
} else if (props[propName].multiple) {
|
|
714
|
-
defaultState[propName] = [];
|
|
715
|
-
} else if (propType === Object) {
|
|
716
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {};
|
|
717
|
-
} else if (propType === String) {
|
|
718
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : "";
|
|
719
|
-
} else {
|
|
720
|
-
defaultState[propName] = propDefaultValue;
|
|
721
|
-
}
|
|
779
|
+
if (!this.staticAreaItem) {
|
|
780
|
+
this.staticAreaItem = StaticAreaItem.createInstance();
|
|
781
|
+
this.staticAreaItem.setOwnerElement(this);
|
|
722
782
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
if (slotsAreManaged) {
|
|
726
|
-
const slots = MetadataClass.getSlots();
|
|
727
|
-
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
|
|
728
|
-
const propertyName = slotData.propertyName || slotName;
|
|
729
|
-
defaultState[propertyName] = [];
|
|
730
|
-
}
|
|
783
|
+
if (!this.staticAreaItem.parentElement) {
|
|
784
|
+
getSingletonElementInstance("ui5-static-area").appendChild(this.staticAreaItem);
|
|
731
785
|
}
|
|
732
786
|
|
|
733
|
-
this.
|
|
734
|
-
return defaultState;
|
|
787
|
+
return this.staticAreaItem.getDomRef();
|
|
735
788
|
}
|
|
736
789
|
|
|
737
790
|
/**
|
|
@@ -745,7 +798,7 @@ class UI5Element extends HTMLElement {
|
|
|
745
798
|
const properties = this.getMetadata().getProperties();
|
|
746
799
|
for (const [prop, propData] of Object.entries(properties)) { // eslint-disable-line
|
|
747
800
|
if (!isValidPropertyName(prop)) {
|
|
748
|
-
|
|
801
|
+
console.warn(`"${prop}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
|
|
749
802
|
}
|
|
750
803
|
|
|
751
804
|
if (propData.type === Boolean && propData.defaultValue) {
|
|
@@ -783,14 +836,27 @@ class UI5Element extends HTMLElement {
|
|
|
783
836
|
}
|
|
784
837
|
},
|
|
785
838
|
set(value) {
|
|
839
|
+
let isDifferent;
|
|
786
840
|
value = this.constructor.getMetadata().constructor.validatePropertyValue(value, propData);
|
|
787
841
|
|
|
788
842
|
const oldState = this._state[prop];
|
|
843
|
+
if (propData.multiple && propData.compareValues) {
|
|
844
|
+
isDifferent = !arraysAreEqual(oldState, value);
|
|
845
|
+
} else if (isDescendantOf(propData.type, DataType)) {
|
|
846
|
+
isDifferent = !propData.type.valuesAreEqual(oldState, value);
|
|
847
|
+
} else {
|
|
848
|
+
isDifferent = oldState !== value;
|
|
849
|
+
}
|
|
789
850
|
|
|
790
|
-
if (
|
|
851
|
+
if (isDifferent) {
|
|
791
852
|
this._state[prop] = value;
|
|
792
|
-
|
|
793
|
-
|
|
853
|
+
_invalidate.call(this, {
|
|
854
|
+
type: "property",
|
|
855
|
+
name: prop,
|
|
856
|
+
newValue: value,
|
|
857
|
+
oldValue: oldState,
|
|
858
|
+
});
|
|
859
|
+
this._updateAttribute(prop, value);
|
|
794
860
|
}
|
|
795
861
|
},
|
|
796
862
|
});
|
|
@@ -801,7 +867,7 @@ class UI5Element extends HTMLElement {
|
|
|
801
867
|
const slots = this.getMetadata().getSlots();
|
|
802
868
|
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
|
|
803
869
|
if (!isValidPropertyName(slotName)) {
|
|
804
|
-
|
|
870
|
+
console.warn(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
|
|
805
871
|
}
|
|
806
872
|
|
|
807
873
|
const propertyName = slotData.propertyName || slotName;
|
|
@@ -813,7 +879,7 @@ class UI5Element extends HTMLElement {
|
|
|
813
879
|
return [];
|
|
814
880
|
},
|
|
815
881
|
set() {
|
|
816
|
-
throw new Error("Cannot set
|
|
882
|
+
throw new Error("Cannot set slot content directly, use the DOM APIs (appendChild, removeChild, etc...)");
|
|
817
883
|
},
|
|
818
884
|
});
|
|
819
885
|
}
|
|
@@ -825,7 +891,7 @@ class UI5Element extends HTMLElement {
|
|
|
825
891
|
* @protected
|
|
826
892
|
*/
|
|
827
893
|
static get metadata() {
|
|
828
|
-
return
|
|
894
|
+
return {};
|
|
829
895
|
}
|
|
830
896
|
|
|
831
897
|
/**
|
|
@@ -844,6 +910,50 @@ class UI5Element extends HTMLElement {
|
|
|
844
910
|
return "";
|
|
845
911
|
}
|
|
846
912
|
|
|
913
|
+
/**
|
|
914
|
+
* Returns an array with the dependencies for this UI5 Web Component, which could be:
|
|
915
|
+
* - composed components (used in its shadow root or static area item)
|
|
916
|
+
* - slotted components that the component may need to communicate with
|
|
917
|
+
*
|
|
918
|
+
* @protected
|
|
919
|
+
*/
|
|
920
|
+
static get dependencies() {
|
|
921
|
+
return [];
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Returns a list of the unique dependencies for this UI5 Web Component
|
|
926
|
+
*
|
|
927
|
+
* @public
|
|
928
|
+
*/
|
|
929
|
+
static getUniqueDependencies() {
|
|
930
|
+
if (!uniqueDependenciesCache.has(this)) {
|
|
931
|
+
const filtered = this.dependencies.filter((dep, index, deps) => deps.indexOf(dep) === index);
|
|
932
|
+
uniqueDependenciesCache.set(this, filtered);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return uniqueDependenciesCache.get(this);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Returns a promise that resolves whenever all dependencies for this UI5 Web Component have resolved
|
|
940
|
+
*
|
|
941
|
+
* @returns {Promise<any[]>}
|
|
942
|
+
*/
|
|
943
|
+
static whenDependenciesDefined() {
|
|
944
|
+
return Promise.all(this.getUniqueDependencies().map(dep => dep.define()));
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Hook that will be called upon custom element definition
|
|
949
|
+
*
|
|
950
|
+
* @protected
|
|
951
|
+
* @returns {Promise<void>}
|
|
952
|
+
*/
|
|
953
|
+
static async onDefine() {
|
|
954
|
+
return Promise.resolve();
|
|
955
|
+
}
|
|
956
|
+
|
|
847
957
|
/**
|
|
848
958
|
* Registers a UI5 Web Component in the browser window object
|
|
849
959
|
* @public
|
|
@@ -852,21 +962,31 @@ class UI5Element extends HTMLElement {
|
|
|
852
962
|
static async define() {
|
|
853
963
|
await boot();
|
|
854
964
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
965
|
+
await Promise.all([
|
|
966
|
+
this.whenDependenciesDefined(),
|
|
967
|
+
this.onDefine(),
|
|
968
|
+
]);
|
|
858
969
|
|
|
859
970
|
const tag = this.getMetadata().getTag();
|
|
971
|
+
const altTag = this.getMetadata().getAltTag();
|
|
860
972
|
|
|
861
973
|
const definedLocally = isTagRegistered(tag);
|
|
862
974
|
const definedGlobally = customElements.get(tag);
|
|
863
975
|
|
|
864
976
|
if (definedGlobally && !definedLocally) {
|
|
865
|
-
|
|
977
|
+
recordTagRegistrationFailure(tag);
|
|
866
978
|
} else if (!definedGlobally) {
|
|
867
979
|
this._generateAccessors();
|
|
868
980
|
registerTag(tag);
|
|
869
981
|
window.customElements.define(tag, this);
|
|
982
|
+
preloadLinks(this);
|
|
983
|
+
|
|
984
|
+
if (altTag && !customElements.get(altTag)) {
|
|
985
|
+
registerTag(altTag);
|
|
986
|
+
window.customElements.define(altTag, getClassCopy(this, () => {
|
|
987
|
+
console.log(`The ${altTag} tag is deprecated and will be removed in the next release, please use ${tag} instead.`); // eslint-disable-line
|
|
988
|
+
}));
|
|
989
|
+
}
|
|
870
990
|
}
|
|
871
991
|
return this;
|
|
872
992
|
}
|