<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://tippvomtibb.de/wiki/api.php?hidebots=1&amp;urlversion=1&amp;days=7&amp;limit=50&amp;action=feedrecentchanges&amp;feedformat=atom</id>
	<title>TippvomTibb  - Letzte Änderungen [de]</title>
	<link rel="self" type="application/atom+xml" href="https://tippvomtibb.de/wiki/api.php?hidebots=1&amp;urlversion=1&amp;days=7&amp;limit=50&amp;action=feedrecentchanges&amp;feedformat=atom"/>
	<link rel="alternate" type="text/html" href="https://tippvomtibb.de/mediawiki/Spezial:Letzte_%C3%84nderungen"/>
	<updated>2026-04-30T01:55:59Z</updated>
	<subtitle>Verfolge mit diesem Feed die letzten Änderungen in TippvomTibb.</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3&amp;diff=4888&amp;oldid=4881</id>
		<title>(FHEM) FTUI 3</title>
		<link rel="alternate" type="text/html" href="https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3&amp;diff=4888&amp;oldid=4881"/>
		<updated>2026-04-27T16:47:21Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Komponentenprogramme&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;de&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Nächstältere Version&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Version vom 27. April 2026, 18:47 Uhr&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l191&quot;&gt;Zeile 191:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 191:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Der &#039;&#039;&#039;View&#039;&#039;&#039; ist die Basis fuer:&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Toolbar&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Stage&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Sheet&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Section&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Item&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Für `button` zeigt das Repository z.B. `button.component.js`, `button-nice.component.js` und CSS. ([GitHub][4])&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Für `button` zeigt das Repository z.B. `button.component.js`, `button-nice.component.js` und CSS. ([GitHub][4])&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Chris T. Ludwig</name></author>
	</entry>
	<entry>
		<id>https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3_Components&amp;diff=4887&amp;oldid=4882</id>
		<title>(FHEM) FTUI 3 Components</title>
		<link rel="alternate" type="text/html" href="https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3_Components&amp;diff=4887&amp;oldid=4882"/>
		<updated>2026-04-26T15:44:03Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;initBooleanAttribute&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;de&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Nächstältere Version&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Version vom 26. April 2026, 17:44 Uhr&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-multi&quot; lang=&quot;de&quot;&gt;(4 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Zeile 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=element.components.js=&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=element.components.js=&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Definition &lt;/del&gt;der &#039;&#039;&#039;Basisklasse&#039;&#039;&#039; für alle FTUI-v3-Webcomponents. Jede Komponente wie `ftui-button`, `ftui-label`, `ftui-icon` usw. erbt vermutlich von `FtuiElement`.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Deklaration &lt;/ins&gt;der &#039;&#039;&#039;Basisklasse&#039;&#039;&#039; für alle FTUI-v3-Webcomponents. Jede Komponente wie `ftui-button`, `ftui-label`, `ftui-icon` usw. erbt vermutlich von `FtuiElement`.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Sie kuemmert sich um:&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Sie kuemmert sich um:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l32&quot;&gt;Zeile 32:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 32:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Es werden drei Hilfsfunktionen verwendet:&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Es werden drei Hilfsfunktionen verwendet:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* &lt;/ins&gt;isNumeric()   prüft, ob ein Wert numerisch ist&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/pre&amp;gt;text&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* &lt;/ins&gt;toKebabCase() wandelt z.B. &quot;baseWidth&quot; in &quot;base-width&quot;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;isNumeric()   prüft, ob ein Wert numerisch ist&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* &lt;/ins&gt;log()         schreibt Debug-Ausgaben&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;toKebabCase() wandelt z.B. &quot;baseWidth&quot; in &quot;base-width&quot;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;log()         schreibt Debug-Ausgaben&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/pre&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==UID-Zähler==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==UID-Zähler==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l198&quot;&gt;Zeile 198:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 195:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Wichtig: Hier werden nur die Basiseigenschaften beobachtet. Abgeleitete Komponenten müssen wahrscheinlich selbst `observedAttributes` erweitern, sonst werden ihre eigenen Attribute nicht automatisch beobachtet.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Wichtig: Hier werden nur die Basiseigenschaften beobachtet. Abgeleitete Komponenten müssen wahrscheinlich selbst `observedAttributes` erweitern, sonst werden ihre eigenen Attribute nicht automatisch beobachtet.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==convertToAttributes&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==convertToAttributes&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l236&quot;&gt;Zeile 236:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 233:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1. Standardwerte werden verarbeitet.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;1. Standardwerte werden verarbeitet.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;2. Falls die konkrete Komponente `onConnected()` definiert, wird diese Hook-Funktion ausgeführt.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;2. Falls die konkrete Komponente `onConnected()` definiert, wird diese Hook-Funktion ausgeführt.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l246&quot;&gt;Zeile 246:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 244:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==attributeChangedCallback&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==attributeChangedCallback&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l507&quot;&gt;Zeile 507:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 505:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Da `hidden`, `disabled`, `readonly` alle `false` sind, werden sie standardmäßig nicht gesetzt.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Da `hidden`, `disabled`, `readonly` alle `false` sind, werden sie standardmäßig nicht gesetzt.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineBooleanProperty&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineBooleanProperty&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l553&quot;&gt;Zeile 553:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 551:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;wird als `false` interpretiert. Das ist etwas komfortabler als natives HTML, wo ein vorhandenes Boolean-Attribut normalerweise immer wahr ist.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;wird als `false` interpretiert. Das ist etwas komfortabler als natives HTML, wo ein vorhandenes Boolean-Attribut normalerweise immer wahr ist.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineNumberProperty&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineNumberProperty&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l572&quot;&gt;Zeile 572:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 570:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;liefert Zahl `2`.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;liefert Zahl `2`.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineStringProperty&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==defineStringProperty&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l591&quot;&gt;Zeile 591:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 589:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==updateProperties&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==updateProperties&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Chris T. Ludwig</name></author>
	</entry>
	<entry>
		<id>https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3_Components&amp;diff=4882&amp;oldid=0</id>
		<title>(FHEM) FTUI 3 Components</title>
		<link rel="alternate" type="text/html" href="https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3_Components&amp;diff=4882&amp;oldid=0"/>
		<updated>2026-04-26T15:20:13Z</updated>

		<summary type="html">&lt;p&gt;Die Seite wurde neu angelegt: „=element.components.js=  Definition der &amp;#039;&amp;#039;&amp;#039;Basisklasse&amp;#039;&amp;#039;&amp;#039; für alle FTUI-v3-Webcomponents. Jede Komponente wie `ftui-button`, `ftui-label`, `ftui-icon` usw. erbt vermutlich von `FtuiElement`.  Sie kuemmert sich um:  * automatische IDs * Standardattribute wie `hidden`, `disabled`, `readonly`, `margin`, `padding` * Verbindung zwischen Attributen und JavaScript-Properties * Shadow DOM * Change-Events für FTUI-Bindings * Hooks für abgeleitete Komponenten  =…“&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;=element.components.js=&lt;br /&gt;
&lt;br /&gt;
Definition der &amp;#039;&amp;#039;&amp;#039;Basisklasse&amp;#039;&amp;#039;&amp;#039; für alle FTUI-v3-Webcomponents. Jede Komponente wie `ftui-button`, `ftui-label`, `ftui-icon` usw. erbt vermutlich von `FtuiElement`.&lt;br /&gt;
&lt;br /&gt;
Sie kuemmert sich um:&lt;br /&gt;
&lt;br /&gt;
* automatische IDs&lt;br /&gt;
* Standardattribute wie `hidden`, `disabled`, `readonly`, `margin`, `padding`&lt;br /&gt;
* Verbindung zwischen Attributen und JavaScript-Properties&lt;br /&gt;
* Shadow DOM&lt;br /&gt;
* Change-Events für FTUI-Bindings&lt;br /&gt;
* Hooks für abgeleitete Komponenten&lt;br /&gt;
&lt;br /&gt;
==Kurzueberblick==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export class FtuiElement extends HTMLElement&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`FtuiElement` erweitert den nativen Browser-Typ `HTMLElement`. Dadurch wird daraus die gemeinsame Basis für eigene HTML-Tags wie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;ftui-label&amp;gt;&amp;lt;/ftui-label&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Import==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import { isNumeric, toKebabCase, log } from &amp;#039;../modules/ftui/ftui.helper.js&amp;#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden drei Hilfsfunktionen verwendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;text&lt;br /&gt;
isNumeric()   prüft, ob ein Wert numerisch ist&lt;br /&gt;
toKebabCase() wandelt z.B. &amp;quot;baseWidth&amp;quot; in &amp;quot;base-width&amp;quot;&lt;br /&gt;
log()         schreibt Debug-Ausgaben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==UID-Zähler==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const uids = {};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit bekommt jedes FTUI-Element automatisch eine ID, falls keine gesetzt wurde.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-label&amp;gt;&amp;lt;/ftui-label&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird intern etwa zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-label id=&amp;quot;ftui_label_1&amp;quot;&amp;gt;&amp;lt;/ftui-label&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Constructor==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
constructor(properties) {&lt;br /&gt;
  super();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`super()` ruft den Konstruktor von `HTMLElement` auf. Das ist bei Webcomponents Pflicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!this.id) {&lt;br /&gt;
  ...&lt;br /&gt;
  this.id = `${this.localName.replace(/-/g, &amp;#039;_&amp;#039;)}_${uids[this.localName]++}`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls das Element keine ID hat, wird automatisch eine erzeugt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.properties = Object.assign(FtuiElement.properties, properties);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden die Standard-Properties der Basisklasse mit den Properties der konkreten Komponente gemischt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FtuiElement.properties = {&lt;br /&gt;
  hidden: false,&lt;br /&gt;
  disabled: false,&lt;br /&gt;
  readonly: false,&lt;br /&gt;
  margin: &amp;#039;&amp;#039;,&lt;br /&gt;
  padding: &amp;#039;&amp;#039;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein `ftui-button` könnte zusätzlich `value`, `color`, `fill` usw. definieren.&lt;br /&gt;
&lt;br /&gt;
Achtung: `Object.assign(FtuiElement.properties, properties)` verändert das Objekt `FtuiElement.properties`. Sauberer wäre oft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Object.assign({}, FtuiElement.properties, properties)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sonst können Properties versehentlich global vermischt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.initProperties(this.properties);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erzeugt für jede Property Getter/Setter und initialisiert die passenden HTML-Attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (typeof this.template === &amp;#039;function&amp;#039;) {&lt;br /&gt;
  this.createShadowRoot(this.template());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die konkrete Komponente eine Methode `template()` besitzt, wird daraus ein Shadow DOM erzeugt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.isActiveChange = {};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merker für aktive Änderungen, wichtig für Two-Way-Binding.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (window.ftuiApp) {&lt;br /&gt;
  ftuiApp.attachBinding(this);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die FTUI-App bereits existiert, wird das Element mit dem FTUI-Binding-System verbunden.&lt;br /&gt;
&lt;br /&gt;
==Shadow DOM==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
createShadowRoot(content) {&lt;br /&gt;
  const elemTemplate = document.createElement(&amp;#039;template&amp;#039;);&lt;br /&gt;
  elemTemplate.innerHTML = content;&lt;br /&gt;
  this.attachShadow({ mode: &amp;#039;open&amp;#039; });&lt;br /&gt;
  this.shadowRoot.appendChild(elemTemplate.content.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode baut das interne DOM der Komponente.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
template() {&lt;br /&gt;
  return `&amp;lt;button&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/button&amp;gt;`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird zu einem Shadow DOM innerhalb des Elements.&lt;br /&gt;
&lt;br /&gt;
`mode: &amp;#039;open&amp;#039;` bedeutet: Man kann von außen per JavaScript darauf zugreifen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.shadowRoot&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Standard-Properties==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static get properties() {&lt;br /&gt;
  return {&lt;br /&gt;
    hidden: false,&lt;br /&gt;
    disabled: false,&lt;br /&gt;
    readonly: false,&lt;br /&gt;
    margin: &amp;#039;&amp;#039;,&lt;br /&gt;
    padding: &amp;#039;&amp;#039;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes FTUI-Element bekommt diese Attribute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button hidden&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button disabled&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button readonly&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button margin=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button padding=&amp;quot;0.5&amp;quot;&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==observedAttributes==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static get observedAttributes() {&lt;br /&gt;
  return [...Object.keys(FtuiElement.properties)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Browser ruft `attributeChangedCallback()` nur für Attribute auf, die hier stehen.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Hier werden nur die Basiseigenschaften beobachtet. Abgeleitete Komponenten müssen wahrscheinlich selbst `observedAttributes` erweitern, sonst werden ihre eigenen Attribute nicht automatisch beobachtet.&lt;br /&gt;
&lt;br /&gt;
==convertToAttributes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static convertToAttributes(properties) {&lt;br /&gt;
  return Object.keys(properties).map(property =&amp;gt; toKebabCase(property));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hilfsfunktion, um Property-Namen in HTML-Attributnamen umzuwandeln.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
baseWidth&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
base-width&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==connectedCallback==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
connectedCallback() {&lt;br /&gt;
  this.updateProperties();&lt;br /&gt;
  if (typeof this.onConnected === &amp;#039;function&amp;#039;) {&lt;br /&gt;
    this.onConnected();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode wird automatisch vom Browser aufgerufen, wenn das Element in die Seite eingefügt wird.&lt;br /&gt;
&lt;br /&gt;
Ablauf:&lt;br /&gt;
&lt;br /&gt;
1. Standardwerte werden verarbeitet.&lt;br /&gt;
2. Falls die konkrete Komponente `onConnected()` definiert, wird diese Hook-Funktion ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Beispiel in einer Kindklasse:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onConnected() {&lt;br /&gt;
  console.log(&amp;#039;Button ist im DOM&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==attributeChangedCallback&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attributeChangedCallback(name, oldValue, newValue) {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird aufgerufen, wenn ein beobachtetes Attribut geändert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
log(3, `${this.id} -  attributeChangedCallback ...`)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debug-Ausgabe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (typeof this.onAttributeChanged === &amp;#039;function&amp;#039;) {&lt;br /&gt;
  this.onAttributeChanged(name, newValue, oldValue);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hook für Kindklassen.&lt;br /&gt;
&lt;br /&gt;
Danach behandelt die Basisklasse ihre Standardattribute:&lt;br /&gt;
&lt;br /&gt;
#==hidden&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
case &amp;#039;hidden&amp;#039;:&lt;br /&gt;
  this.style.display = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn `hidden` gesetzt ist, wird das Element ausgeblendet.&lt;br /&gt;
&lt;br /&gt;
#==disabled&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
case &amp;#039;disabled&amp;#039;:&lt;br /&gt;
  this.style.filter = hasValue ? &amp;#039;sepia(1) saturate(0) blur(1px)&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
  this.style.pointerEvents = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optisch ausgegraut und nicht anklickbar.&lt;br /&gt;
&lt;br /&gt;
#==readonly&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
case &amp;#039;readonly&amp;#039;:&lt;br /&gt;
  this.style.pointerEvents = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nicht bedienbar, aber ohne optischen Filter.&lt;br /&gt;
&lt;br /&gt;
#==margin&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
case &amp;#039;margin&amp;#039;:&lt;br /&gt;
  if (this.tagName !== &amp;#039;FTUI-GRID&amp;#039;) {&lt;br /&gt;
    this.style.margin = isNumeric(newValue) ? newValue + &amp;#039;em&amp;#039; : newValue;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn numerisch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
margin=&amp;quot;1&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
margin: 1em;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn nicht numerisch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
margin=&amp;quot;10px&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bleibt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
margin: 10px;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für `FTUI-GRID` wird `margin` hier nicht gesetzt, vermutlich weil `ftui-grid` sein eigenes Margin-Verhalten hat.&lt;br /&gt;
&lt;br /&gt;
#==padding&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
case &amp;#039;padding&amp;#039;:&lt;br /&gt;
  this.style.padding = isNumeric(newValue) ? newValue + &amp;#039;em&amp;#039; : newValue;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zu `margin`.&lt;br /&gt;
&lt;br /&gt;
==submitChange==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
submitChange(property, value) {&lt;br /&gt;
  this.isActiveChange[property] = true;&lt;br /&gt;
  this[property] = value;&lt;br /&gt;
  this.emitChangeEvent(property, value);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das ist wichtig für FTUI-Bindings.&lt;br /&gt;
&lt;br /&gt;
Wenn eine Komponente intern einen Wert ändert, etwa ein Button oder Slider, ruft sie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.submitChange(&amp;#039;value&amp;#039;, newValue);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann passiert:&lt;br /&gt;
&lt;br /&gt;
1. Änderung wird als aktiv markiert.&lt;br /&gt;
2. Property wird gesetzt.&lt;br /&gt;
3. Ein Event `valueChange` wird ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Dieses Event kann FTUI dann nutzen, um per `(value)` oder `[(value)]` etwas an FHEM zu senden.&lt;br /&gt;
&lt;br /&gt;
==emitChangeEvent und emitEvent==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emitChangeEvent(attribute, value) {&lt;br /&gt;
  this.emitEvent(attribute + &amp;#039;Change&amp;#039;, value);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aus `value` wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;text&lt;br /&gt;
valueChange&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emitEvent(name, value) {&lt;br /&gt;
  const event = new CustomEvent(name, { detail: value });&lt;br /&gt;
  this.dispatchEvent(event);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird ein normales DOM-Event ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.emitChangeEvent(&amp;#039;value&amp;#039;, &amp;#039;on&amp;#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new CustomEvent(&amp;#039;valueChange&amp;#039;, { detail: &amp;#039;on&amp;#039; })&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==initProperties==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
initProperties(properties) {&lt;br /&gt;
  Object.entries(properties).forEach(([name, defaultValue]) =&amp;gt; {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für jede Property wird automatisch ein passender Getter/Setter erzeugt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hidden: false&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.hidden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und HTML-Attribut:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hidden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#==Boolean&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (typeof properties[name] === &amp;#039;boolean&amp;#039;) {&lt;br /&gt;
  this.defineBooleanProperty(name, attr);&lt;br /&gt;
  this.initBooleanAttribute(attr, defaultValue);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boolean-Attribute funktionieren nach HTML-Logik:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button disabled&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
bedeutet `true`.&lt;br /&gt;
&lt;br /&gt;
#==Number&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
else if (typeof properties[name] === &amp;#039;number&amp;#039;) {&lt;br /&gt;
  this.defineNumberProperty(name, attr);&lt;br /&gt;
  this.initAttribute(attr, defaultValue);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird beim Lesen in `Number(...)` umgewandelt.&lt;br /&gt;
&lt;br /&gt;
#==String&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
else {&lt;br /&gt;
  this.defineStringProperty(name, attr);&lt;br /&gt;
  this.initAttribute(attr, defaultValue);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normale String-Attribute.&lt;br /&gt;
&lt;br /&gt;
==initAttribute==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
initAttribute(attr, value) {&lt;br /&gt;
  if (!this.hasAttribute(attr)) {&lt;br /&gt;
    this.setAttribute(attr, value);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Attribut noch nicht im HTML steht, wird der Default gesetzt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
padding: &amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
führt zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
padding=&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==initBooleanAttribute==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
initBooleanAttribute(attr, value) {&lt;br /&gt;
  if (!this.hasAttribute(attr) &amp;amp;&amp;amp; value) {&lt;br /&gt;
    this.setAttribute(attr, &amp;#039;&amp;#039;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boolean-Attribute werden nur gesetzt, wenn der Default `true` ist.&lt;br /&gt;
&lt;br /&gt;
Da `hidden`, `disabled`, `readonly` alle `false` sind, werden sie standardmäßig nicht gesetzt.&lt;br /&gt;
&lt;br /&gt;
==defineBooleanProperty&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Object.defineProperty(this, name, {&lt;br /&gt;
  get() {&lt;br /&gt;
    return this.hasAttribute(attr)&lt;br /&gt;
      &amp;amp;&amp;amp; this.getAttribute(attr) !== &amp;#039;false&amp;#039;;&lt;br /&gt;
  },&lt;br /&gt;
  set(value) {&lt;br /&gt;
    if (value) {&lt;br /&gt;
      this.setAttribute(attr, &amp;#039;&amp;#039;);&lt;br /&gt;
    } else {&lt;br /&gt;
      this.removeAttribute(attr);&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit kann man schreiben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.disabled = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und bekommt im HTML:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-button disabled&amp;gt;&amp;lt;/ftui-button&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.disabled = false;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird das Attribut entfernt.&lt;br /&gt;
&lt;br /&gt;
Interessant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disabled=&amp;quot;false&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird als `false` interpretiert. Das ist etwas komfortabler als natives HTML, wo ein vorhandenes Boolean-Attribut normalerweise immer wahr ist.&lt;br /&gt;
&lt;br /&gt;
==defineNumberProperty&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get() { return Number(this.getAttribute(attr)); },&lt;br /&gt;
set(value) { this.setAttribute(attr, value); },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;ftui-grid-tile row=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;/ftui-grid-tile&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.row&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
liefert Zahl `2`.&lt;br /&gt;
&lt;br /&gt;
==defineStringProperty&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get() { return this.getAttribute(attr); },&lt;br /&gt;
set(value) { this.setAttribute(attr, value); },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normale Abbildung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
element.text = &amp;#039;Hallo&amp;#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
text=&amp;quot;Hallo&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==updateProperties&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
updateProperties() {&lt;br /&gt;
  Object.entries(this.properties).forEach(([name, defaultValue]) =&amp;gt; {&lt;br /&gt;
    const attr = toKebabCase(name);&lt;br /&gt;
    if (this.getAttribute(attr) === String(defaultValue)) {&lt;br /&gt;
      this.attributeChangedCallback(attr, null, defaultValue);&lt;br /&gt;
    }&lt;br /&gt;
  })&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Einfügen ins DOM werden Standardattribute nochmal verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Warum?&lt;br /&gt;
Wenn ein Attribut schon beim Erzeugen gesetzt wurde, kann es sein, dass die Style-Logik noch nicht gelaufen ist. `updateProperties()` erzwingt deshalb die Behandlung der Defaultwerte.&lt;br /&gt;
&lt;br /&gt;
==Kommentierte Version==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import { isNumeric, toKebabCase, log } from &amp;#039;../modules/ftui/ftui.helper.js&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
// Zähler für automatisch erzeugte IDs pro Elementtyp&lt;br /&gt;
const uids = {};&lt;br /&gt;
&lt;br /&gt;
// Basisklasse aller FTUI-Webcomponents&lt;br /&gt;
export class FtuiElement extends HTMLElement {&lt;br /&gt;
&lt;br /&gt;
  constructor(properties) {&lt;br /&gt;
    super();&lt;br /&gt;
&lt;br /&gt;
    // Falls keine ID vorhanden ist, automatisch eine eindeutige ID erzeugen&lt;br /&gt;
    if (!this.id) {&lt;br /&gt;
      if (!uids[this.localName]) {&lt;br /&gt;
        uids[this.localName] = 1;&lt;br /&gt;
      }&lt;br /&gt;
      this.id = `${this.localName.replace(/-/g, &amp;#039;_&amp;#039;)}_${uids[this.localName]++}`;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Standardproperties der Basisklasse mit Komponentenproperties kombinieren&lt;br /&gt;
    this.properties = Object.assign(FtuiElement.properties, properties);&lt;br /&gt;
&lt;br /&gt;
    // Für alle Properties Getter/Setter und Default-Attribute anlegen&lt;br /&gt;
    this.initProperties(this.properties);&lt;br /&gt;
&lt;br /&gt;
    // Wenn die Komponente ein Template besitzt, Shadow DOM erzeugen&lt;br /&gt;
    if (typeof this.template === &amp;#039;function&amp;#039;) {&lt;br /&gt;
      this.createShadowRoot(this.template());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Merker für aktive Änderungen, wichtig für Output-/Two-Way-Bindings&lt;br /&gt;
    this.isActiveChange = {};&lt;br /&gt;
&lt;br /&gt;
    // Element beim globalen FTUI-Binding-System anmelden&lt;br /&gt;
    if (window.ftuiApp) {&lt;br /&gt;
      ftuiApp.attachBinding(this);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Erzeugt Shadow DOM aus einem HTML-Template-String&lt;br /&gt;
  createShadowRoot(content) {&lt;br /&gt;
    const elemTemplate = document.createElement(&amp;#039;template&amp;#039;);&lt;br /&gt;
    elemTemplate.innerHTML = content;&lt;br /&gt;
    this.attachShadow({ mode: &amp;#039;open&amp;#039; });&lt;br /&gt;
    this.shadowRoot.appendChild(elemTemplate.content.cloneNode(true));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Standardattribute, die jedes FTUI-Element besitzt&lt;br /&gt;
  static get properties() {&lt;br /&gt;
    return {&lt;br /&gt;
      hidden: false,&lt;br /&gt;
      disabled: false,&lt;br /&gt;
      readonly: false,&lt;br /&gt;
      margin: &amp;#039;&amp;#039;,&lt;br /&gt;
      padding: &amp;#039;&amp;#039;,&lt;br /&gt;
    };&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Attribute, bei deren Änderung attributeChangedCallback ausgelöst wird&lt;br /&gt;
  static get observedAttributes() {&lt;br /&gt;
    return [...Object.keys(FtuiElement.properties)];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Wandelt Property-Namen in HTML-Attributnamen um&lt;br /&gt;
  static convertToAttributes(properties) {&lt;br /&gt;
    return Object.keys(properties).map(property =&amp;gt; toKebabCase(property));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Wird vom Browser aufgerufen, wenn das Element in den DOM eingefügt wurde&lt;br /&gt;
  connectedCallback() {&lt;br /&gt;
    this.updateProperties();&lt;br /&gt;
&lt;br /&gt;
    // Hook für abgeleitete Komponenten&lt;br /&gt;
    if (typeof this.onConnected === &amp;#039;function&amp;#039;) {&lt;br /&gt;
      this.onConnected();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Wird aufgerufen, wenn sich ein beobachtetes Attribut ändert&lt;br /&gt;
  attributeChangedCallback(name, oldValue, newValue) {&lt;br /&gt;
    log(3, `${this.id} -  attributeChangedCallback name=${name}, oldValue=${oldValue}, newValue=${newValue}`);&lt;br /&gt;
&lt;br /&gt;
    // Hook für abgeleitete Komponenten&lt;br /&gt;
    if (typeof this.onAttributeChanged === &amp;#039;function&amp;#039;) {&lt;br /&gt;
      this.onAttributeChanged(name, newValue, oldValue);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const hasValue = newValue !== null &amp;amp;&amp;amp; newValue !== false;&lt;br /&gt;
&lt;br /&gt;
    // Standardattribute behandeln&lt;br /&gt;
    switch (name) {&lt;br /&gt;
      case &amp;#039;hidden&amp;#039;:&lt;br /&gt;
        this.style.display = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;#039;disabled&amp;#039;:&lt;br /&gt;
        this.style.filter = hasValue ? &amp;#039;sepia(1) saturate(0) blur(1px)&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
        this.style.pointerEvents = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;#039;readonly&amp;#039;:&lt;br /&gt;
        this.style.pointerEvents = hasValue ? &amp;#039;none&amp;#039; : &amp;#039;&amp;#039;;&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;#039;margin&amp;#039;: {&lt;br /&gt;
        // ftui-grid behandelt margin selbst&lt;br /&gt;
        if (this.tagName !== &amp;#039;FTUI-GRID&amp;#039;) {&lt;br /&gt;
          this.style.margin = isNumeric(newValue) ? newValue + &amp;#039;em&amp;#039; : newValue;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      case &amp;#039;padding&amp;#039;: {&lt;br /&gt;
        this.style.padding = isNumeric(newValue) ? newValue + &amp;#039;em&amp;#039; : newValue;&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Wird von Komponenten genutzt, wenn ein Benutzerwert geändert wurde&lt;br /&gt;
  submitChange(property, value) {&lt;br /&gt;
    this.isActiveChange[property] = true;&lt;br /&gt;
    this[property] = value;&lt;br /&gt;
    this.emitChangeEvent(property, value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Erzeugt z.B. valueChange aus value&lt;br /&gt;
  emitChangeEvent(attribute, value) {&lt;br /&gt;
    this.emitEvent(attribute + &amp;#039;Change&amp;#039;, value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Löst ein DOM CustomEvent aus&lt;br /&gt;
  emitEvent(name, value) {&lt;br /&gt;
    const event = new CustomEvent(name, { detail: value });&lt;br /&gt;
    this.dispatchEvent(event);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Initialisiert Properties abhängig vom Typ des Defaultwerts&lt;br /&gt;
  initProperties(properties) {&lt;br /&gt;
    Object.entries(properties).forEach(([name, defaultValue]) =&amp;gt; {&lt;br /&gt;
      const attr = toKebabCase(name);&lt;br /&gt;
&lt;br /&gt;
      if (typeof properties[name] === &amp;#039;boolean&amp;#039;) {&lt;br /&gt;
        this.defineBooleanProperty(name, attr);&lt;br /&gt;
        this.initBooleanAttribute(attr, defaultValue);&lt;br /&gt;
&lt;br /&gt;
      } else if (typeof properties[name] === &amp;#039;number&amp;#039;) {&lt;br /&gt;
        this.defineNumberProperty(name, attr);&lt;br /&gt;
        this.initAttribute(attr, defaultValue);&lt;br /&gt;
&lt;br /&gt;
      } else {&lt;br /&gt;
        this.defineStringProperty(name, attr);&lt;br /&gt;
        this.initAttribute(attr, defaultValue);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Setzt Default-Attribut, wenn es noch nicht existiert&lt;br /&gt;
  initAttribute(attr, value) {&lt;br /&gt;
    if (!this.hasAttribute(attr)) {&lt;br /&gt;
      this.setAttribute(attr, value);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Setzt Boolean-Attribut nur, wenn Default true ist&lt;br /&gt;
  initBooleanAttribute(attr, value) {&lt;br /&gt;
    if (!this.hasAttribute(attr) &amp;amp;&amp;amp; value) {&lt;br /&gt;
      this.setAttribute(attr, &amp;#039;&amp;#039;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Definiert Boolean-Property mit HTML-Attribut-Synchronisierung&lt;br /&gt;
  defineBooleanProperty(name, attr) {&lt;br /&gt;
    Object.defineProperty(this, name, {&lt;br /&gt;
      get() {&lt;br /&gt;
        return this.hasAttribute(attr)&lt;br /&gt;
          &amp;amp;&amp;amp; this.getAttribute(attr) !== &amp;#039;false&amp;#039;;&lt;br /&gt;
      },&lt;br /&gt;
      set(value) {&lt;br /&gt;
        if (value) {&lt;br /&gt;
          this.setAttribute(attr, &amp;#039;&amp;#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
          this.removeAttribute(attr);&lt;br /&gt;
        }&lt;br /&gt;
      },&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Definiert Number-Property&lt;br /&gt;
  defineNumberProperty(name, attr) {&lt;br /&gt;
    Object.defineProperty(this, name, {&lt;br /&gt;
      get() {&lt;br /&gt;
        return Number(this.getAttribute(attr));&lt;br /&gt;
      },&lt;br /&gt;
      set(value) {&lt;br /&gt;
        this.setAttribute(attr, value);&lt;br /&gt;
      },&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Definiert String-Property&lt;br /&gt;
  defineStringProperty(name, attr) {&lt;br /&gt;
    Object.defineProperty(this, name, {&lt;br /&gt;
      get() {&lt;br /&gt;
        return this.getAttribute(attr);&lt;br /&gt;
      },&lt;br /&gt;
      set(value) {&lt;br /&gt;
        this.setAttribute(attr, value);&lt;br /&gt;
      },&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Behandelt Defaultwerte beim Einfügen des Elements in den DOM&lt;br /&gt;
  updateProperties() {&lt;br /&gt;
    Object.entries(this.properties).forEach(([name, defaultValue]) =&amp;gt; {&lt;br /&gt;
      const attr = toKebabCase(name);&lt;br /&gt;
&lt;br /&gt;
      if (this.getAttribute(attr) === String(defaultValue)) {&lt;br /&gt;
        this.attributeChangedCallback(attr, null, defaultValue);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Mögliche Schwachstellen / Besonderheiten==&lt;br /&gt;
&lt;br /&gt;
1. **`Object.assign(FtuiElement.properties, properties)` mutiert die statischen Basiseigenschaften.**&lt;br /&gt;
   Sicherer wäre:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.properties = Object.assign({}, FtuiElement.properties, properties);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. **`observedAttributes` enthält nur Basiseigenschaften.**&lt;br /&gt;
   Kindklassen müssen eigene Attribute selbst hinzufügen.&lt;br /&gt;
&lt;br /&gt;
3. **Boolean-Erkennung `newValue !== false` ist etwas ungenau.**&lt;br /&gt;
   Attribute liefern normalerweise Strings oder `null`, nicht echtes `false`. Bei `disabled=&amp;quot;false&amp;quot;` funktioniert der Getter zwar korrekt, aber `attributeChangedCallback()` behandelt `&amp;quot;false&amp;quot;` trotzdem als vorhanden.&lt;br /&gt;
&lt;br /&gt;
4. **`initAttribute()` setzt auch leere Default-Strings als Attribute.**&lt;br /&gt;
   Dadurch entstehen Attribute wie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
margin=&amp;quot;&amp;quot;&lt;br /&gt;
padding=&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das ist nicht falsch, aber kann unnötige `attributeChangedCallback()`-Aufrufe erzeugen.&lt;br /&gt;
&lt;br /&gt;
5. **`createShadowRoot()` nutzt `innerHTML`.**&lt;br /&gt;
   Das ist normal für Templates, aber Template-Inhalte sollten kontrolliert sein.&lt;br /&gt;
&lt;br /&gt;
==Merksatz==&lt;br /&gt;
&lt;br /&gt;
Dieses Programm macht aus einer normalen Webcomponent eine **FTUI-kompatible Komponente mit Attributbindung, Defaultwerten, Shadow DOM und Change-Events**.&lt;/div&gt;</summary>
		<author><name>Chris T. Ludwig</name></author>
	</entry>
	<entry>
		<id>https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3&amp;diff=4881&amp;oldid=4868</id>
		<title>(FHEM) FTUI 3</title>
		<link rel="alternate" type="text/html" href="https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3&amp;diff=4881&amp;oldid=4868"/>
		<updated>2026-04-26T15:08:08Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Hauptstruktur&lt;/span&gt;&lt;/p&gt;
&lt;a href=&quot;https://tippvomtibb.de/wiki/index.php?title=(FHEM)_FTUI_3&amp;amp;diff=4881&amp;amp;oldid=4868&quot;&gt;Änderungen zeigen&lt;/a&gt;</summary>
		<author><name>Chris T. Ludwig</name></author>
	</entry>
</feed>