@ui5/webcomponents-base 0.0.0-306572ffa → 0.0.0-35e2c9666
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 +242 -0
- package/README.md +26 -2
- package/bundle.esm.js +13 -11
- package/dist/AssetRegistry.js +8 -7
- package/dist/Boot.js +59 -0
- package/dist/CSP.js +59 -0
- package/dist/CustomElementsRegistry.js +60 -4
- package/dist/DOMObserver.js +65 -0
- package/dist/Device.js +69 -776
- package/dist/EventProvider.js +30 -26
- package/dist/FeaturesRegistry.js +4 -1
- package/dist/FontFace.js +19 -62
- package/dist/InitialConfiguration.js +43 -8
- package/dist/Keys.js +107 -0
- package/dist/ManagedStyles.js +83 -0
- package/dist/MediaRange.js +109 -0
- package/{src/util/parseProperties.js → dist/PropertiesFileFormat.js} +6 -0
- package/dist/Render.js +175 -0
- package/dist/RenderScheduler.js +16 -138
- package/dist/Runtimes.js +107 -0
- package/dist/StaticArea.js +1 -29
- package/dist/StaticAreaItem.js +58 -65
- package/dist/SystemCSSVars.js +4 -25
- package/dist/Theming.js +2 -1
- package/dist/UI5Element.js +310 -365
- package/dist/UI5ElementMetadata.js +131 -16
- package/dist/asset-registries/Icons.js +121 -13
- package/dist/asset-registries/Illustrations.js +30 -0
- package/dist/asset-registries/LocaleData.js +105 -66
- package/dist/asset-registries/Themes.js +23 -32
- package/dist/asset-registries/i18n.js +62 -48
- package/dist/assets-meta/IconCollectionsAlias.js +18 -0
- package/dist/config/Language.js +33 -6
- package/dist/config/Theme.js +25 -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 +239 -170
- package/dist/delegate/ResizeHandler.js +78 -37
- package/dist/delegate/ScrollEnablement.js +49 -20
- package/dist/features/F6Navigation.js +108 -0
- package/dist/features/OpenUI5Support.js +41 -6
- package/dist/generated/AssetParameters.js +1 -1
- package/dist/generated/VersionInfo.js +10 -0
- 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/i18nBundle.js +38 -4
- package/dist/isLegacyBrowser.js +3 -0
- package/dist/locale/applyDirection.js +6 -4
- 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 +1 -1
- package/dist/renderer/LitRenderer.js +24 -21
- package/dist/renderer/directives/style-map.js +72 -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/encodeCSS.js +14 -0
- package/dist/sap/base/security/encodeXML.js +23 -0
- package/dist/sap/base/security/sanitizeHTML.js +16 -0
- package/dist/sap/base/strings/toHex.js +8 -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 +8 -8
- 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 +0 -2
- package/dist/test-resources/pages/i18n.html +2 -9
- package/dist/test-resources/specs/ConfigurationChange.spec.js +10 -8
- 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 +17 -15
- 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 +25 -5
- package/dist/theming/ThemeLoaded.js +22 -0
- package/dist/theming/applyTheme.js +13 -15
- package/dist/theming/getConstructableStyle.js +7 -6
- package/dist/theming/getEffectiveLinksHrefs.js +20 -0
- package/dist/theming/getEffectiveStyle.js +15 -8
- package/dist/theming/getStylesString.js +4 -2
- package/dist/theming/getThemeDesignerTheme.js +25 -5
- 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 +4 -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/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 +22 -9
- package/dist/util/HTMLSanitizer.js +7 -0
- package/dist/util/InvisibleMessage.js +60 -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/escapeRegex.js +10 -0
- package/dist/util/generateHighlightedMarkup.js +42 -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/isElementInView.js +15 -0
- package/dist/util/isNodeHidden.js +1 -1
- package/dist/util/isNodeTabbable.js +4 -4
- package/dist/util/isValidPropertyName.js +4 -2
- 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/lib/generate-version-info/index.js +27 -0
- package/package-scripts.js +34 -19
- package/package.json +19 -13
- package/src/AssetRegistry.js +8 -7
- package/src/Boot.js +59 -0
- package/src/CSP.js +59 -0
- package/src/CustomElementsRegistry.js +60 -4
- package/src/DOMObserver.js +65 -0
- package/src/Device.js +69 -776
- package/src/EventProvider.js +30 -26
- package/src/FeaturesRegistry.js +4 -1
- package/src/FontFace.js +19 -62
- package/src/InitialConfiguration.js +43 -8
- package/src/Keys.js +107 -0
- package/src/ManagedStyles.js +83 -0
- package/src/MediaRange.js +109 -0
- package/{dist/util/parseProperties.js → src/PropertiesFileFormat.js} +6 -0
- package/src/Render.js +175 -0
- package/src/RenderScheduler.js +16 -138
- package/src/Runtimes.js +107 -0
- package/src/StaticArea.js +1 -29
- package/src/StaticAreaItem.js +58 -65
- package/src/SystemCSSVars.js +4 -25
- package/src/Theming.js +2 -1
- package/src/UI5Element.js +310 -365
- package/src/UI5ElementMetadata.js +131 -16
- package/src/asset-registries/Icons.js +121 -13
- package/src/asset-registries/Illustrations.js +30 -0
- package/src/asset-registries/LocaleData.js +105 -66
- package/src/asset-registries/Themes.js +23 -32
- package/src/asset-registries/i18n.js +62 -48
- package/src/assets-meta/IconCollectionsAlias.js +18 -0
- package/src/config/Language.js +33 -6
- package/src/config/Theme.js +25 -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 +239 -170
- package/src/delegate/ResizeHandler.js +78 -37
- package/src/delegate/ScrollEnablement.js +49 -20
- package/src/features/F6Navigation.js +108 -0
- package/src/features/OpenUI5Support.js +41 -6
- package/src/i18nBundle.js +38 -4
- package/src/isLegacyBrowser.js +3 -0
- package/src/locale/applyDirection.js +6 -4
- 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 +1 -1
- package/src/renderer/LitRenderer.js +24 -21
- package/src/renderer/directives/style-map.js +72 -0
- package/src/theming/CustomStyle.js +25 -5
- package/src/theming/ThemeLoaded.js +22 -0
- package/src/theming/applyTheme.js +13 -15
- package/src/theming/getConstructableStyle.js +7 -6
- package/src/theming/getEffectiveLinksHrefs.js +20 -0
- package/src/theming/getEffectiveStyle.js +15 -8
- package/src/theming/getStylesString.js +4 -2
- package/src/theming/getThemeDesignerTheme.js +25 -5
- 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 +4 -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/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 +22 -9
- package/src/util/HTMLSanitizer.js +7 -0
- package/src/util/InvisibleMessage.js +60 -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/escapeRegex.js +10 -0
- package/src/util/generateHighlightedMarkup.js +42 -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/isElementInView.js +15 -0
- package/src/util/isNodeHidden.js +1 -1
- package/src/util/isNodeTabbable.js +4 -4
- package/src/util/isValidPropertyName.js +4 -2
- package/used-modules.txt +10 -0
- package/bundle.es5.js +0 -28
- package/dist/SVGIconRegistry.js +0 -62
- package/dist/boot.js +0 -34
- 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/PropertiesFormatSupport.js +0 -8
- 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/renderer/scopeHTML.js +0 -32
- 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 -95
- package/dist/theming/createComponentStyleTag.js +0 -55
- 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/util/getEffectiveAriaLabelText.js +0 -28
- package/dist/util/isSlot.js +0 -3
- 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 -62
- package/src/boot.js +0 -34
- 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/PropertiesFormatSupport.js +0 -8
- 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/renderer/scopeHTML.js +0 -32
- package/src/theming/CSSVarsPonyfill.js +0 -24
- package/src/theming/adaptCSSForIE.js +0 -95
- package/src/theming/createComponentStyleTag.js +0 -55
- 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/src/util/getEffectiveAriaLabelText.js +0 -28
- package/src/util/isSlot.js +0 -3
package/dist/UI5Element.js
CHANGED
|
@@ -1,36 +1,50 @@
|
|
|
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
|
|
4
|
+
import EventProvider from "./EventProvider.js";
|
|
5
|
+
import getSingletonElementInstance from "./util/getSingletonElementInstance.js";
|
|
5
6
|
import StaticAreaItem from "./StaticAreaItem.js";
|
|
6
|
-
import
|
|
7
|
+
import updateShadowRoot from "./updateShadowRoot.js";
|
|
8
|
+
import { renderDeferred, renderImmediately, cancelRender } from "./Render.js";
|
|
7
9
|
import { registerTag, isTagRegistered, recordTagRegistrationFailure } from "./CustomElementsRegistry.js";
|
|
8
|
-
import
|
|
10
|
+
import { observeDOMNode, unobserveDOMNode } from "./DOMObserver.js";
|
|
9
11
|
import { skipOriginalEvent } from "./config/NoConflict.js";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import createComponentStyleTag from "./theming/createComponentStyleTag.js";
|
|
13
|
-
import getEffectiveStyle from "./theming/getEffectiveStyle.js";
|
|
14
|
-
import Integer from "./types/Integer.js";
|
|
15
|
-
import Float from "./types/Float.js";
|
|
12
|
+
import getEffectiveDir from "./locale/getEffectiveDir.js";
|
|
13
|
+
import DataType from "./types/DataType.js";
|
|
16
14
|
import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js";
|
|
17
15
|
import isValidPropertyName from "./util/isValidPropertyName.js";
|
|
18
|
-
import
|
|
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";
|
|
19
20
|
import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
|
|
20
|
-
|
|
21
|
-
const metadata = {
|
|
22
|
-
events: {
|
|
23
|
-
"_property-change": {},
|
|
24
|
-
},
|
|
25
|
-
};
|
|
21
|
+
import preloadLinks from "./theming/preloadLinks.js";
|
|
26
22
|
|
|
27
23
|
let autoId = 0;
|
|
28
24
|
|
|
29
25
|
const elementTimeouts = new Map();
|
|
30
26
|
const uniqueDependenciesCache = new Map();
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
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
|
+
}
|
|
34
48
|
|
|
35
49
|
/**
|
|
36
50
|
* Base class for all UI5 Web Components
|
|
@@ -45,22 +59,26 @@ const GLOBAL_DIR_CSS_VAR = "--_ui5_dir";
|
|
|
45
59
|
class UI5Element extends HTMLElement {
|
|
46
60
|
constructor() {
|
|
47
61
|
super();
|
|
48
|
-
this._initializeState();
|
|
49
|
-
this._upgradeAllProperties();
|
|
50
|
-
this._initializeContainers();
|
|
51
|
-
this._upToDate = false;
|
|
52
|
-
this._inDOM = false;
|
|
53
|
-
this._fullyConnected = false;
|
|
54
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
|
|
55
70
|
let deferredResolve;
|
|
56
71
|
this._domRefReadyPromise = new Promise(resolve => {
|
|
57
72
|
deferredResolve = resolve;
|
|
58
73
|
});
|
|
59
74
|
this._domRefReadyPromise._deferredResolve = deferredResolve;
|
|
60
75
|
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
|
|
76
|
+
this._initializeState();
|
|
77
|
+
this._upgradeAllProperties();
|
|
78
|
+
|
|
79
|
+
if (this.constructor._needsShadowDOM()) {
|
|
80
|
+
this.attachShadow({ mode: "open" });
|
|
81
|
+
}
|
|
64
82
|
}
|
|
65
83
|
|
|
66
84
|
/**
|
|
@@ -77,32 +95,16 @@ class UI5Element extends HTMLElement {
|
|
|
77
95
|
return this.__id;
|
|
78
96
|
}
|
|
79
97
|
|
|
80
|
-
/**
|
|
81
|
-
* @private
|
|
82
|
-
*/
|
|
83
|
-
_initializeContainers() {
|
|
84
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
85
|
-
const needsStaticArea = this.constructor._needsStaticArea();
|
|
86
|
-
|
|
87
|
-
// Init Shadow Root
|
|
88
|
-
if (needsShadowDOM) {
|
|
89
|
-
this.attachShadow({ mode: "open" });
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Init StaticAreaItem only if needed
|
|
93
|
-
if (needsStaticArea) {
|
|
94
|
-
this.staticAreaItem = new StaticAreaItem(this);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
98
|
/**
|
|
99
99
|
* Do not call this method from derivatives of UI5Element, use "onEnterDOM" only
|
|
100
100
|
* @private
|
|
101
101
|
*/
|
|
102
102
|
async connectedCallback() {
|
|
103
103
|
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
|
|
104
|
+
if (this.constructor.getMetadata().supportsF6FastNavigation()) {
|
|
105
|
+
this.setAttribute("data-sap-ui-fastnavgroup", "true");
|
|
106
|
+
}
|
|
104
107
|
|
|
105
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
106
108
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
107
109
|
|
|
108
110
|
this._inDOM = true;
|
|
@@ -113,23 +115,15 @@ class UI5Element extends HTMLElement {
|
|
|
113
115
|
await this._processChildren();
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
await Promise.resolve();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!this._inDOM) { // Component removed from DOM while _processChildren was running
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
118
|
+
if (!this._inDOM) { // Component removed from DOM while _processChildren was running
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.onEnterDOM();
|
|
132
|
-
}
|
|
122
|
+
renderImmediately(this);
|
|
123
|
+
this._domRefReadyPromise._deferredResolve();
|
|
124
|
+
this._fullyConnected = true;
|
|
125
|
+
if (typeof this.onEnterDOM === "function") {
|
|
126
|
+
this.onEnterDOM();
|
|
133
127
|
}
|
|
134
128
|
}
|
|
135
129
|
|
|
@@ -138,8 +132,6 @@ class UI5Element extends HTMLElement {
|
|
|
138
132
|
* @private
|
|
139
133
|
*/
|
|
140
134
|
disconnectedCallback() {
|
|
141
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
142
|
-
const needsStaticArea = this.constructor._needsStaticArea();
|
|
143
135
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
144
136
|
|
|
145
137
|
this._inDOM = false;
|
|
@@ -148,21 +140,18 @@ class UI5Element extends HTMLElement {
|
|
|
148
140
|
this._stopObservingDOMChildren();
|
|
149
141
|
}
|
|
150
142
|
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (typeof this.onExitDOM === "function") {
|
|
155
|
-
this.onExitDOM();
|
|
156
|
-
}
|
|
157
|
-
this._fullyConnected = false;
|
|
143
|
+
if (this._fullyConnected) {
|
|
144
|
+
if (typeof this.onExitDOM === "function") {
|
|
145
|
+
this.onExitDOM();
|
|
158
146
|
}
|
|
147
|
+
this._fullyConnected = false;
|
|
159
148
|
}
|
|
160
149
|
|
|
161
|
-
if (
|
|
162
|
-
this.staticAreaItem.
|
|
150
|
+
if (this.staticAreaItem && this.staticAreaItem.parentElement) {
|
|
151
|
+
this.staticAreaItem.parentElement.removeChild(this.staticAreaItem);
|
|
163
152
|
}
|
|
164
153
|
|
|
165
|
-
|
|
154
|
+
cancelRender(this);
|
|
166
155
|
}
|
|
167
156
|
|
|
168
157
|
/**
|
|
@@ -178,16 +167,16 @@ class UI5Element extends HTMLElement {
|
|
|
178
167
|
const mutationObserverOptions = {
|
|
179
168
|
childList: true,
|
|
180
169
|
subtree: canSlotText,
|
|
181
|
-
characterData:
|
|
170
|
+
characterData: canSlotText,
|
|
182
171
|
};
|
|
183
|
-
|
|
172
|
+
observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
|
|
184
173
|
}
|
|
185
174
|
|
|
186
175
|
/**
|
|
187
176
|
* @private
|
|
188
177
|
*/
|
|
189
178
|
_stopObservingDOMChildren() {
|
|
190
|
-
|
|
179
|
+
unobserveDOMNode(this);
|
|
191
180
|
}
|
|
192
181
|
|
|
193
182
|
/**
|
|
@@ -209,8 +198,14 @@ class UI5Element extends HTMLElement {
|
|
|
209
198
|
const canSlotText = this.constructor.getMetadata().canSlotText();
|
|
210
199
|
const domChildren = Array.from(canSlotText ? this.childNodes : this.children);
|
|
211
200
|
|
|
212
|
-
//
|
|
201
|
+
const slotsCachedContentMap = new Map(); // Store here the content of each slot before the mutation occurred
|
|
202
|
+
const propertyNameToSlotMap = new Map(); // Used for reverse lookup to determine to which slot the property name corresponds
|
|
203
|
+
|
|
204
|
+
// Init the _state object based on the supported slots and store the previous values
|
|
213
205
|
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
|
|
206
|
+
const propertyName = slotData.propertyName || slotName;
|
|
207
|
+
propertyNameToSlotMap.set(propertyName, slotName);
|
|
208
|
+
slotsCachedContentMap.set(propertyName, [...this._state[propertyName]]);
|
|
214
209
|
this._clearSlot(slotName, slotData);
|
|
215
210
|
}
|
|
216
211
|
|
|
@@ -219,7 +214,7 @@ class UI5Element extends HTMLElement {
|
|
|
219
214
|
|
|
220
215
|
const allChildrenUpgraded = domChildren.map(async (child, idx) => {
|
|
221
216
|
// Determine the type of the child (mainly by the slot attribute)
|
|
222
|
-
const slotName =
|
|
217
|
+
const slotName = getSlotName(child);
|
|
223
218
|
const slotData = slotsMap[slotName];
|
|
224
219
|
|
|
225
220
|
// Check if the slotName is supported
|
|
@@ -257,16 +252,15 @@ class UI5Element extends HTMLElement {
|
|
|
257
252
|
|
|
258
253
|
child = this.constructor.getMetadata().constructor.validateSlotValue(child, slotData);
|
|
259
254
|
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (child.isUI5Element && slotData.invalidateParent) {
|
|
265
|
-
child._shouldInvalidateParent = true;
|
|
255
|
+
// Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
|
|
256
|
+
if (child.isUI5Element && slotData.invalidateOnChildChange) {
|
|
257
|
+
const method = (child.attachInvalidate || child._attachChange).bind(child);
|
|
258
|
+
method(this._getChildChangeListener(slotName));
|
|
266
259
|
}
|
|
267
260
|
|
|
261
|
+
// Listen for the slotchange event if the child is a slot itself
|
|
268
262
|
if (isSlot(child)) {
|
|
269
|
-
this._attachSlotChange(child);
|
|
263
|
+
this._attachSlotChange(child, slotName);
|
|
270
264
|
}
|
|
271
265
|
|
|
272
266
|
const propertyName = slotData.propertyName || slotName;
|
|
@@ -282,10 +276,33 @@ class UI5Element extends HTMLElement {
|
|
|
282
276
|
|
|
283
277
|
// Distribute the child in the _state object, keeping the Light DOM order,
|
|
284
278
|
// not the order elements are defined.
|
|
285
|
-
slottedChildrenMap.forEach((children,
|
|
286
|
-
this._state[
|
|
279
|
+
slottedChildrenMap.forEach((children, propertyName) => {
|
|
280
|
+
this._state[propertyName] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
|
|
287
281
|
});
|
|
288
|
-
|
|
282
|
+
|
|
283
|
+
// Compare the content of each slot with the cached values and invalidate for the ones that changed
|
|
284
|
+
let invalidated = false;
|
|
285
|
+
for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
|
|
286
|
+
const propertyName = slotData.propertyName || slotName;
|
|
287
|
+
if (!arraysAreEqual(slotsCachedContentMap.get(propertyName), this._state[propertyName])) {
|
|
288
|
+
_invalidate.call(this, {
|
|
289
|
+
type: "slot",
|
|
290
|
+
name: propertyNameToSlotMap.get(propertyName),
|
|
291
|
+
reason: "children",
|
|
292
|
+
});
|
|
293
|
+
invalidated = true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// If none of the slots had an invalidation due to changes to immediate children,
|
|
298
|
+
// the change is considered to be text content of the default slot
|
|
299
|
+
if (!invalidated) {
|
|
300
|
+
_invalidate.call(this, {
|
|
301
|
+
type: "slot",
|
|
302
|
+
name: "default",
|
|
303
|
+
reason: "textcontent",
|
|
304
|
+
});
|
|
305
|
+
}
|
|
289
306
|
}
|
|
290
307
|
|
|
291
308
|
/**
|
|
@@ -294,25 +311,62 @@ class UI5Element extends HTMLElement {
|
|
|
294
311
|
*/
|
|
295
312
|
_clearSlot(slotName, slotData) {
|
|
296
313
|
const propertyName = slotData.propertyName || slotName;
|
|
297
|
-
|
|
298
|
-
let children = this._state[propertyName];
|
|
299
|
-
if (!Array.isArray(children)) {
|
|
300
|
-
children = [children];
|
|
301
|
-
}
|
|
314
|
+
const children = this._state[propertyName];
|
|
302
315
|
|
|
303
316
|
children.forEach(child => {
|
|
304
317
|
if (child && child.isUI5Element) {
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
const method = (child.detachInvalidate || child._detachChange).bind(child);
|
|
319
|
+
method(this._getChildChangeListener(slotName));
|
|
307
320
|
}
|
|
308
321
|
|
|
309
322
|
if (isSlot(child)) {
|
|
310
|
-
this._detachSlotChange(child);
|
|
323
|
+
this._detachSlotChange(child, slotName);
|
|
311
324
|
}
|
|
312
325
|
});
|
|
313
326
|
|
|
314
327
|
this._state[propertyName] = [];
|
|
315
|
-
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Attach a callback that will be executed whenever the component is invalidated
|
|
332
|
+
*
|
|
333
|
+
* @param callback
|
|
334
|
+
* @public
|
|
335
|
+
*/
|
|
336
|
+
attachInvalidate(callback) {
|
|
337
|
+
this._eventProvider.attachEvent("invalidate", callback);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Detach the callback that is executed whenever the component is invalidated
|
|
342
|
+
*
|
|
343
|
+
* @param callback
|
|
344
|
+
* @public
|
|
345
|
+
*/
|
|
346
|
+
detachInvalidate(callback) {
|
|
347
|
+
this._eventProvider.detachEvent("invalidate", callback);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Callback that is executed whenever a monitored child changes its state
|
|
352
|
+
*
|
|
353
|
+
* @param slotName the slot in which a child was invalidated
|
|
354
|
+
* @param childChangeInfo the changeInfo object for the child in the given slot
|
|
355
|
+
* @private
|
|
356
|
+
*/
|
|
357
|
+
_onChildChange(slotName, childChangeInfo) {
|
|
358
|
+
if (!this.constructor.getMetadata().shouldInvalidateOnChildChange(slotName, childChangeInfo.type, childChangeInfo.name)) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// The component should be invalidated as this type of change on the child is listened for
|
|
363
|
+
// However, no matter what changed on the child (property/slot), the invalidation is registered as "type=slot" for the component itself
|
|
364
|
+
_invalidate.call(this, {
|
|
365
|
+
type: "slot",
|
|
366
|
+
name: slotName,
|
|
367
|
+
reason: "childchange",
|
|
368
|
+
child: childChangeInfo.target,
|
|
369
|
+
});
|
|
316
370
|
}
|
|
317
371
|
|
|
318
372
|
/**
|
|
@@ -327,12 +381,8 @@ class UI5Element extends HTMLElement {
|
|
|
327
381
|
const propertyTypeClass = properties[nameInCamelCase].type;
|
|
328
382
|
if (propertyTypeClass === Boolean) {
|
|
329
383
|
newValue = newValue !== null;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
newValue = parseInt(newValue);
|
|
333
|
-
}
|
|
334
|
-
if (propertyTypeClass === Float) {
|
|
335
|
-
newValue = parseFloat(newValue);
|
|
384
|
+
} else if (isDescendantOf(propertyTypeClass, DataType)) {
|
|
385
|
+
newValue = propertyTypeClass.attributeToProperty(newValue);
|
|
336
386
|
}
|
|
337
387
|
this[nameInCamelCase] = newValue;
|
|
338
388
|
}
|
|
@@ -345,22 +395,24 @@ class UI5Element extends HTMLElement {
|
|
|
345
395
|
if (!this.constructor.getMetadata().hasAttribute(name)) {
|
|
346
396
|
return;
|
|
347
397
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
|
|
398
|
+
const properties = this.constructor.getMetadata().getProperties();
|
|
399
|
+
const propertyTypeClass = properties[name].type;
|
|
353
400
|
const attrName = camelToKebabCase(name);
|
|
354
401
|
const attrValue = this.getAttribute(attrName);
|
|
355
|
-
|
|
402
|
+
|
|
403
|
+
if (propertyTypeClass === Boolean) {
|
|
356
404
|
if (newValue === true && attrValue === null) {
|
|
357
405
|
this.setAttribute(attrName, "");
|
|
358
406
|
} else if (newValue === false && attrValue !== null) {
|
|
359
407
|
this.removeAttribute(attrName);
|
|
360
408
|
}
|
|
361
|
-
} else if (
|
|
362
|
-
this.setAttribute(attrName, newValue);
|
|
363
|
-
}
|
|
409
|
+
} else if (isDescendantOf(propertyTypeClass, DataType)) {
|
|
410
|
+
this.setAttribute(attrName, propertyTypeClass.propertyToAttribute(newValue));
|
|
411
|
+
} else if (typeof newValue !== "object") {
|
|
412
|
+
if (attrValue !== newValue) {
|
|
413
|
+
this.setAttribute(attrName, newValue);
|
|
414
|
+
}
|
|
415
|
+
} // else { return; } // old object handling
|
|
364
416
|
}
|
|
365
417
|
|
|
366
418
|
/**
|
|
@@ -386,124 +438,96 @@ class UI5Element extends HTMLElement {
|
|
|
386
438
|
* @private
|
|
387
439
|
*/
|
|
388
440
|
_initializeState() {
|
|
389
|
-
|
|
390
|
-
this._state = Object.assign({}, defaultState);
|
|
441
|
+
this._state = { ...this.constructor.getMetadata().getInitialState() };
|
|
391
442
|
}
|
|
392
443
|
|
|
393
444
|
/**
|
|
445
|
+
* Returns a singleton event listener for the "change" event of a child in a given slot
|
|
446
|
+
*
|
|
447
|
+
* @param slotName the name of the slot, where the child is
|
|
448
|
+
* @returns {any}
|
|
394
449
|
* @private
|
|
395
450
|
*/
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
slotName
|
|
399
|
-
childProperties = childMetadata.getProperties();
|
|
400
|
-
|
|
401
|
-
let observedProps = [],
|
|
402
|
-
notObservedProps = [];
|
|
403
|
-
|
|
404
|
-
if (Array.isArray(listenFor)) {
|
|
405
|
-
observedProps = listenFor;
|
|
406
|
-
} else {
|
|
407
|
-
observedProps = Array.isArray(listenFor.props) ? listenFor.props : Object.keys(childProperties);
|
|
408
|
-
notObservedProps = Array.isArray(listenFor.exclude) ? listenFor.exclude : [];
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (!this._monitoredChildProps.has(slotName)) {
|
|
412
|
-
this._monitoredChildProps.set(slotName, { observedProps, notObservedProps });
|
|
451
|
+
_getChildChangeListener(slotName) {
|
|
452
|
+
if (!this._childChangeListeners.has(slotName)) {
|
|
453
|
+
this._childChangeListeners.set(slotName, this._onChildChange.bind(this, slotName));
|
|
413
454
|
}
|
|
414
|
-
|
|
415
|
-
child.addEventListener("_property-change", this._invalidateParentOnPropertyUpdate);
|
|
416
|
-
child._firePropertyChange = true;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* @private
|
|
421
|
-
*/
|
|
422
|
-
_detachChildPropertyUpdated(child) {
|
|
423
|
-
child.removeEventListener("_property-change", this._invalidateParentOnPropertyUpdate);
|
|
424
|
-
child._firePropertyChange = false;
|
|
455
|
+
return this._childChangeListeners.get(slotName);
|
|
425
456
|
}
|
|
426
457
|
|
|
427
458
|
/**
|
|
459
|
+
* Returns a singleton slotchange event listener that invalidates the component due to changes in the given slot
|
|
460
|
+
*
|
|
461
|
+
* @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
|
|
462
|
+
* @returns {any}
|
|
428
463
|
* @private
|
|
429
464
|
*/
|
|
430
|
-
|
|
431
|
-
this.
|
|
432
|
-
|
|
433
|
-
if (this._firePropertyChange) {
|
|
434
|
-
this.dispatchEvent(new CustomEvent("_property-change", {
|
|
435
|
-
detail: { name, newValue: value },
|
|
436
|
-
composed: false,
|
|
437
|
-
bubbles: true,
|
|
438
|
-
}));
|
|
465
|
+
_getSlotChangeListener(slotName) {
|
|
466
|
+
if (!this._slotChangeListeners.has(slotName)) {
|
|
467
|
+
this._slotChangeListeners.set(slotName, this._onSlotChange.bind(this, slotName));
|
|
439
468
|
}
|
|
469
|
+
return this._slotChangeListeners.get(slotName);
|
|
440
470
|
}
|
|
441
471
|
|
|
442
472
|
/**
|
|
443
473
|
* @private
|
|
444
474
|
*/
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const parentNode = this.parentNode;
|
|
448
|
-
if (!parentNode) {
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const slotName = parentNode.constructor._getSlotName(this);
|
|
453
|
-
const propsMetadata = parentNode._monitoredChildProps.get(slotName);
|
|
454
|
-
|
|
455
|
-
if (!propsMetadata) {
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
const { observedProps, notObservedProps } = propsMetadata;
|
|
459
|
-
|
|
460
|
-
if (observedProps.includes(prop.detail.name) && !notObservedProps.includes(prop.detail.name)) {
|
|
461
|
-
parentNode._invalidate("_parent_", this);
|
|
462
|
-
}
|
|
475
|
+
_attachSlotChange(child, slotName) {
|
|
476
|
+
child.addEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
463
477
|
}
|
|
464
478
|
|
|
465
479
|
/**
|
|
466
480
|
* @private
|
|
467
481
|
*/
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
this._invalidateOnSlotChange = () => {
|
|
471
|
-
this._invalidate("slotchange");
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
child.addEventListener("slotchange", this._invalidateOnSlotChange);
|
|
482
|
+
_detachSlotChange(child, slotName) {
|
|
483
|
+
child.removeEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
475
484
|
}
|
|
476
485
|
|
|
477
486
|
/**
|
|
487
|
+
* Whenever a slot element is slotted inside a UI5 Web Component, its slotchange event invalidates the component
|
|
488
|
+
*
|
|
489
|
+
* @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
|
|
478
490
|
* @private
|
|
479
491
|
*/
|
|
480
|
-
|
|
481
|
-
|
|
492
|
+
_onSlotChange(slotName) {
|
|
493
|
+
_invalidate.call(this, {
|
|
494
|
+
type: "slot",
|
|
495
|
+
name: slotName,
|
|
496
|
+
reason: "slotchange",
|
|
497
|
+
});
|
|
482
498
|
}
|
|
483
499
|
|
|
484
500
|
/**
|
|
485
|
-
*
|
|
486
|
-
*
|
|
501
|
+
* A callback that is executed each time an already rendered component is invalidated (scheduled for re-rendering)
|
|
502
|
+
*
|
|
503
|
+
* @param changeInfo An object with information about the change that caused invalidation.
|
|
504
|
+
* The object can have the following properties:
|
|
505
|
+
* - type: (property|slot) tells what caused the invalidation
|
|
506
|
+
* 1) property: a property value was changed either directly or as a result of changing the corresponding attribute
|
|
507
|
+
* 2) slot: a slotted node(nodes) changed in one of several ways (see "reason")
|
|
508
|
+
*
|
|
509
|
+
* - name: the name of the property or slot that caused the invalidation
|
|
510
|
+
*
|
|
511
|
+
* - reason: (children|textcontent|childchange|slotchange) relevant only for type="slot" only and tells exactly what changed in the slot
|
|
512
|
+
* 1) children: immediate children (HTML elements or text nodes) were added, removed or reordered in the slot
|
|
513
|
+
* 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"
|
|
514
|
+
* 3) slotchange: a slot element, slotted inside that slot had its "slotchange" event listener called. This practically means that transitively slotted children changed.
|
|
515
|
+
* Can only trigger if the child of a slot is a slot element itself.
|
|
516
|
+
* 4) childchange: indicates that a UI5Element child in that slot was invalidated and in turn invalidated the component.
|
|
517
|
+
* Can only trigger for slots with "invalidateOnChildChange" metadata descriptor
|
|
518
|
+
*
|
|
519
|
+
* - newValue: the new value of the property (for type="property" only)
|
|
520
|
+
*
|
|
521
|
+
* - oldValue: the old value of the property (for type="property" only)
|
|
522
|
+
*
|
|
523
|
+
* - child the child that was changed (for type="slot" and reason="childchange" only)
|
|
524
|
+
*
|
|
525
|
+
* @public
|
|
487
526
|
*/
|
|
488
|
-
|
|
489
|
-
if (this._shouldInvalidateParent) {
|
|
490
|
-
this.parentNode._invalidate();
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
if (!this._upToDate) {
|
|
494
|
-
// console.log("already invalidated", this, ...arguments);
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
if (this.getDomRef() && !this._suppressInvalidation) {
|
|
499
|
-
this._upToDate = false;
|
|
500
|
-
// console.log("INVAL", this, ...arguments);
|
|
501
|
-
RenderScheduler.renderDeferred(this);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
527
|
+
onInvalidation(changeInfo) {}
|
|
504
528
|
|
|
505
529
|
/**
|
|
506
|
-
* Do not call this method directly, only intended to be called by
|
|
530
|
+
* Do not call this method directly, only intended to be called by js
|
|
507
531
|
* @protected
|
|
508
532
|
*/
|
|
509
533
|
_render() {
|
|
@@ -522,15 +546,37 @@ class UI5Element extends HTMLElement {
|
|
|
522
546
|
}
|
|
523
547
|
|
|
524
548
|
// resume normal invalidation handling
|
|
525
|
-
|
|
549
|
+
this._suppressInvalidation = false;
|
|
526
550
|
|
|
527
551
|
// Update the shadow root with the render result
|
|
528
|
-
|
|
529
|
-
this.
|
|
530
|
-
|
|
552
|
+
/*
|
|
553
|
+
if (this._changedState.length) {
|
|
554
|
+
let element = this.localName;
|
|
555
|
+
if (this.id) {
|
|
556
|
+
element = `${element}#${this.id}`;
|
|
557
|
+
}
|
|
558
|
+
console.log("Re-rendering:", element, this._changedState.map(x => { // eslint-disable-line
|
|
559
|
+
let res = `${x.type}`;
|
|
560
|
+
if (x.reason) {
|
|
561
|
+
res = `${res}(${x.reason})`;
|
|
562
|
+
}
|
|
563
|
+
res = `${res}: ${x.name}`;
|
|
564
|
+
if (x.type === "property") {
|
|
565
|
+
res = `${res} ${x.oldValue} => ${x.newValue}`;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return res;
|
|
569
|
+
}));
|
|
570
|
+
}
|
|
571
|
+
*/
|
|
572
|
+
this._changedState = [];
|
|
531
573
|
|
|
532
|
-
|
|
533
|
-
|
|
574
|
+
// Update shadow root and static area item
|
|
575
|
+
if (this.constructor._needsShadowDOM()) {
|
|
576
|
+
updateShadowRoot(this);
|
|
577
|
+
}
|
|
578
|
+
if (this.staticAreaItem) {
|
|
579
|
+
this.staticAreaItem.update();
|
|
534
580
|
}
|
|
535
581
|
|
|
536
582
|
// Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM
|
|
@@ -544,35 +590,6 @@ class UI5Element extends HTMLElement {
|
|
|
544
590
|
}
|
|
545
591
|
}
|
|
546
592
|
|
|
547
|
-
/**
|
|
548
|
-
* @private
|
|
549
|
-
*/
|
|
550
|
-
_updateShadowRoot() {
|
|
551
|
-
if (!this.constructor._needsShadowDOM()) {
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
let styleToPrepend;
|
|
556
|
-
const renderResult = executeTemplate(this.constructor.template, this);
|
|
557
|
-
|
|
558
|
-
// IE11, Edge
|
|
559
|
-
if (window.ShadyDOM) {
|
|
560
|
-
createComponentStyleTag(this.constructor);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Chrome
|
|
564
|
-
if (document.adoptedStyleSheets) {
|
|
565
|
-
this.shadowRoot.adoptedStyleSheets = getConstructableStyle(this.constructor);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// FF, Safari
|
|
569
|
-
if (!document.adoptedStyleSheets && !window.ShadyDOM) {
|
|
570
|
-
styleToPrepend = getEffectiveStyle(this.constructor);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
this.constructor.render(renderResult, this.shadowRoot, styleToPrepend, { eventContext: this });
|
|
574
|
-
}
|
|
575
|
-
|
|
576
593
|
/**
|
|
577
594
|
* @private
|
|
578
595
|
*/
|
|
@@ -595,16 +612,27 @@ class UI5Element extends HTMLElement {
|
|
|
595
612
|
|
|
596
613
|
/**
|
|
597
614
|
* Returns the DOM Element inside the Shadow Root that corresponds to the opening tag in the UI5 Web Component's template
|
|
615
|
+
* *Note:* For logical (abstract) elements (items, options, etc...), returns the part of the parent's DOM that represents this option
|
|
598
616
|
* Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
|
|
617
|
+
*
|
|
599
618
|
* @public
|
|
600
619
|
*/
|
|
601
620
|
getDomRef() {
|
|
621
|
+
// If a component set _getRealDomRef to its children, use the return value of this function
|
|
622
|
+
if (typeof this._getRealDomRef === "function") {
|
|
623
|
+
return this._getRealDomRef();
|
|
624
|
+
}
|
|
625
|
+
|
|
602
626
|
if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
|
|
603
627
|
return;
|
|
604
628
|
}
|
|
605
629
|
|
|
606
|
-
|
|
607
|
-
|
|
630
|
+
const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
|
|
631
|
+
if (children.length !== 1) {
|
|
632
|
+
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
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return children[0];
|
|
608
636
|
}
|
|
609
637
|
|
|
610
638
|
/**
|
|
@@ -621,12 +649,13 @@ class UI5Element extends HTMLElement {
|
|
|
621
649
|
}
|
|
622
650
|
|
|
623
651
|
/**
|
|
624
|
-
*
|
|
652
|
+
* Waits for dom ref and then returns the DOM Element marked with "data-sap-focus-ref" inside the template.
|
|
653
|
+
* This is the element that will receive the focus by default.
|
|
625
654
|
* @public
|
|
626
|
-
* @param {String} refName Defines the name of the stable DOM ref
|
|
627
655
|
*/
|
|
628
|
-
|
|
629
|
-
|
|
656
|
+
async getFocusDomRefAsync() {
|
|
657
|
+
await this._waitForDomRef();
|
|
658
|
+
return this.getFocusDomRef();
|
|
630
659
|
}
|
|
631
660
|
|
|
632
661
|
/**
|
|
@@ -664,8 +693,6 @@ class UI5Element extends HTMLElement {
|
|
|
664
693
|
}
|
|
665
694
|
|
|
666
695
|
_fireEvent(name, data, cancelable = false, bubbles = true) {
|
|
667
|
-
let compatEventResult = true; // Initialized to true, because if the event is not fired at all, it should be considered "not-prevented"
|
|
668
|
-
|
|
669
696
|
const noConflictEvent = new CustomEvent(`ui5-${name}`, {
|
|
670
697
|
detail: data,
|
|
671
698
|
composed: false,
|
|
@@ -673,14 +700,14 @@ class UI5Element extends HTMLElement {
|
|
|
673
700
|
cancelable,
|
|
674
701
|
});
|
|
675
702
|
|
|
676
|
-
// This will be false if the
|
|
677
|
-
|
|
703
|
+
// This will be false if the no-conflict event is prevented
|
|
704
|
+
const noConflictEventResult = this.dispatchEvent(noConflictEvent);
|
|
678
705
|
|
|
679
706
|
if (skipOriginalEvent(name)) {
|
|
680
|
-
return
|
|
707
|
+
return noConflictEventResult;
|
|
681
708
|
}
|
|
682
709
|
|
|
683
|
-
const
|
|
710
|
+
const normalEvent = new CustomEvent(name, {
|
|
684
711
|
detail: data,
|
|
685
712
|
composed: false,
|
|
686
713
|
bubbles,
|
|
@@ -688,10 +715,10 @@ class UI5Element extends HTMLElement {
|
|
|
688
715
|
});
|
|
689
716
|
|
|
690
717
|
// This will be false if the normal event is prevented
|
|
691
|
-
const normalEventResult = this.dispatchEvent(
|
|
718
|
+
const normalEventResult = this.dispatchEvent(normalEvent);
|
|
692
719
|
|
|
693
720
|
// Return false if any of the two events was prevented (its result was false).
|
|
694
|
-
return normalEventResult &&
|
|
721
|
+
return normalEventResult && noConflictEventResult;
|
|
695
722
|
}
|
|
696
723
|
|
|
697
724
|
/**
|
|
@@ -700,18 +727,7 @@ class UI5Element extends HTMLElement {
|
|
|
700
727
|
* @public
|
|
701
728
|
*/
|
|
702
729
|
getSlottedNodes(slotName) {
|
|
703
|
-
|
|
704
|
-
if (!isSlot(curr)) {
|
|
705
|
-
return acc.concat([curr]);
|
|
706
|
-
}
|
|
707
|
-
return acc.concat(curr.assignedNodes({ flatten: true }).filter(item => item instanceof HTMLElement));
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
return this[slotName].reduce(reducer, []);
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
get isCompact() {
|
|
714
|
-
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact";
|
|
730
|
+
return getSlottedElementsList(this[slotName]);
|
|
715
731
|
}
|
|
716
732
|
|
|
717
733
|
/**
|
|
@@ -723,33 +739,7 @@ class UI5Element extends HTMLElement {
|
|
|
723
739
|
*/
|
|
724
740
|
get effectiveDir() {
|
|
725
741
|
markAsRtlAware(this.constructor); // if a UI5 Element calls this method, it's considered to be rtl-aware
|
|
726
|
-
|
|
727
|
-
const doc = window.document;
|
|
728
|
-
const dirValues = ["ltr", "rtl"]; // exclude "auto" and "" from all calculations
|
|
729
|
-
const locallyAppliedDir = getComputedStyle(this).getPropertyValue(GLOBAL_DIR_CSS_VAR);
|
|
730
|
-
|
|
731
|
-
// In that order, inspect the CSS Var (for modern browsers), the element itself, html and body (for IE fallback)
|
|
732
|
-
if (dirValues.includes(locallyAppliedDir)) {
|
|
733
|
-
return locallyAppliedDir;
|
|
734
|
-
}
|
|
735
|
-
if (dirValues.includes(this.dir)) {
|
|
736
|
-
return this.dir;
|
|
737
|
-
}
|
|
738
|
-
if (dirValues.includes(doc.documentElement.dir)) {
|
|
739
|
-
return doc.documentElement.dir;
|
|
740
|
-
}
|
|
741
|
-
if (dirValues.includes(doc.body.dir)) {
|
|
742
|
-
return doc.body.dir;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// Finally, check the configuration for explicitly set RTL or language-implied RTL
|
|
746
|
-
return getRTL() ? "rtl" : undefined;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
updateStaticAreaItemContentDensity() {
|
|
750
|
-
if (this.staticAreaItem) {
|
|
751
|
-
this.staticAreaItem._updateContentDensity(this.isCompact);
|
|
752
|
-
}
|
|
742
|
+
return getEffectiveDir(this);
|
|
753
743
|
}
|
|
754
744
|
|
|
755
745
|
/**
|
|
@@ -769,26 +759,6 @@ class UI5Element extends HTMLElement {
|
|
|
769
759
|
return this.getMetadata().getAttributesList();
|
|
770
760
|
}
|
|
771
761
|
|
|
772
|
-
/**
|
|
773
|
-
* @private
|
|
774
|
-
*/
|
|
775
|
-
static _getSlotName(child) {
|
|
776
|
-
// Text nodes can only go to the default slot
|
|
777
|
-
if (!(child instanceof HTMLElement)) {
|
|
778
|
-
return "default";
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
|
|
782
|
-
const slot = child.getAttribute("slot");
|
|
783
|
-
if (slot) {
|
|
784
|
-
const match = slot.match(/^(.+?)-\d+$/);
|
|
785
|
-
return match ? match[1] : slot;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
// Use default slot as a fallback
|
|
789
|
-
return "default";
|
|
790
|
-
}
|
|
791
|
-
|
|
792
762
|
/**
|
|
793
763
|
* @private
|
|
794
764
|
*/
|
|
@@ -796,70 +766,30 @@ class UI5Element extends HTMLElement {
|
|
|
796
766
|
return !!this.template;
|
|
797
767
|
}
|
|
798
768
|
|
|
799
|
-
_shouldUpdateFragment() {
|
|
800
|
-
return this.constructor._needsStaticArea() && this.staticAreaItem.isRendered();
|
|
801
|
-
}
|
|
802
|
-
|
|
803
769
|
/**
|
|
804
770
|
* @private
|
|
805
771
|
*/
|
|
806
772
|
static _needsStaticArea() {
|
|
807
|
-
return
|
|
773
|
+
return !!this.staticAreaTemplate;
|
|
808
774
|
}
|
|
809
775
|
|
|
810
776
|
/**
|
|
811
777
|
* @public
|
|
812
778
|
*/
|
|
813
779
|
getStaticAreaItemDomRef() {
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
/**
|
|
818
|
-
* @private
|
|
819
|
-
*/
|
|
820
|
-
static _getDefaultState() {
|
|
821
|
-
if (this._defaultState) {
|
|
822
|
-
return this._defaultState;
|
|
780
|
+
if (!this.constructor._needsStaticArea()) {
|
|
781
|
+
throw new Error("This component does not use the static area");
|
|
823
782
|
}
|
|
824
783
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
// Initialize properties
|
|
830
|
-
const props = MetadataClass.getProperties();
|
|
831
|
-
for (const propName in props) { // eslint-disable-line
|
|
832
|
-
const propType = props[propName].type;
|
|
833
|
-
const propDefaultValue = props[propName].defaultValue;
|
|
834
|
-
|
|
835
|
-
if (propType === Boolean) {
|
|
836
|
-
defaultState[propName] = false;
|
|
837
|
-
|
|
838
|
-
if (propDefaultValue !== undefined) {
|
|
839
|
-
console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line
|
|
840
|
-
}
|
|
841
|
-
} else if (props[propName].multiple) {
|
|
842
|
-
defaultState[propName] = [];
|
|
843
|
-
} else if (propType === Object) {
|
|
844
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {};
|
|
845
|
-
} else if (propType === String) {
|
|
846
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : "";
|
|
847
|
-
} else {
|
|
848
|
-
defaultState[propName] = propDefaultValue;
|
|
849
|
-
}
|
|
784
|
+
if (!this.staticAreaItem) {
|
|
785
|
+
this.staticAreaItem = StaticAreaItem.createInstance();
|
|
786
|
+
this.staticAreaItem.setOwnerElement(this);
|
|
850
787
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
if (slotsAreManaged) {
|
|
854
|
-
const slots = MetadataClass.getSlots();
|
|
855
|
-
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
|
|
856
|
-
const propertyName = slotData.propertyName || slotName;
|
|
857
|
-
defaultState[propertyName] = [];
|
|
858
|
-
}
|
|
788
|
+
if (!this.staticAreaItem.parentElement) {
|
|
789
|
+
getSingletonElementInstance("ui5-static-area").appendChild(this.staticAreaItem);
|
|
859
790
|
}
|
|
860
791
|
|
|
861
|
-
this.
|
|
862
|
-
return defaultState;
|
|
792
|
+
return this.staticAreaItem.getDomRef();
|
|
863
793
|
}
|
|
864
794
|
|
|
865
795
|
/**
|
|
@@ -873,7 +803,7 @@ class UI5Element extends HTMLElement {
|
|
|
873
803
|
const properties = this.getMetadata().getProperties();
|
|
874
804
|
for (const [prop, propData] of Object.entries(properties)) { // eslint-disable-line
|
|
875
805
|
if (!isValidPropertyName(prop)) {
|
|
876
|
-
|
|
806
|
+
console.warn(`"${prop}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
|
|
877
807
|
}
|
|
878
808
|
|
|
879
809
|
if (propData.type === Boolean && propData.defaultValue) {
|
|
@@ -911,14 +841,27 @@ class UI5Element extends HTMLElement {
|
|
|
911
841
|
}
|
|
912
842
|
},
|
|
913
843
|
set(value) {
|
|
844
|
+
let isDifferent;
|
|
914
845
|
value = this.constructor.getMetadata().constructor.validatePropertyValue(value, propData);
|
|
915
846
|
|
|
916
847
|
const oldState = this._state[prop];
|
|
848
|
+
if (propData.multiple && propData.compareValues) {
|
|
849
|
+
isDifferent = !arraysAreEqual(oldState, value);
|
|
850
|
+
} else if (isDescendantOf(propData.type, DataType)) {
|
|
851
|
+
isDifferent = !propData.type.valuesAreEqual(oldState, value);
|
|
852
|
+
} else {
|
|
853
|
+
isDifferent = oldState !== value;
|
|
854
|
+
}
|
|
917
855
|
|
|
918
|
-
if (
|
|
856
|
+
if (isDifferent) {
|
|
919
857
|
this._state[prop] = value;
|
|
920
|
-
|
|
921
|
-
|
|
858
|
+
_invalidate.call(this, {
|
|
859
|
+
type: "property",
|
|
860
|
+
name: prop,
|
|
861
|
+
newValue: value,
|
|
862
|
+
oldValue: oldState,
|
|
863
|
+
});
|
|
864
|
+
this._updateAttribute(prop, value);
|
|
922
865
|
}
|
|
923
866
|
},
|
|
924
867
|
});
|
|
@@ -929,7 +872,7 @@ class UI5Element extends HTMLElement {
|
|
|
929
872
|
const slots = this.getMetadata().getSlots();
|
|
930
873
|
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
|
|
931
874
|
if (!isValidPropertyName(slotName)) {
|
|
932
|
-
|
|
875
|
+
console.warn(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
|
|
933
876
|
}
|
|
934
877
|
|
|
935
878
|
const propertyName = slotData.propertyName || slotName;
|
|
@@ -941,7 +884,7 @@ class UI5Element extends HTMLElement {
|
|
|
941
884
|
return [];
|
|
942
885
|
},
|
|
943
886
|
set() {
|
|
944
|
-
throw new Error("Cannot set
|
|
887
|
+
throw new Error("Cannot set slot content directly, use the DOM APIs (appendChild, removeChild, etc...)");
|
|
945
888
|
},
|
|
946
889
|
});
|
|
947
890
|
}
|
|
@@ -953,7 +896,7 @@ class UI5Element extends HTMLElement {
|
|
|
953
896
|
* @protected
|
|
954
897
|
*/
|
|
955
898
|
static get metadata() {
|
|
956
|
-
return
|
|
899
|
+
return {};
|
|
957
900
|
}
|
|
958
901
|
|
|
959
902
|
/**
|
|
@@ -1041,11 +984,13 @@ class UI5Element extends HTMLElement {
|
|
|
1041
984
|
this._generateAccessors();
|
|
1042
985
|
registerTag(tag);
|
|
1043
986
|
window.customElements.define(tag, this);
|
|
987
|
+
preloadLinks(this);
|
|
1044
988
|
|
|
1045
989
|
if (altTag && !customElements.get(altTag)) {
|
|
1046
|
-
class oldClassName extends this {}
|
|
1047
990
|
registerTag(altTag);
|
|
1048
|
-
window.customElements.define(altTag,
|
|
991
|
+
window.customElements.define(altTag, getClassCopy(this, () => {
|
|
992
|
+
console.log(`The ${altTag} tag is deprecated and will be removed in the next release, please use ${tag} instead.`); // eslint-disable-line
|
|
993
|
+
}));
|
|
1049
994
|
}
|
|
1050
995
|
}
|
|
1051
996
|
return this;
|