@ui5/webcomponents-base 0.0.0-aeb93167c → 0.0.0-b053ad005
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 +84 -0
- package/README.md +26 -2
- package/bundle.esm.js +13 -11
- package/dist/AssetRegistry.js +8 -9
- package/dist/Boot.js +43 -0
- package/dist/CSP.js +59 -0
- package/dist/DOMObserver.js +65 -0
- package/dist/Device.js +62 -778
- package/dist/EventProvider.js +30 -26
- package/dist/FontFace.js +7 -95
- package/dist/InitialConfiguration.js +37 -21
- package/dist/Keys.js +51 -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/StaticArea.js +1 -29
- package/dist/StaticAreaItem.js +56 -66
- package/dist/SystemCSSVars.js +4 -25
- package/dist/UI5Element.js +301 -383
- package/dist/UI5ElementMetadata.js +123 -16
- package/dist/asset-registries/Icons.js +121 -14
- package/dist/asset-registries/Illustrations.js +30 -0
- package/dist/asset-registries/LocaleData.js +91 -67
- package/dist/asset-registries/Themes.js +23 -33
- package/dist/asset-registries/i18n.js +61 -50
- package/dist/assets-meta/IconCollectionsAlias.js +18 -0
- package/dist/config/Language.js +18 -20
- 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 +233 -201
- package/dist/delegate/ResizeHandler.js +78 -37
- package/dist/delegate/ScrollEnablement.js +49 -20
- package/dist/features/OpenUI5Support.js +41 -6
- 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/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/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/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 +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 +2 -2
- package/dist/theming/applyTheme.js +5 -14
- 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 +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 +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 +4 -4
- package/dist/util/Caret.js +45 -0
- package/dist/util/ColorConversion.js +370 -0
- package/dist/util/FocusableElements.js +17 -6
- 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 +1 -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/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/isNodeTabbable.js +4 -4
- 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 -13
- package/src/AssetRegistry.js +8 -9
- package/src/Boot.js +43 -0
- package/src/CSP.js +59 -0
- package/src/DOMObserver.js +65 -0
- package/src/Device.js +62 -778
- package/src/EventProvider.js +30 -26
- package/src/FontFace.js +7 -95
- package/src/InitialConfiguration.js +37 -21
- package/src/Keys.js +51 -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/StaticArea.js +1 -29
- package/src/StaticAreaItem.js +56 -66
- package/src/SystemCSSVars.js +4 -25
- package/src/UI5Element.js +301 -383
- package/src/UI5ElementMetadata.js +123 -16
- package/src/asset-registries/Icons.js +121 -14
- package/src/asset-registries/Illustrations.js +30 -0
- package/src/asset-registries/LocaleData.js +91 -67
- package/src/asset-registries/Themes.js +23 -33
- package/src/asset-registries/i18n.js +61 -50
- package/src/assets-meta/IconCollectionsAlias.js +18 -0
- package/src/config/Language.js +18 -20
- 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 +233 -201
- package/src/delegate/ResizeHandler.js +78 -37
- package/src/delegate/ScrollEnablement.js +49 -20
- 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/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 +2 -2
- package/src/theming/applyTheme.js +5 -14
- 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 +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 +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 +4 -4
- package/src/util/Caret.js +45 -0
- package/src/util/ColorConversion.js +370 -0
- package/src/util/FocusableElements.js +17 -6
- 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 +1 -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/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/isNodeTabbable.js +4 -4
- package/used-modules.txt +7 -0
- package/bundle.es5.js +0 -28
- package/dist/SVGIconRegistry.js +0 -73
- 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/config/AssetsPath.js +0 -17
- package/dist/delegate/CustomResize.js +0 -78
- package/dist/delegate/NativeResize.js +0 -45
- package/dist/features/PropertiesFormatSupport.js +0 -8
- package/dist/features/browsersupport/Edge.js +0 -6
- package/dist/features/browsersupport/IE11.js +0 -42
- 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 -68
- package/dist/theming/adaptCSSForIE.js +0 -95
- package/dist/theming/createComponentStyleTag.js +0 -54
- 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.parseFloat.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/EffectiveAssetPath.js +0 -27
- 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 -73
- 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/config/AssetsPath.js +0 -17
- package/src/delegate/CustomResize.js +0 -78
- package/src/delegate/NativeResize.js +0 -45
- package/src/features/PropertiesFormatSupport.js +0 -8
- package/src/features/browsersupport/Edge.js +0 -6
- package/src/features/browsersupport/IE11.js +0 -42
- 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 -68
- package/src/theming/adaptCSSForIE.js +0 -95
- package/src/theming/createComponentStyleTag.js +0 -54
- 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.parseFloat.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/EffectiveAssetPath.js +0 -27
- 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,40 +59,26 @@ const GLOBAL_DIR_CSS_VAR = "--_ui5_dir";
|
|
|
45
59
|
class UI5Element extends HTMLElement {
|
|
46
60
|
constructor() {
|
|
47
61
|
super();
|
|
48
|
-
this._propertyChangeListeners = new Set();
|
|
49
|
-
this._initializeState();
|
|
50
|
-
this._upgradeAllProperties();
|
|
51
|
-
this._initializeContainers();
|
|
52
|
-
this._upToDate = false;
|
|
53
|
-
this._inDOM = false;
|
|
54
|
-
this._fullyConnected = false;
|
|
55
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
|
|
56
70
|
let deferredResolve;
|
|
57
71
|
this._domRefReadyPromise = new Promise(resolve => {
|
|
58
72
|
deferredResolve = resolve;
|
|
59
73
|
});
|
|
60
74
|
this._domRefReadyPromise._deferredResolve = deferredResolve;
|
|
61
75
|
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
addEventListener(type, listener, options) {
|
|
67
|
-
if (type === "_property-change") {
|
|
68
|
-
this._propertyChangeListeners.add(listener);
|
|
69
|
-
}
|
|
70
|
-
return super.addEventListener(type, listener, options);
|
|
71
|
-
}
|
|
76
|
+
this._initializeState();
|
|
77
|
+
this._upgradeAllProperties();
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this._propertyChangeListeners.delete(listener);
|
|
79
|
+
if (this.constructor._needsShadowDOM()) {
|
|
80
|
+
this.attachShadow({ mode: "open" });
|
|
76
81
|
}
|
|
77
|
-
return super.removeEventListener(type, listener, options);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
_hasPropertyChangeListeners() {
|
|
81
|
-
return !!this._propertyChangeListeners.size;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -95,24 +95,6 @@ class UI5Element extends HTMLElement {
|
|
|
95
95
|
return this.__id;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
/**
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
_initializeContainers() {
|
|
102
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
103
|
-
const needsStaticArea = this.constructor._needsStaticArea();
|
|
104
|
-
|
|
105
|
-
// Init Shadow Root
|
|
106
|
-
if (needsShadowDOM) {
|
|
107
|
-
this.attachShadow({ mode: "open" });
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Init StaticAreaItem only if needed
|
|
111
|
-
if (needsStaticArea) {
|
|
112
|
-
this.staticAreaItem = new StaticAreaItem(this);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
98
|
/**
|
|
117
99
|
* Do not call this method from derivatives of UI5Element, use "onEnterDOM" only
|
|
118
100
|
* @private
|
|
@@ -120,7 +102,6 @@ class UI5Element extends HTMLElement {
|
|
|
120
102
|
async connectedCallback() {
|
|
121
103
|
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
|
|
122
104
|
|
|
123
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
124
105
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
125
106
|
|
|
126
107
|
this._inDOM = true;
|
|
@@ -131,23 +112,15 @@ class UI5Element extends HTMLElement {
|
|
|
131
112
|
await this._processChildren();
|
|
132
113
|
}
|
|
133
114
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
await Promise.resolve();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!this._inDOM) { // Component removed from DOM while _processChildren was running
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
115
|
+
if (!this._inDOM) { // Component removed from DOM while _processChildren was running
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
143
118
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this.onEnterDOM();
|
|
150
|
-
}
|
|
119
|
+
renderImmediately(this);
|
|
120
|
+
this._domRefReadyPromise._deferredResolve();
|
|
121
|
+
this._fullyConnected = true;
|
|
122
|
+
if (typeof this.onEnterDOM === "function") {
|
|
123
|
+
this.onEnterDOM();
|
|
151
124
|
}
|
|
152
125
|
}
|
|
153
126
|
|
|
@@ -156,8 +129,6 @@ class UI5Element extends HTMLElement {
|
|
|
156
129
|
* @private
|
|
157
130
|
*/
|
|
158
131
|
disconnectedCallback() {
|
|
159
|
-
const needsShadowDOM = this.constructor._needsShadowDOM();
|
|
160
|
-
const needsStaticArea = this.constructor._needsStaticArea();
|
|
161
132
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
162
133
|
|
|
163
134
|
this._inDOM = false;
|
|
@@ -166,21 +137,18 @@ class UI5Element extends HTMLElement {
|
|
|
166
137
|
this._stopObservingDOMChildren();
|
|
167
138
|
}
|
|
168
139
|
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (typeof this.onExitDOM === "function") {
|
|
173
|
-
this.onExitDOM();
|
|
174
|
-
}
|
|
175
|
-
this._fullyConnected = false;
|
|
140
|
+
if (this._fullyConnected) {
|
|
141
|
+
if (typeof this.onExitDOM === "function") {
|
|
142
|
+
this.onExitDOM();
|
|
176
143
|
}
|
|
144
|
+
this._fullyConnected = false;
|
|
177
145
|
}
|
|
178
146
|
|
|
179
|
-
if (
|
|
180
|
-
this.staticAreaItem.
|
|
147
|
+
if (this.staticAreaItem && this.staticAreaItem.parentElement) {
|
|
148
|
+
this.staticAreaItem.parentElement.removeChild(this.staticAreaItem);
|
|
181
149
|
}
|
|
182
150
|
|
|
183
|
-
|
|
151
|
+
cancelRender(this);
|
|
184
152
|
}
|
|
185
153
|
|
|
186
154
|
/**
|
|
@@ -196,16 +164,16 @@ class UI5Element extends HTMLElement {
|
|
|
196
164
|
const mutationObserverOptions = {
|
|
197
165
|
childList: true,
|
|
198
166
|
subtree: canSlotText,
|
|
199
|
-
characterData:
|
|
167
|
+
characterData: canSlotText,
|
|
200
168
|
};
|
|
201
|
-
|
|
169
|
+
observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
|
|
202
170
|
}
|
|
203
171
|
|
|
204
172
|
/**
|
|
205
173
|
* @private
|
|
206
174
|
*/
|
|
207
175
|
_stopObservingDOMChildren() {
|
|
208
|
-
|
|
176
|
+
unobserveDOMNode(this);
|
|
209
177
|
}
|
|
210
178
|
|
|
211
179
|
/**
|
|
@@ -227,8 +195,14 @@ class UI5Element extends HTMLElement {
|
|
|
227
195
|
const canSlotText = this.constructor.getMetadata().canSlotText();
|
|
228
196
|
const domChildren = Array.from(canSlotText ? this.childNodes : this.children);
|
|
229
197
|
|
|
230
|
-
//
|
|
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
|
|
231
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]]);
|
|
232
206
|
this._clearSlot(slotName, slotData);
|
|
233
207
|
}
|
|
234
208
|
|
|
@@ -237,7 +211,7 @@ class UI5Element extends HTMLElement {
|
|
|
237
211
|
|
|
238
212
|
const allChildrenUpgraded = domChildren.map(async (child, idx) => {
|
|
239
213
|
// Determine the type of the child (mainly by the slot attribute)
|
|
240
|
-
const slotName =
|
|
214
|
+
const slotName = getSlotName(child);
|
|
241
215
|
const slotData = slotsMap[slotName];
|
|
242
216
|
|
|
243
217
|
// Check if the slotName is supported
|
|
@@ -275,16 +249,14 @@ class UI5Element extends HTMLElement {
|
|
|
275
249
|
|
|
276
250
|
child = this.constructor.getMetadata().constructor.validateSlotValue(child, slotData);
|
|
277
251
|
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (child.isUI5Element && slotData.invalidateParent) {
|
|
283
|
-
child._shouldInvalidateParent = true;
|
|
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));
|
|
284
255
|
}
|
|
285
256
|
|
|
257
|
+
// Listen for the slotchange event if the child is a slot itself
|
|
286
258
|
if (isSlot(child)) {
|
|
287
|
-
this._attachSlotChange(child);
|
|
259
|
+
this._attachSlotChange(child, slotName);
|
|
288
260
|
}
|
|
289
261
|
|
|
290
262
|
const propertyName = slotData.propertyName || slotName;
|
|
@@ -300,10 +272,33 @@ class UI5Element extends HTMLElement {
|
|
|
300
272
|
|
|
301
273
|
// Distribute the child in the _state object, keeping the Light DOM order,
|
|
302
274
|
// not the order elements are defined.
|
|
303
|
-
slottedChildrenMap.forEach((children,
|
|
304
|
-
this._state[
|
|
275
|
+
slottedChildrenMap.forEach((children, propertyName) => {
|
|
276
|
+
this._state[propertyName] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
|
|
305
277
|
});
|
|
306
|
-
|
|
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
|
+
}
|
|
307
302
|
}
|
|
308
303
|
|
|
309
304
|
/**
|
|
@@ -312,25 +307,61 @@ class UI5Element extends HTMLElement {
|
|
|
312
307
|
*/
|
|
313
308
|
_clearSlot(slotName, slotData) {
|
|
314
309
|
const propertyName = slotData.propertyName || slotName;
|
|
315
|
-
|
|
316
|
-
let children = this._state[propertyName];
|
|
317
|
-
if (!Array.isArray(children)) {
|
|
318
|
-
children = [children];
|
|
319
|
-
}
|
|
310
|
+
const children = this._state[propertyName];
|
|
320
311
|
|
|
321
312
|
children.forEach(child => {
|
|
322
313
|
if (child && child.isUI5Element) {
|
|
323
|
-
this.
|
|
324
|
-
child._shouldInvalidateParent = false;
|
|
314
|
+
child.detachInvalidate(this._getChildChangeListener(slotName));
|
|
325
315
|
}
|
|
326
316
|
|
|
327
317
|
if (isSlot(child)) {
|
|
328
|
-
this._detachSlotChange(child);
|
|
318
|
+
this._detachSlotChange(child, slotName);
|
|
329
319
|
}
|
|
330
320
|
});
|
|
331
321
|
|
|
332
322
|
this._state[propertyName] = [];
|
|
333
|
-
|
|
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
|
+
});
|
|
334
365
|
}
|
|
335
366
|
|
|
336
367
|
/**
|
|
@@ -345,12 +376,8 @@ class UI5Element extends HTMLElement {
|
|
|
345
376
|
const propertyTypeClass = properties[nameInCamelCase].type;
|
|
346
377
|
if (propertyTypeClass === Boolean) {
|
|
347
378
|
newValue = newValue !== null;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
newValue = parseInt(newValue);
|
|
351
|
-
}
|
|
352
|
-
if (propertyTypeClass === Float) {
|
|
353
|
-
newValue = parseFloat(newValue);
|
|
379
|
+
} else if (isDescendantOf(propertyTypeClass, DataType)) {
|
|
380
|
+
newValue = propertyTypeClass.attributeToProperty(newValue);
|
|
354
381
|
}
|
|
355
382
|
this[nameInCamelCase] = newValue;
|
|
356
383
|
}
|
|
@@ -363,22 +390,24 @@ class UI5Element extends HTMLElement {
|
|
|
363
390
|
if (!this.constructor.getMetadata().hasAttribute(name)) {
|
|
364
391
|
return;
|
|
365
392
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
393
|
+
const properties = this.constructor.getMetadata().getProperties();
|
|
394
|
+
const propertyTypeClass = properties[name].type;
|
|
371
395
|
const attrName = camelToKebabCase(name);
|
|
372
396
|
const attrValue = this.getAttribute(attrName);
|
|
373
|
-
|
|
397
|
+
|
|
398
|
+
if (propertyTypeClass === Boolean) {
|
|
374
399
|
if (newValue === true && attrValue === null) {
|
|
375
400
|
this.setAttribute(attrName, "");
|
|
376
401
|
} else if (newValue === false && attrValue !== null) {
|
|
377
402
|
this.removeAttribute(attrName);
|
|
378
403
|
}
|
|
379
|
-
} else if (
|
|
380
|
-
this.setAttribute(attrName, newValue);
|
|
381
|
-
}
|
|
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
|
|
382
411
|
}
|
|
383
412
|
|
|
384
413
|
/**
|
|
@@ -404,123 +433,96 @@ class UI5Element extends HTMLElement {
|
|
|
404
433
|
* @private
|
|
405
434
|
*/
|
|
406
435
|
_initializeState() {
|
|
407
|
-
|
|
408
|
-
this._state = Object.assign({}, defaultState);
|
|
436
|
+
this._state = { ...this.constructor.getMetadata().getInitialState() };
|
|
409
437
|
}
|
|
410
438
|
|
|
411
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}
|
|
412
444
|
* @private
|
|
413
445
|
*/
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
let observedProps = [],
|
|
418
|
-
notObservedProps = [];
|
|
419
|
-
|
|
420
|
-
if (Array.isArray(listenFor)) {
|
|
421
|
-
observedProps = listenFor;
|
|
422
|
-
} else {
|
|
423
|
-
observedProps = Array.isArray(listenFor.include) ? listenFor.include : [];
|
|
424
|
-
notObservedProps = Array.isArray(listenFor.exclude) ? listenFor.exclude : [];
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (!this._monitoredChildProps.has(slotName)) {
|
|
428
|
-
this._monitoredChildProps.set(slotName, { observedProps, notObservedProps });
|
|
446
|
+
_getChildChangeListener(slotName) {
|
|
447
|
+
if (!this._childChangeListeners.has(slotName)) {
|
|
448
|
+
this._childChangeListeners.set(slotName, this._onChildChange.bind(this, slotName));
|
|
429
449
|
}
|
|
430
|
-
|
|
431
|
-
child.addEventListener("_property-change", this._invalidateParentOnPropertyUpdate);
|
|
450
|
+
return this._childChangeListeners.get(slotName);
|
|
432
451
|
}
|
|
433
452
|
|
|
434
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}
|
|
435
458
|
* @private
|
|
436
459
|
*/
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* @private
|
|
443
|
-
*/
|
|
444
|
-
_propertyChange(name, value) {
|
|
445
|
-
this._updateAttribute(name, value);
|
|
446
|
-
|
|
447
|
-
if (this._hasPropertyChangeListeners()) {
|
|
448
|
-
this.dispatchEvent(new CustomEvent("_property-change", {
|
|
449
|
-
detail: { name, newValue: value },
|
|
450
|
-
composed: false,
|
|
451
|
-
bubbles: false,
|
|
452
|
-
}));
|
|
460
|
+
_getSlotChangeListener(slotName) {
|
|
461
|
+
if (!this._slotChangeListeners.has(slotName)) {
|
|
462
|
+
this._slotChangeListeners.set(slotName, this._onSlotChange.bind(this, slotName));
|
|
453
463
|
}
|
|
464
|
+
return this._slotChangeListeners.get(slotName);
|
|
454
465
|
}
|
|
455
466
|
|
|
456
467
|
/**
|
|
457
468
|
* @private
|
|
458
469
|
*/
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const parentNode = this.parentNode;
|
|
462
|
-
if (!parentNode) {
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const slotName = parentNode.constructor._getSlotName(this);
|
|
467
|
-
const propsMetadata = parentNode._monitoredChildProps.get(slotName);
|
|
468
|
-
|
|
469
|
-
if (!propsMetadata) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
const { observedProps, notObservedProps } = propsMetadata;
|
|
473
|
-
|
|
474
|
-
const allPropertiesAreObserved = observedProps.length === 1 && observedProps[0] === "*";
|
|
475
|
-
const shouldObserve = allPropertiesAreObserved || observedProps.includes(prop.detail.name);
|
|
476
|
-
const shouldSkip = notObservedProps.includes(prop.detail.name);
|
|
477
|
-
if (shouldObserve && !shouldSkip) {
|
|
478
|
-
parentNode._invalidate("_parent_", this);
|
|
479
|
-
}
|
|
470
|
+
_attachSlotChange(child, slotName) {
|
|
471
|
+
child.addEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
480
472
|
}
|
|
481
473
|
|
|
482
474
|
/**
|
|
483
475
|
* @private
|
|
484
476
|
*/
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
this._invalidateOnSlotChange = () => {
|
|
488
|
-
this._invalidate("slotchange");
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
child.addEventListener("slotchange", this._invalidateOnSlotChange);
|
|
477
|
+
_detachSlotChange(child, slotName) {
|
|
478
|
+
child.removeEventListener("slotchange", this._getSlotChangeListener(slotName));
|
|
492
479
|
}
|
|
493
480
|
|
|
494
481
|
/**
|
|
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
|
|
495
485
|
* @private
|
|
496
486
|
*/
|
|
497
|
-
|
|
498
|
-
|
|
487
|
+
_onSlotChange(slotName) {
|
|
488
|
+
_invalidate.call(this, {
|
|
489
|
+
type: "slot",
|
|
490
|
+
name: slotName,
|
|
491
|
+
reason: "slotchange",
|
|
492
|
+
});
|
|
499
493
|
}
|
|
500
494
|
|
|
501
495
|
/**
|
|
502
|
-
*
|
|
503
|
-
*
|
|
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
|
|
504
521
|
*/
|
|
505
|
-
|
|
506
|
-
if (this._shouldInvalidateParent) {
|
|
507
|
-
this.parentNode._invalidate();
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (!this._upToDate) {
|
|
511
|
-
// console.log("already invalidated", this, ...arguments);
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (this.getDomRef() && !this._suppressInvalidation) {
|
|
516
|
-
this._upToDate = false;
|
|
517
|
-
// console.log("INVAL", this, ...arguments);
|
|
518
|
-
RenderScheduler.renderDeferred(this);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
522
|
+
onInvalidation(changeInfo) {}
|
|
521
523
|
|
|
522
524
|
/**
|
|
523
|
-
* Do not call this method directly, only intended to be called by
|
|
525
|
+
* Do not call this method directly, only intended to be called by js
|
|
524
526
|
* @protected
|
|
525
527
|
*/
|
|
526
528
|
_render() {
|
|
@@ -539,16 +541,37 @@ class UI5Element extends HTMLElement {
|
|
|
539
541
|
}
|
|
540
542
|
|
|
541
543
|
// resume normal invalidation handling
|
|
542
|
-
|
|
544
|
+
this._suppressInvalidation = false;
|
|
543
545
|
|
|
544
546
|
// Update the shadow root with the render result
|
|
545
|
-
|
|
546
|
-
this.
|
|
547
|
-
|
|
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
|
+
}
|
|
548
562
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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();
|
|
552
575
|
}
|
|
553
576
|
|
|
554
577
|
// Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM
|
|
@@ -562,35 +585,6 @@ class UI5Element extends HTMLElement {
|
|
|
562
585
|
}
|
|
563
586
|
}
|
|
564
587
|
|
|
565
|
-
/**
|
|
566
|
-
* @private
|
|
567
|
-
*/
|
|
568
|
-
_updateShadowRoot() {
|
|
569
|
-
if (!this.constructor._needsShadowDOM()) {
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
let styleToPrepend;
|
|
574
|
-
const renderResult = executeTemplate(this.constructor.template, this);
|
|
575
|
-
|
|
576
|
-
// IE11, Edge
|
|
577
|
-
if (window.ShadyDOM) {
|
|
578
|
-
createComponentStyleTag(this.constructor);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Chrome
|
|
582
|
-
if (document.adoptedStyleSheets) {
|
|
583
|
-
this.shadowRoot.adoptedStyleSheets = getConstructableStyle(this.constructor);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// FF, Safari
|
|
587
|
-
if (!document.adoptedStyleSheets && !window.ShadyDOM) {
|
|
588
|
-
styleToPrepend = getEffectiveStyle(this.constructor);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
this.constructor.render(renderResult, this.shadowRoot, styleToPrepend, { eventContext: this });
|
|
592
|
-
}
|
|
593
|
-
|
|
594
588
|
/**
|
|
595
589
|
* @private
|
|
596
590
|
*/
|
|
@@ -613,16 +607,27 @@ class UI5Element extends HTMLElement {
|
|
|
613
607
|
|
|
614
608
|
/**
|
|
615
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
|
|
616
611
|
* Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
|
|
612
|
+
*
|
|
617
613
|
* @public
|
|
618
614
|
*/
|
|
619
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
|
+
|
|
620
621
|
if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
|
|
621
622
|
return;
|
|
622
623
|
}
|
|
623
624
|
|
|
624
|
-
|
|
625
|
-
|
|
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];
|
|
626
631
|
}
|
|
627
632
|
|
|
628
633
|
/**
|
|
@@ -639,16 +644,13 @@ class UI5Element extends HTMLElement {
|
|
|
639
644
|
}
|
|
640
645
|
|
|
641
646
|
/**
|
|
642
|
-
*
|
|
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.
|
|
643
649
|
* @public
|
|
644
|
-
* @method
|
|
645
|
-
* @param {String} refName Defines the name of the stable DOM ref
|
|
646
650
|
*/
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
return staticAreaResult
|
|
651
|
-
|| this.getDomRef().querySelector(`[data-ui5-stable=${refName}]`);
|
|
651
|
+
async getFocusDomRefAsync() {
|
|
652
|
+
await this._waitForDomRef();
|
|
653
|
+
return this.getFocusDomRef();
|
|
652
654
|
}
|
|
653
655
|
|
|
654
656
|
/**
|
|
@@ -686,8 +688,6 @@ class UI5Element extends HTMLElement {
|
|
|
686
688
|
}
|
|
687
689
|
|
|
688
690
|
_fireEvent(name, data, cancelable = false, bubbles = true) {
|
|
689
|
-
let compatEventResult = true; // Initialized to true, because if the event is not fired at all, it should be considered "not-prevented"
|
|
690
|
-
|
|
691
691
|
const noConflictEvent = new CustomEvent(`ui5-${name}`, {
|
|
692
692
|
detail: data,
|
|
693
693
|
composed: false,
|
|
@@ -695,14 +695,14 @@ class UI5Element extends HTMLElement {
|
|
|
695
695
|
cancelable,
|
|
696
696
|
});
|
|
697
697
|
|
|
698
|
-
// This will be false if the
|
|
699
|
-
|
|
698
|
+
// This will be false if the no-conflict event is prevented
|
|
699
|
+
const noConflictEventResult = this.dispatchEvent(noConflictEvent);
|
|
700
700
|
|
|
701
701
|
if (skipOriginalEvent(name)) {
|
|
702
|
-
return
|
|
702
|
+
return noConflictEventResult;
|
|
703
703
|
}
|
|
704
704
|
|
|
705
|
-
const
|
|
705
|
+
const normalEvent = new CustomEvent(name, {
|
|
706
706
|
detail: data,
|
|
707
707
|
composed: false,
|
|
708
708
|
bubbles,
|
|
@@ -710,10 +710,10 @@ class UI5Element extends HTMLElement {
|
|
|
710
710
|
});
|
|
711
711
|
|
|
712
712
|
// This will be false if the normal event is prevented
|
|
713
|
-
const normalEventResult = this.dispatchEvent(
|
|
713
|
+
const normalEventResult = this.dispatchEvent(normalEvent);
|
|
714
714
|
|
|
715
715
|
// Return false if any of the two events was prevented (its result was false).
|
|
716
|
-
return normalEventResult &&
|
|
716
|
+
return normalEventResult && noConflictEventResult;
|
|
717
717
|
}
|
|
718
718
|
|
|
719
719
|
/**
|
|
@@ -722,18 +722,7 @@ class UI5Element extends HTMLElement {
|
|
|
722
722
|
* @public
|
|
723
723
|
*/
|
|
724
724
|
getSlottedNodes(slotName) {
|
|
725
|
-
|
|
726
|
-
if (!isSlot(curr)) {
|
|
727
|
-
return acc.concat([curr]);
|
|
728
|
-
}
|
|
729
|
-
return acc.concat(curr.assignedNodes({ flatten: true }).filter(item => item instanceof HTMLElement));
|
|
730
|
-
};
|
|
731
|
-
|
|
732
|
-
return this[slotName].reduce(reducer, []);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
get isCompact() {
|
|
736
|
-
return getComputedStyle(this).getPropertyValue(GLOBAL_CONTENT_DENSITY_CSS_VAR) === "compact";
|
|
725
|
+
return getSlottedElementsList(this[slotName]);
|
|
737
726
|
}
|
|
738
727
|
|
|
739
728
|
/**
|
|
@@ -745,33 +734,7 @@ class UI5Element extends HTMLElement {
|
|
|
745
734
|
*/
|
|
746
735
|
get effectiveDir() {
|
|
747
736
|
markAsRtlAware(this.constructor); // if a UI5 Element calls this method, it's considered to be rtl-aware
|
|
748
|
-
|
|
749
|
-
const doc = window.document;
|
|
750
|
-
const dirValues = ["ltr", "rtl"]; // exclude "auto" and "" from all calculations
|
|
751
|
-
const locallyAppliedDir = getComputedStyle(this).getPropertyValue(GLOBAL_DIR_CSS_VAR);
|
|
752
|
-
|
|
753
|
-
// In that order, inspect the CSS Var (for modern browsers), the element itself, html and body (for IE fallback)
|
|
754
|
-
if (dirValues.includes(locallyAppliedDir)) {
|
|
755
|
-
return locallyAppliedDir;
|
|
756
|
-
}
|
|
757
|
-
if (dirValues.includes(this.dir)) {
|
|
758
|
-
return this.dir;
|
|
759
|
-
}
|
|
760
|
-
if (dirValues.includes(doc.documentElement.dir)) {
|
|
761
|
-
return doc.documentElement.dir;
|
|
762
|
-
}
|
|
763
|
-
if (dirValues.includes(doc.body.dir)) {
|
|
764
|
-
return doc.body.dir;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
// Finally, check the configuration for explicitly set RTL or language-implied RTL
|
|
768
|
-
return getRTL() ? "rtl" : undefined;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
updateStaticAreaItemContentDensity() {
|
|
772
|
-
if (this.staticAreaItem) {
|
|
773
|
-
this.staticAreaItem._updateContentDensity(this.isCompact);
|
|
774
|
-
}
|
|
737
|
+
return getEffectiveDir(this);
|
|
775
738
|
}
|
|
776
739
|
|
|
777
740
|
/**
|
|
@@ -791,26 +754,6 @@ class UI5Element extends HTMLElement {
|
|
|
791
754
|
return this.getMetadata().getAttributesList();
|
|
792
755
|
}
|
|
793
756
|
|
|
794
|
-
/**
|
|
795
|
-
* @private
|
|
796
|
-
*/
|
|
797
|
-
static _getSlotName(child) {
|
|
798
|
-
// Text nodes can only go to the default slot
|
|
799
|
-
if (!(child instanceof HTMLElement)) {
|
|
800
|
-
return "default";
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
|
|
804
|
-
const slot = child.getAttribute("slot");
|
|
805
|
-
if (slot) {
|
|
806
|
-
const match = slot.match(/^(.+?)-\d+$/);
|
|
807
|
-
return match ? match[1] : slot;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// Use default slot as a fallback
|
|
811
|
-
return "default";
|
|
812
|
-
}
|
|
813
|
-
|
|
814
757
|
/**
|
|
815
758
|
* @private
|
|
816
759
|
*/
|
|
@@ -818,70 +761,30 @@ class UI5Element extends HTMLElement {
|
|
|
818
761
|
return !!this.template;
|
|
819
762
|
}
|
|
820
763
|
|
|
821
|
-
_shouldUpdateFragment() {
|
|
822
|
-
return this.constructor._needsStaticArea() && this.staticAreaItem.isRendered();
|
|
823
|
-
}
|
|
824
|
-
|
|
825
764
|
/**
|
|
826
765
|
* @private
|
|
827
766
|
*/
|
|
828
767
|
static _needsStaticArea() {
|
|
829
|
-
return
|
|
768
|
+
return !!this.staticAreaTemplate;
|
|
830
769
|
}
|
|
831
770
|
|
|
832
771
|
/**
|
|
833
772
|
* @public
|
|
834
773
|
*/
|
|
835
774
|
getStaticAreaItemDomRef() {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
/**
|
|
840
|
-
* @private
|
|
841
|
-
*/
|
|
842
|
-
static _getDefaultState() {
|
|
843
|
-
if (this._defaultState) {
|
|
844
|
-
return this._defaultState;
|
|
775
|
+
if (!this.constructor._needsStaticArea()) {
|
|
776
|
+
throw new Error("This component does not use the static area");
|
|
845
777
|
}
|
|
846
778
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
// Initialize properties
|
|
852
|
-
const props = MetadataClass.getProperties();
|
|
853
|
-
for (const propName in props) { // eslint-disable-line
|
|
854
|
-
const propType = props[propName].type;
|
|
855
|
-
const propDefaultValue = props[propName].defaultValue;
|
|
856
|
-
|
|
857
|
-
if (propType === Boolean) {
|
|
858
|
-
defaultState[propName] = false;
|
|
859
|
-
|
|
860
|
-
if (propDefaultValue !== undefined) {
|
|
861
|
-
console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line
|
|
862
|
-
}
|
|
863
|
-
} else if (props[propName].multiple) {
|
|
864
|
-
defaultState[propName] = [];
|
|
865
|
-
} else if (propType === Object) {
|
|
866
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {};
|
|
867
|
-
} else if (propType === String) {
|
|
868
|
-
defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : "";
|
|
869
|
-
} else {
|
|
870
|
-
defaultState[propName] = propDefaultValue;
|
|
871
|
-
}
|
|
779
|
+
if (!this.staticAreaItem) {
|
|
780
|
+
this.staticAreaItem = StaticAreaItem.createInstance();
|
|
781
|
+
this.staticAreaItem.setOwnerElement(this);
|
|
872
782
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
if (slotsAreManaged) {
|
|
876
|
-
const slots = MetadataClass.getSlots();
|
|
877
|
-
for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
|
|
878
|
-
const propertyName = slotData.propertyName || slotName;
|
|
879
|
-
defaultState[propertyName] = [];
|
|
880
|
-
}
|
|
783
|
+
if (!this.staticAreaItem.parentElement) {
|
|
784
|
+
getSingletonElementInstance("ui5-static-area").appendChild(this.staticAreaItem);
|
|
881
785
|
}
|
|
882
786
|
|
|
883
|
-
this.
|
|
884
|
-
return defaultState;
|
|
787
|
+
return this.staticAreaItem.getDomRef();
|
|
885
788
|
}
|
|
886
789
|
|
|
887
790
|
/**
|
|
@@ -933,14 +836,27 @@ class UI5Element extends HTMLElement {
|
|
|
933
836
|
}
|
|
934
837
|
},
|
|
935
838
|
set(value) {
|
|
839
|
+
let isDifferent;
|
|
936
840
|
value = this.constructor.getMetadata().constructor.validatePropertyValue(value, propData);
|
|
937
841
|
|
|
938
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
|
+
}
|
|
939
850
|
|
|
940
|
-
if (
|
|
851
|
+
if (isDifferent) {
|
|
941
852
|
this._state[prop] = value;
|
|
942
|
-
|
|
943
|
-
|
|
853
|
+
_invalidate.call(this, {
|
|
854
|
+
type: "property",
|
|
855
|
+
name: prop,
|
|
856
|
+
newValue: value,
|
|
857
|
+
oldValue: oldState,
|
|
858
|
+
});
|
|
859
|
+
this._updateAttribute(prop, value);
|
|
944
860
|
}
|
|
945
861
|
},
|
|
946
862
|
});
|
|
@@ -963,7 +879,7 @@ class UI5Element extends HTMLElement {
|
|
|
963
879
|
return [];
|
|
964
880
|
},
|
|
965
881
|
set() {
|
|
966
|
-
throw new Error("Cannot set
|
|
882
|
+
throw new Error("Cannot set slot content directly, use the DOM APIs (appendChild, removeChild, etc...)");
|
|
967
883
|
},
|
|
968
884
|
});
|
|
969
885
|
}
|
|
@@ -975,7 +891,7 @@ class UI5Element extends HTMLElement {
|
|
|
975
891
|
* @protected
|
|
976
892
|
*/
|
|
977
893
|
static get metadata() {
|
|
978
|
-
return
|
|
894
|
+
return {};
|
|
979
895
|
}
|
|
980
896
|
|
|
981
897
|
/**
|
|
@@ -1063,11 +979,13 @@ class UI5Element extends HTMLElement {
|
|
|
1063
979
|
this._generateAccessors();
|
|
1064
980
|
registerTag(tag);
|
|
1065
981
|
window.customElements.define(tag, this);
|
|
982
|
+
preloadLinks(this);
|
|
1066
983
|
|
|
1067
984
|
if (altTag && !customElements.get(altTag)) {
|
|
1068
|
-
class oldClassName extends this {}
|
|
1069
985
|
registerTag(altTag);
|
|
1070
|
-
window.customElements.define(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
|
+
}));
|
|
1071
989
|
}
|
|
1072
990
|
}
|
|
1073
991
|
return this;
|