<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Steff</id>
	<title>Wikizone - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Steff"/>
	<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Spezial:Beitr%C3%A4ge/Steff"/>
	<updated>2026-05-06T12:23:51Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Job_Template&amp;diff=33109</id>
		<title>ProcessWire - Job Template</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Job_Template&amp;diff=33109"/>
		<updated>2025-12-12T09:02:15Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ProcessWire - Job Modul]]&lt;br /&gt;
&lt;br /&gt;
== Beispiel Setting für Jobs mit strukturierten Daten ==&lt;br /&gt;
Beispiel von SPPS&lt;br /&gt;
&lt;br /&gt;
=== Job Template ===&lt;br /&gt;
&lt;br /&gt;
==== Felder ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job_addresscountry&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 191,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addresscountry&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Land&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_addresslocality&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 188,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addresslocality&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Ort&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_addressregion&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 189,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addressregion&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job Region&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_maxvalue&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 185,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeInteger&amp;quot;,&lt;br /&gt;
        &amp;quot;zeroNotEmpty&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 10,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;min&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;max&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_minvalue&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 184,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeInteger&amp;quot;,&lt;br /&gt;
        &amp;quot;zeroNotEmpty&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 10,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;min&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;max&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_unittext&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 186,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_unittext&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Bezahlung pro&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=MONTH|Monat\n2=YEAR|Jahr\n3=HOUR|Stunde\n4=WEEK|Woche\n5=DAY|Tag&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_dateposted&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 179,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_dateposted&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job Datum&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeDatetime&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;htmlType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;dateSelectFormat&amp;quot;: &amp;quot;yMd&amp;quot;,&lt;br /&gt;
        &amp;quot;yearFrom&amp;quot;: 1922,&lt;br /&gt;
        &amp;quot;yearTo&amp;quot;: 2042,&lt;br /&gt;
        &amp;quot;yearLock&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;datepicker&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;timeInputSelect&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateInputFormat&amp;quot;: &amp;quot;Y-m-d&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;Datum des Postings&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultToday&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;dateOutputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeStep&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeInputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;yearRange&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_description&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 181,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_description&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_description&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeTextareaLanguage&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldCKEditor&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;rows&amp;quot;: 5,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterHannaCode&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;htmlOptions&amp;quot;: [&lt;br /&gt;
            2,&lt;br /&gt;
            4,&lt;br /&gt;
            16&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;langBlankInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;toolbar&amp;quot;: &amp;quot;Format, Styles, -, Bold, Italic, -, RemoveFormat\nNumberedList, BulletedList, -, Blockquote\nPWLink, Unlink, Anchor\nPWImage, Table, HorizontalRule, SpecialChar\nPasteText, PasteFromWord\nScayt, -, Sourcedialog\nJustifyCenter, JustifyLeft, JustifyRight&amp;quot;,&lt;br /&gt;
        &amp;quot;inlineMode&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useACF&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;usePurifier&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;formatTags&amp;quot;: &amp;quot;p;h1;h2;h3;h4;h5;h6;pre;address&amp;quot;,&lt;br /&gt;
        &amp;quot;contentsCss&amp;quot;: &amp;quot;/site/templates/modules/InputfieldCKEditor/contents.css&amp;quot;,&lt;br /&gt;
        &amp;quot;stylesSet&amp;quot;: &amp;quot;customstyles:/site/templates/modules/InputfieldCKEditor/mystyles.js&amp;quot;,&lt;br /&gt;
        &amp;quot;extraPlugins&amp;quot;: [&lt;br /&gt;
            &amp;quot;pwimage&amp;quot;,&lt;br /&gt;
            &amp;quot;pwlink&amp;quot;,&lt;br /&gt;
            &amp;quot;sourcedialog&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;removePlugins&amp;quot;: &amp;quot;image,magicline&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;imageFields&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;toggles&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;extraAllowedContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentsInlineCss&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;customOptions&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;plugin_sourcedialog&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_employmenttype&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 192,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_employmenttype&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Art der Anstellung&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=FULL_TIME|Vollzeit\n2=PART_TIME|Teilzeit\n3=CONTRACTOR|Vertrag\n4=TEMPORARY|Zeitarbeit\n5=INTERN|Internship (Trainee etc.)\n6=VOLUNTEER|Volontariat\n7=PER_DIEM|Per diem\n8=OTHER|Andere&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_link&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 178,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_link&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Link zum Jobangebot&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeURL&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;noRelative&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowIDN&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowQuotes&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;addRoot&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 1024,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_logo&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 183,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_logo&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Logo&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeImage&amp;quot;,&lt;br /&gt;
        &amp;quot;fileSchema&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;extensions&amp;quot;: &amp;quot;gif jpg jpeg png&amp;quot;,&lt;br /&gt;
        &amp;quot;maxFiles&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;outputFormat&amp;quot;: 2,&lt;br /&gt;
        &amp;quot;descriptionRows&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;useTags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;gridMode&amp;quot;: &amp;quot;grid&amp;quot;,&lt;br /&gt;
        &amp;quot;focusMode&amp;quot;: &amp;quot;on&amp;quot;,&lt;br /&gt;
        &amp;quot;resizeServer&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;clientQuality&amp;quot;: 90,&lt;br /&gt;
        &amp;quot;maxReject&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dimensionsByAspectRatio&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValuePage&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldImage&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;optional&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;outputString&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;entityEncode&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tagsList&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;unzip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;overwrite&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxHeight&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;minWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;minHeight&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;aspect_ratios&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_organizationname&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 193,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_organizationname&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Name der Organisation&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=intensiv|SPPS Karlsruhe Intensiv\n2=karlsruhe|SPPS Karlsruhe\n3=rastatt|SPPS Ötigheim/Rastatt\n4=pforzheim|SPPS Pforzheim\n5=rheinhausen|SPPS Rheinhausen-Oberhausen\n6=tagespflege|Tagespflege Etje&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_organizationname_old&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 182,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_organizationname_old&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Name der Organisation&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_postalcode&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 190,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_postalcode&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;PLZ&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_streetaddress&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 187,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_streetaddress&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Adresse&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_validthrough&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 180,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_validthrough&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Gültig bis&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeDatetime&amp;quot;,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;htmlType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;dateSelectFormat&amp;quot;: &amp;quot;yMd&amp;quot;,&lt;br /&gt;
        &amp;quot;yearFrom&amp;quot;: 1922,&lt;br /&gt;
        &amp;quot;yearTo&amp;quot;: 2042,&lt;br /&gt;
        &amp;quot;yearLock&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;datepicker&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;timeInputSelect&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateInputFormat&amp;quot;: &amp;quot;Y-m-d&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateOutputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeStep&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeInputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;yearRange&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultToday&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Options für:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_basesalary_unittext&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1=MONTH|Monat&lt;br /&gt;
2=YEAR|Jahr&lt;br /&gt;
3=HOUR|Stunde&lt;br /&gt;
4=WEEK|Woche&lt;br /&gt;
5=DAY|Tag&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_employmenttype&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1=FULL_TIME|Vollzeit&lt;br /&gt;
2=PART_TIME|Teilzeit&lt;br /&gt;
3=CONTRACTOR|Vertrag&lt;br /&gt;
4=TEMPORARY|Zeitarbeit&lt;br /&gt;
5=INTERN|Internship (Trainee etc.)&lt;br /&gt;
6=VOLUNTEER|Volontariat&lt;br /&gt;
7=PER_DIEM|Per diem&lt;br /&gt;
8=OTHER|Andere&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_organizationname&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kann genutzt werden wenn man mehrere Organisationen hat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Job Fieldset Page&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
&lt;br /&gt;
Das Feld fasst die anderen Felder in eines zusammen. So kann man sie einfacher handeln.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 177,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeFieldsetPage&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;Daten für ein Jobposting&amp;quot;,&lt;br /&gt;
        &amp;quot;icon&amp;quot;: &amp;quot;wrench&amp;quot;,&lt;br /&gt;
        &amp;quot;template_id&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;parent_id&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;repeaterLoading&amp;quot;: 2,&lt;br /&gt;
        &amp;quot;repeaterMaxItems&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;repeaterMinItems&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;repeaterFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;job_dateposted&amp;quot;,&lt;br /&gt;
            &amp;quot;job_validthrough&amp;quot;,&lt;br /&gt;
            &amp;quot;job_organizationname&amp;quot;,&lt;br /&gt;
            &amp;quot;job_description&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_unittext&amp;quot;,&lt;br /&gt;
            &amp;quot;job_streetaddress&amp;quot;,&lt;br /&gt;
            &amp;quot;job_postalcode&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addresslocality&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addressregion&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addresscountry&amp;quot;,&lt;br /&gt;
            &amp;quot;job_employmenttype&amp;quot;,&lt;br /&gt;
            &amp;quot;job_link&amp;quot;,&lt;br /&gt;
            &amp;quot;job_logo&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;job_dateposted&amp;quot;: {&lt;br /&gt;
                &amp;quot;icon&amp;quot;: &amp;quot;calendar&amp;quot;,&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Datum des Postings. Wenn leer wird das Erstelldatum dieser Seite verwendet.&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_validthrough&amp;quot;: {&lt;br /&gt;
                &amp;quot;icon&amp;quot;: &amp;quot;calendar&amp;quot;,&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Empfohlen. Unbefristet für manche Berufsgruppen erlaubt (z.B. Bedienungen)&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_organizationname&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_description&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_minvalue&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_maxvalue&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_unittext&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_streetaddress&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_postalcode&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addresslocality&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addressregion&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addresscountry&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_employmenttype&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_link&amp;quot;: {&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Wenn leer wird diese Seite genutzt.&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_logo&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Templates Import ====&lt;br /&gt;
Import Daten (Zulässige Kind/Elternseiten von Hand nachtragen)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 53,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldgroups_id&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cache_time&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useRoles&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;editRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;addRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;createRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;rolesPermissions&amp;quot;: [],&lt;br /&gt;
        &amp;quot;noInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;childrenTemplatesID&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;sortfield&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noChildren&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noParents&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childTemplates&amp;quot;: [],&lt;br /&gt;
        &amp;quot;parentTemplates&amp;quot;: [&lt;br /&gt;
            &amp;quot;jobs&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;allowPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowChangeUser&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;redirectLogin&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;urlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;https&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrls&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;slashPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;altFilename&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;guestSearchable&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;pageClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childNameFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pageLabelField&amp;quot;: &amp;quot;fa-user-circle-o title&amp;quot;,&lt;br /&gt;
        &amp;quot;noGlobal&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noMove&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noTrash&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noSettings&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noChangeTemplate&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noShortcut&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noUnpublish&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;compile&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;nameContentTab&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noCacheGetVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noCachePostVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;useCacheForUsers&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpire&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpirePages&amp;quot;: [],&lt;br /&gt;
        &amp;quot;cacheExpireSelector&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Stellenangebot&amp;quot;,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;titleNames&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noPrependTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noAppendTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;prependFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;appendFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pagefileSecure&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;tabContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tabChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;nameLabel&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;errorAction&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;connectedFieldID&amp;quot;: null,&lt;br /&gt;
        &amp;quot;ns&amp;quot;: &amp;quot;ProcessWire&amp;quot;,&lt;br /&gt;
        &amp;quot;_exportMode&amp;quot;: true,&lt;br /&gt;
        &amp;quot;roles&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;title&amp;quot;,&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;,&lt;br /&gt;
            &amp;quot;job&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;title&amp;quot;: [],&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jobs&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 55,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;jobs&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldgroups_id&amp;quot;: &amp;quot;jobs&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cache_time&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useRoles&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;editRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;addRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;createRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;rolesPermissions&amp;quot;: [],&lt;br /&gt;
        &amp;quot;noInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;childrenTemplatesID&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;sortfield&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noParents&amp;quot;: -1,&lt;br /&gt;
        &amp;quot;childTemplates&amp;quot;: [&lt;br /&gt;
            &amp;quot;job&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;parentTemplates&amp;quot;: [],&lt;br /&gt;
        &amp;quot;allowPageNum&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;allowChangeUser&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;redirectLogin&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;urlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;https&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrls&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;slashPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;altFilename&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;guestSearchable&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;pageClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childNameFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pageLabelField&amp;quot;: &amp;quot;fa-users title&amp;quot;,&lt;br /&gt;
        &amp;quot;noGlobal&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noMove&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noTrash&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noSettings&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noChangeTemplate&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noShortcut&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noUnpublish&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;compile&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;nameContentTab&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noCacheGetVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noCachePostVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;useCacheForUsers&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpire&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpirePages&amp;quot;: [],&lt;br /&gt;
        &amp;quot;cacheExpireSelector&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Stellenangebote&amp;quot;,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;titleNames&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noPrependTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noAppendTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;prependFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;appendFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pagefileSecure&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;tabContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tabChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;nameLabel&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;errorAction&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;connectedFieldID&amp;quot;: null,&lt;br /&gt;
        &amp;quot;ns&amp;quot;: &amp;quot;ProcessWire&amp;quot;,&lt;br /&gt;
        &amp;quot;_exportMode&amp;quot;: true,&lt;br /&gt;
        &amp;quot;roles&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;title&amp;quot;,&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;,&lt;br /&gt;
            &amp;quot;images&amp;quot;,&lt;br /&gt;
            &amp;quot;files&amp;quot;,&lt;br /&gt;
            &amp;quot;menu&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;title&amp;quot;: [],&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;: [],&lt;br /&gt;
            &amp;quot;images&amp;quot;: [],&lt;br /&gt;
            &amp;quot;files&amp;quot;: [],&lt;br /&gt;
            &amp;quot;menu&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Template Jobs ===&lt;br /&gt;
Todo besser als Layout-Block&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// JOBLIST&lt;br /&gt;
$joblist = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobs = pages(&amp;#039;template=job,sort=-published&amp;#039;);&lt;br /&gt;
foreach ($jobs as $item) {&lt;br /&gt;
  $joblist .= &amp;#039;&amp;lt;li class=&amp;quot;joblist-item&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039; (&amp;#039;.$item-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title.&amp;#039;)&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
$joblist = &amp;#039;&amp;lt;ul class=&amp;quot;joblist&amp;quot;&amp;gt;&amp;#039;.$joblist.&amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Template Job ===&lt;br /&gt;
Benötigt im Admin Bereich nur das job Feld. In diesem sind alle anderen benötigten Felder bereits enthalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
include_once(&amp;#039;includes/SchemaHelper.php&amp;#039;);&lt;br /&gt;
$sh = new SchemaHelper;&lt;br /&gt;
$jsonld = $sh-&amp;gt;jsonldJobPosting($page);&lt;br /&gt;
&lt;br /&gt;
// BEWERBUNGSFORMULAR WENN GEWÜNSCHT&lt;br /&gt;
$contact =  $forms-&amp;gt;render(&amp;#039;bewerbung&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
ob_start();&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;apply&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;&amp;lt;?=$page-&amp;gt;title?&amp;gt;&amp;lt;/h1&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;job-description&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_description?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;&amp;quot;&amp;gt;Arbeitgeber&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title?&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
	&amp;lt;?=$page-&amp;gt;link?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Arbeitsort&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_streetaddress?&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_postalcode?&amp;gt; &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_addresslocality?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php if ($page-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_maxvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_unittext): ?&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Vergütung&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_minvalue?&amp;gt;€ - &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_maxvalue?&amp;gt;€ &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php elseif($page-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_unittext): ?&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Vergütung&amp;lt;/div&amp;gt;&lt;br /&gt;
	&amp;lt;div&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_minvalue?&amp;gt;€ &amp;lt;?=$page-&amp;gt;unit-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php endif ?&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;font-heavy pt-20&amp;quot;&amp;gt;Art der Anstellung&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;pb-30&amp;quot;&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_employmenttype-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Bewerbungsmöglichkeit --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;apply-form&amp;quot; class=&amp;quot;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2&amp;gt;Bewerbung&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div&amp;gt;&amp;lt;?= $contact ?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- job ldjson --&amp;gt;&lt;br /&gt;
    &amp;lt;?=$jsonld?&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$content = ob_get_clean();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bewerbungsformular ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;required&amp;quot;: false,&lt;br /&gt;
    &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;roles&amp;quot;: {&lt;br /&gt;
        &amp;quot;form-submit&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;form-list&amp;quot;: [],&lt;br /&gt;
        &amp;quot;form-edit&amp;quot;: [],&lt;br /&gt;
        &amp;quot;form-delete&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-list&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-edit&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-delete&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-page&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-resend&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;flags&amp;quot;: 256,&lt;br /&gt;
    &amp;quot;pluginActions&amp;quot;: [],&lt;br /&gt;
    &amp;quot;framework&amp;quot;: &amp;quot;Uikit3&amp;quot;,&lt;br /&gt;
    &amp;quot;allowPreset&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;skipSessionKey&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;useCookies&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;partialEntryDays&amp;quot;: 14,&lt;br /&gt;
    &amp;quot;spamEntryDays&amp;quot;: 7,&lt;br /&gt;
    &amp;quot;submitText&amp;quot;: &amp;quot;Absenden&amp;quot;,&lt;br /&gt;
    &amp;quot;successMessage&amp;quot;: &amp;quot;Vielen Dank - Ihre Bewerbung wurde versendet.&amp;quot;,&lt;br /&gt;
    &amp;quot;errorMessage&amp;quot;: &amp;quot;Ein Fehler ist aufgetreten. Bitte überprüfen Sie Ihre Eingaben.&amp;quot;,&lt;br /&gt;
    &amp;quot;mobilePx&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;frBasic_noLoad&amp;quot;: [],&lt;br /&gt;
    &amp;quot;frBasic_cssURL&amp;quot;: &amp;quot;/site/modules/FormBuilder/frameworks/basic/main.css&amp;quot;,&lt;br /&gt;
    &amp;quot;frBasic_itemContent&amp;quot;: [&lt;br /&gt;
        &amp;quot;description&amp;quot;,&lt;br /&gt;
        &amp;quot;out&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;spamFlags&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;listFields&amp;quot;: [],&lt;br /&gt;
    &amp;quot;entryDays&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;emailSubject&amp;quot;: &amp;quot;Bewerbungsformular auf salus-klinik.de&amp;quot;,&lt;br /&gt;
    &amp;quot;responderSubject&amp;quot;: &amp;quot;Auto-Response&amp;quot;,&lt;br /&gt;
    &amp;quot;saveFlags&amp;quot;: 35,&lt;br /&gt;
    &amp;quot;spamWords&amp;quot;: [],&lt;br /&gt;
    &amp;quot;honeypot&amp;quot;: &amp;quot;name_1&amp;quot;,&lt;br /&gt;
    &amp;quot;emailTo&amp;quot;: &amp;quot;post@stephanschlegel.de&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_noLoad&amp;quot;: [&lt;br /&gt;
        &amp;quot;framework&amp;quot;,&lt;br /&gt;
        &amp;quot;jquery&amp;quot;,&lt;br /&gt;
        &amp;quot;jqueryui&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;frUikit3_ukURL&amp;quot;: &amp;quot;/site/modules/FormBuilder/frameworks/uikit3/&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_css&amp;quot;: &amp;quot;uikit.min.css&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_horizontal&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_inlineErrorBelow&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_horizHeaderWidth&amp;quot;: 30,&lt;br /&gt;
    &amp;quot;frUikit3_buttonType&amp;quot;: &amp;quot;primary&amp;quot;,&lt;br /&gt;
    &amp;quot;children&amp;quot;: {&lt;br /&gt;
        &amp;quot;name_1&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: false,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name_2&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;e_mail&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Email&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;E-Mail&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 250,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;telefon&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Telefon&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;bewerbungsunterlagen&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;FormBuilderFile&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Bewerbungsunterlagen&amp;quot;,&lt;br /&gt;
            &amp;quot;notes&amp;quot;: &amp;quot;Maximal 3 Dateien á 5MB&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: false,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;extensions&amp;quot;: &amp;quot;pdf doc docx xls xlsx gif jpg jpeg png&amp;quot;,&lt;br /&gt;
            &amp;quot;maxFiles&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;maxFileSize&amp;quot;: 5242880&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Layout Block - Job-Liste ===&lt;br /&gt;
Beispiel Salus&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
$sectionClasses = array($page-&amp;gt;_type);&lt;br /&gt;
$containerClasses = array(&amp;#039;ani section&amp;#039;);&lt;br /&gt;
if($page-&amp;gt;bg &amp;amp;&amp;amp; $page-&amp;gt;bg-&amp;gt;value) {&lt;br /&gt;
    $colorClassBorder = $page-&amp;gt;bg-&amp;gt;value;&lt;br /&gt;
    $colorClassContent = $page-&amp;gt;bg-&amp;gt;value;&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
    $colorClassBorder = &amp;#039;bc1&amp;#039;;&lt;br /&gt;
    $colorClassContent = &amp;#039;bc1&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobsMarkup = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobsAccordion = new Box;&lt;br /&gt;
$jobs = pages(&amp;#039;template=job,sort=-published&amp;#039;);&lt;br /&gt;
foreach ($jobs as $item) {&lt;br /&gt;
&lt;br /&gt;
    $jobsMarkup .= &amp;#039;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;bc1 joblist-item&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;a class=&amp;quot;uk-accordion-title uk-padding-small&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;#039;.$item-&amp;gt;title.&amp;#039;&lt;br /&gt;
        &amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-accordion-content uk-padding-small nmt npt&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&amp;#039;.$item-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title.&amp;#039;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Arbeitsort:&amp;lt;/strong&amp;gt; &amp;#039;.$item-&amp;gt;job-&amp;gt;job_addresslocality.&amp;#039;&amp;lt;br&amp;gt;&lt;br /&gt;
          &amp;lt;strong&amp;gt;Art der Anstellung: &amp;lt;/strong&amp;gt;&amp;#039;.$item-&amp;gt;job-&amp;gt;job_employmenttype-&amp;gt;title.&amp;#039;&amp;lt;/p&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;a class=&amp;quot;uk-button uk-button-primary&amp;quot; href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;Zur Stellenbeschreibung&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$jobsAccordion-&amp;gt;addClasses(&amp;#039;accordion uk-accordion nmb&amp;#039;);&lt;br /&gt;
$jobsAccordion-&amp;gt;addAttributes(&amp;#039;uk-accordion=&amp;quot;&amp;quot;&amp;#039;); // i.e. active:0&lt;br /&gt;
$out .= $jobsAccordion-&amp;gt;wrap($jobsMarkup,&amp;#039;ul&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// RANDSPALTE?&lt;br /&gt;
$out = &amp;#039;&lt;br /&gt;
&amp;lt;div class=&amp;quot;uk-grid uk-grid-collapse uk-grid-match&amp;quot; uk-grid&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;uk-visible@m uk-width-1-5 &amp;#039;.$colorClassBorder.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-padding-small&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div class=&amp;quot;uk-width-expand@m&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-padding npt npb npr&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;#039;.renderHeadline($page).&amp;#039;&lt;br /&gt;
            &amp;#039;. $out .&amp;#039;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
//$out = renderContainer($page,$out,$containerClasses);&lt;br /&gt;
$out = renderSection($page,$out,$sectionClasses,array(&amp;#039;skipDefaultClasses&amp;#039;=&amp;gt;false));&lt;br /&gt;
return $out;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Bewerberformular vorausfüllen mit verschiedenen Ansprechpartnern ====&lt;br /&gt;
Das Formular soll versendet werden mit &lt;br /&gt;
- Titel der Stellenanzeige (nicht veränderbar)&lt;br /&gt;
- Name der Einrichtung (nicht veränderbar)&lt;br /&gt;
- an verschiedene E-Mail Adressen, je nach Einrichtung für die die Stellenanzeige gilt.&lt;br /&gt;
&lt;br /&gt;
ready.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
if(!defined(&amp;quot;PROCESSWIRE&amp;quot;)) die();&lt;br /&gt;
&lt;br /&gt;
$emailList = array(&lt;br /&gt;
  &amp;#039;intensiv&amp;#039; =&amp;gt; &amp;#039;intensiv@sp-ps.de&amp;#039;,&lt;br /&gt;
  &amp;#039;karlsruhe&amp;#039; =&amp;gt; &amp;#039;info@sp-ps.de&amp;#039;,&lt;br /&gt;
  &amp;#039;rastatt&amp;#039; =&amp;gt; &amp;#039;oetigheim@sp-ps.de&amp;#039;,&lt;br /&gt;
  &amp;#039;pforzheim&amp;#039; =&amp;gt; &amp;#039;info-pf@sp-ps.de&amp;#039;,&lt;br /&gt;
  &amp;#039;rheinhausen&amp;#039; =&amp;gt; &amp;#039;info-oh@sp-ps.de&amp;#039;,&lt;br /&gt;
  &amp;#039;tagespflege&amp;#039; =&amp;gt; &amp;#039;oetigheim@sp-ps.de&amp;#039;,&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
// HOOKS FÜR BEWERBUNG IM JOBTEMPLATE&lt;br /&gt;
if($page-&amp;gt;template-&amp;gt;name==&amp;#039;job&amp;#039;){&lt;br /&gt;
  $formname = &amp;#039;schnellkontakt&amp;#039;;&lt;br /&gt;
  // E-Mails (Wert aus Template &amp;#039;job&amp;#039; Feld: job_organizationname =&amp;gt; Mailadresse)&lt;br /&gt;
  $organization = $page-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title;&lt;br /&gt;
  $organizationName = $page-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;value;&lt;br /&gt;
  $jobtitle = $page-&amp;gt;title;&lt;br /&gt;
&lt;br /&gt;
  $wire-&amp;gt;addHookBefore(&amp;#039;FormBuilderProcessor::renderReady&amp;#039;, &lt;br /&gt;
    function($event) use($organization, $jobtitle, $formname) {&lt;br /&gt;
      &lt;br /&gt;
      $form = $event-&amp;gt;arguments(0);&lt;br /&gt;
      if($form-&amp;gt;name !== $formname) return;&lt;br /&gt;
      $form-&amp;gt;getChildByName(&amp;#039;ich_bewerbe_mich_fur_folgende_einrichtung&amp;#039;)&lt;br /&gt;
        -&amp;gt;val($organization)&lt;br /&gt;
        -&amp;gt;attr(&amp;#039;disabled&amp;#039;, &amp;#039;disabled&amp;#039;); &lt;br /&gt;
      $form-&amp;gt;getChildByName(&amp;#039;ich_bewerbe_mich_als&amp;#039;)&lt;br /&gt;
        -&amp;gt;val($jobtitle)&lt;br /&gt;
        -&amp;gt;attr(&amp;#039;disabled&amp;#039;, &amp;#039;disabled&amp;#039;);&lt;br /&gt;
    }&lt;br /&gt;
  ); &lt;br /&gt;
  // nach dem übermitteln der eingaben (user kann nichts mehr ändern)&lt;br /&gt;
  $wire-&amp;gt;addHook(&amp;#039;FormBuilderProcessor::processInputDone&amp;#039;, &lt;br /&gt;
    function($event) use($organization, $jobtitle, $formname) {&lt;br /&gt;
      $form = $event-&amp;gt;arguments(0);&lt;br /&gt;
      if($form-&amp;gt;name !== $formname) return;&lt;br /&gt;
      $form-&amp;gt;getChildByName(&amp;#039;ich_bewerbe_mich_fur_folgende_einrichtung&amp;#039;)-&amp;gt;val($organization);&lt;br /&gt;
      $form-&amp;gt;getChildByName(&amp;#039;ich_bewerbe_mich_als&amp;#039;)-&amp;gt;val($jobtitle);  &lt;br /&gt;
    }&lt;br /&gt;
  ); &lt;br /&gt;
  // change email based on job&lt;br /&gt;
  $wire-&amp;gt;addHookBefore(&amp;#039;FormBuilderProcessor::emailForm&amp;#039;, &lt;br /&gt;
    function($event) use($organizationName, $emailList, $formname) {&lt;br /&gt;
      $processor = $event-&amp;gt;object;&lt;br /&gt;
      if($processor-&amp;gt;formName != $formname) return; &lt;br /&gt;
      if(array_key_exists($organizationName,$emailList)){&lt;br /&gt;
        $processor-&amp;gt;emailTo = $emailList[$organizationName]; // tell FormBuilder to use that email&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  );&lt;br /&gt;
}else{&lt;br /&gt;
  // HOOKS FÜR INITIATIVBEWERBUNG&lt;br /&gt;
  // change email based on job&lt;br /&gt;
  $wire-&amp;gt;addHookBefore(&amp;#039;FormBuilderProcessor::emailForm&amp;#039;, &lt;br /&gt;
    function($event) use($emailList) {&lt;br /&gt;
      $processor = $event-&amp;gt;object;&lt;br /&gt;
      if($processor-&amp;gt;formName != &amp;#039;initiativbewerbung&amp;#039;) return; &lt;br /&gt;
      $form = $event-&amp;gt;arguments(0);&lt;br /&gt;
      $name = $form-&amp;gt;getChildByName(&amp;#039;ich_bewerbe_mich_fur_folgende_einrichtung&amp;#039;)-&amp;gt;val();&lt;br /&gt;
      if(array_key_exists($name,$emailList)){&lt;br /&gt;
        $processor-&amp;gt;emailTo = $emailList[$name]; // tell FormBuilder to use that email&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Funktionalität ===&lt;br /&gt;
==== SchemaHelper ====&lt;br /&gt;
Für Erzeugung der Strukturierten Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
/**&lt;br /&gt;
 * SchemaHelper&lt;br /&gt;
 * Class for structured data&lt;br /&gt;
 * V1.0&lt;br /&gt;
 */&lt;br /&gt;
// @todo outsource some of the nessecary types (i.e. place) in backend use&lt;br /&gt;
// fieldgroups for that maybe s.th. like $place = getFg(&amp;#039;schema_place&amp;#039;)&lt;br /&gt;
class SchemaHelper{&lt;br /&gt;
	// Load the requested schema from the schemas directory and register the class&lt;br /&gt;
	public function jsonldJobPosting ($p) {&lt;br /&gt;
		$jsonld = array();&lt;br /&gt;
		$sanitizer = wire(&amp;#039;sanitizer&amp;#039;);&lt;br /&gt;
		//set unset fields (for not mandatory fields)&lt;br /&gt;
		$p-&amp;gt;job-&amp;gt;job_validthrough = $p-&amp;gt;job-&amp;gt;job_validthrough ? : &amp;#039;&amp;#039;; // todo test&lt;br /&gt;
&lt;br /&gt;
		$jsonld[&amp;quot;@context&amp;quot;] = &amp;quot;http://schema.org/&amp;quot;;&lt;br /&gt;
		$jsonld[&amp;quot;@type&amp;quot;] = &amp;quot;JobPosting&amp;quot;;&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;job_link) $jsonld[&amp;quot;url&amp;quot;] = $p-&amp;gt;job-&amp;gt;job_link;&lt;br /&gt;
		else $jsonld[&amp;quot;url&amp;quot;] = $sanitizer-&amp;gt;url($p-&amp;gt;httpUrl);&lt;br /&gt;
		$jsonld[&amp;quot;datePosted&amp;quot;] = !empty($p-&amp;gt;job-&amp;gt;job_dateposted) ? date(&amp;#039;Y-m-d&amp;#039;, $p-&amp;gt;job-&amp;gt;getUnformatted(&amp;#039;job_dateposted&amp;#039;) ) : date(&amp;#039;Y-m-d&amp;#039;, strtotime($p-&amp;gt;created));&lt;br /&gt;
		$jsonld[&amp;quot;validThrough&amp;quot;] = date(&amp;#039;Y-m-d&amp;#039;, $p-&amp;gt;job-&amp;gt;getUnformatted(&amp;#039;job_validthrough&amp;#039;) );&lt;br /&gt;
		$jsonld[&amp;quot;description&amp;quot;] = $sanitizer-&amp;gt;textarea($p-&amp;gt;job-&amp;gt;job_description);&lt;br /&gt;
		$jsonld[&amp;#039;hiringOrganization&amp;#039;] = array(&lt;br /&gt;
			&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;Organization&amp;quot;,&lt;br /&gt;
			&amp;quot;name&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title),&lt;br /&gt;
			&amp;quot;sameAs&amp;quot; =&amp;gt; $sanitizer-&amp;gt;url($p-&amp;gt;job-&amp;gt;job_link)&lt;br /&gt;
		);&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;link2)$jsonld[&amp;#039;hiringOrganization&amp;#039;][&amp;#039;logo&amp;#039;] = $p-&amp;gt;job-&amp;gt;link2;&lt;br /&gt;
		$jsonld[&amp;#039;title&amp;#039;] = $sanitizer-&amp;gt;text($p-&amp;gt;title);&lt;br /&gt;
&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_maxvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_unittext){&lt;br /&gt;
			$jsonld[&amp;#039;baseSalary&amp;#039;] = array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;MonetaryAmount&amp;quot;,&lt;br /&gt;
				&amp;quot;currency&amp;quot; =&amp;gt; &amp;quot;EUR&amp;quot;,&lt;br /&gt;
				&amp;quot;value&amp;quot; =&amp;gt; array(&lt;br /&gt;
					&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;QuantitativeValue&amp;quot;,&lt;br /&gt;
					&amp;quot;minValue&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue),&lt;br /&gt;
					&amp;quot;maxValue&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_maxvalue),&lt;br /&gt;
					&amp;quot;unitText&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;value)&lt;br /&gt;
				)&lt;br /&gt;
			);&lt;br /&gt;
		}else if($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_unittext){&lt;br /&gt;
			$jsonld[&amp;#039;baseSalary&amp;#039;] = array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;MonetaryAmount&amp;quot;,&lt;br /&gt;
				&amp;quot;currency&amp;quot; =&amp;gt; &amp;quot;EUR&amp;quot;,&lt;br /&gt;
				&amp;quot;value&amp;quot; =&amp;gt; array(&lt;br /&gt;
					&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;QuantitativeValue&amp;quot;,&lt;br /&gt;
					&amp;quot;value&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue),&lt;br /&gt;
					&amp;quot;unitText&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;value)&lt;br /&gt;
				)&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		$jsonld[&amp;#039;jobLocation&amp;#039;] = array(&lt;br /&gt;
			&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;Place&amp;quot;,&lt;br /&gt;
			&amp;quot;address&amp;quot; =&amp;gt; array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;PostalAddress&amp;quot;,&lt;br /&gt;
				&amp;quot;streetAddress&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_streetaddress),&lt;br /&gt;
				&amp;quot;addressLocality&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addresslocality),&lt;br /&gt;
				&amp;quot;addressRegion&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addressregion),&lt;br /&gt;
				&amp;quot;postalCode&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_postalcode),&lt;br /&gt;
				&amp;quot;addressCountry&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addresscountry),&lt;br /&gt;
			)&lt;br /&gt;
		);&lt;br /&gt;
		// recommended properties&lt;br /&gt;
&lt;br /&gt;
		if($c = count($p-&amp;gt;job-&amp;gt;job_employmenttype)){&lt;br /&gt;
			$types = array();&lt;br /&gt;
			foreach($p-&amp;gt;job-&amp;gt;job_employmenttype as $type){&lt;br /&gt;
				$types[] = $sanitizer-&amp;gt;text($type-&amp;gt;value);&lt;br /&gt;
			}&lt;br /&gt;
			//var_dump($c);&lt;br /&gt;
			if($c &amp;gt; 1) $jsonld[&amp;#039;employmentType&amp;#039;] = $types;&lt;br /&gt;
			else $jsonld[&amp;#039;employmentType&amp;#039;] = $types[0];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		//$out .= &amp;#039;&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&amp;#039; . json_encode($jsonld) . &amp;#039;&amp;lt;/script&amp;gt;&amp;#039;;&lt;br /&gt;
		$out = &amp;#039;&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&amp;#039; . json_encode($jsonld,JSON_PRETTY_PRINT) . &amp;#039;&amp;lt;/script&amp;gt;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
		return $out;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Job_Template&amp;diff=33108</id>
		<title>ProcessWire - Job Template</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Job_Template&amp;diff=33108"/>
		<updated>2025-12-12T08:41:09Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ProcessWire - Job Modul]]&lt;br /&gt;
&lt;br /&gt;
== Beispiel Setting für Jobs mit strukturierten Daten ==&lt;br /&gt;
Beispiel von SPPS&lt;br /&gt;
&lt;br /&gt;
=== Job Template ===&lt;br /&gt;
&lt;br /&gt;
==== Felder ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job_addresscountry&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 191,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addresscountry&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Land&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_addresslocality&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 188,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addresslocality&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Ort&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_addressregion&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 189,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_addressregion&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job Region&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_maxvalue&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 185,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeInteger&amp;quot;,&lt;br /&gt;
        &amp;quot;zeroNotEmpty&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 10,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;min&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;max&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_minvalue&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 184,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeInteger&amp;quot;,&lt;br /&gt;
        &amp;quot;zeroNotEmpty&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 10,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;min&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;max&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_basesalary_unittext&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 186,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_basesalary_unittext&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Bezahlung pro&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 33,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=MONTH|Monat\n2=YEAR|Jahr\n3=HOUR|Stunde\n4=WEEK|Woche\n5=DAY|Tag&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_dateposted&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 179,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_dateposted&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job Datum&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeDatetime&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;htmlType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;dateSelectFormat&amp;quot;: &amp;quot;yMd&amp;quot;,&lt;br /&gt;
        &amp;quot;yearFrom&amp;quot;: 1922,&lt;br /&gt;
        &amp;quot;yearTo&amp;quot;: 2042,&lt;br /&gt;
        &amp;quot;yearLock&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;datepicker&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;timeInputSelect&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateInputFormat&amp;quot;: &amp;quot;Y-m-d&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;Datum des Postings&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultToday&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;dateOutputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeStep&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeInputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;yearRange&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_description&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 181,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_description&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;job_description&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeTextareaLanguage&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldCKEditor&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;rows&amp;quot;: 5,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterHannaCode&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;htmlOptions&amp;quot;: [&lt;br /&gt;
            2,&lt;br /&gt;
            4,&lt;br /&gt;
            16&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;langBlankInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;toolbar&amp;quot;: &amp;quot;Format, Styles, -, Bold, Italic, -, RemoveFormat\nNumberedList, BulletedList, -, Blockquote\nPWLink, Unlink, Anchor\nPWImage, Table, HorizontalRule, SpecialChar\nPasteText, PasteFromWord\nScayt, -, Sourcedialog\nJustifyCenter, JustifyLeft, JustifyRight&amp;quot;,&lt;br /&gt;
        &amp;quot;inlineMode&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useACF&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;usePurifier&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;formatTags&amp;quot;: &amp;quot;p;h1;h2;h3;h4;h5;h6;pre;address&amp;quot;,&lt;br /&gt;
        &amp;quot;contentsCss&amp;quot;: &amp;quot;/site/templates/modules/InputfieldCKEditor/contents.css&amp;quot;,&lt;br /&gt;
        &amp;quot;stylesSet&amp;quot;: &amp;quot;customstyles:/site/templates/modules/InputfieldCKEditor/mystyles.js&amp;quot;,&lt;br /&gt;
        &amp;quot;extraPlugins&amp;quot;: [&lt;br /&gt;
            &amp;quot;pwimage&amp;quot;,&lt;br /&gt;
            &amp;quot;pwlink&amp;quot;,&lt;br /&gt;
            &amp;quot;sourcedialog&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;removePlugins&amp;quot;: &amp;quot;image,magicline&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;imageFields&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;toggles&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;extraAllowedContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentsInlineCss&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;customOptions&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;plugin_sourcedialog&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_employmenttype&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 192,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_employmenttype&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Art der Anstellung&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=FULL_TIME|Vollzeit\n2=PART_TIME|Teilzeit\n3=CONTRACTOR|Vertrag\n4=TEMPORARY|Zeitarbeit\n5=INTERN|Internship (Trainee etc.)\n6=VOLUNTEER|Volontariat\n7=PER_DIEM|Per diem\n8=OTHER|Andere&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_link&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 178,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_link&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Link zum Jobangebot&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeURL&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;noRelative&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowIDN&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowQuotes&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;addRoot&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 1024,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_logo&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 183,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_logo&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Logo&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeImage&amp;quot;,&lt;br /&gt;
        &amp;quot;fileSchema&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;extensions&amp;quot;: &amp;quot;gif jpg jpeg png&amp;quot;,&lt;br /&gt;
        &amp;quot;maxFiles&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;outputFormat&amp;quot;: 2,&lt;br /&gt;
        &amp;quot;descriptionRows&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;useTags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;gridMode&amp;quot;: &amp;quot;grid&amp;quot;,&lt;br /&gt;
        &amp;quot;focusMode&amp;quot;: &amp;quot;on&amp;quot;,&lt;br /&gt;
        &amp;quot;resizeServer&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;clientQuality&amp;quot;: 90,&lt;br /&gt;
        &amp;quot;maxReject&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dimensionsByAspectRatio&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValuePage&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldImage&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;optional&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;outputString&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;entityEncode&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tagsList&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;unzip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;overwrite&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxHeight&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;maxSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;minWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;minHeight&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;aspect_ratios&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_organizationname&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 193,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_organizationname&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Name der Organisation&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeOptions&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;InputfieldSelect&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultValue&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;export_options&amp;quot;: {&lt;br /&gt;
            &amp;quot;default&amp;quot;: &amp;quot;1=intensiv|SPPS Karlsruhe Intensiv\n2=karlsruhe|SPPS Karlsruhe\n3=rastatt|SPPS Ötigheim/Rastatt\n4=pforzheim|SPPS Pforzheim\n5=rheinhausen|SPPS Rheinhausen-Oberhausen\n6=tagespflege|Tagespflege Etje&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_organizationname_old&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 182,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_organizationname_old&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Name der Organisation&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_postalcode&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 190,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_postalcode&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;PLZ&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_streetaddress&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 187,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_streetaddress&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Adresse&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeText&amp;quot;,&lt;br /&gt;
        &amp;quot;textformatters&amp;quot;: [&lt;br /&gt;
            &amp;quot;TextformatterEntities&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
        &amp;quot;showCount&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputfieldClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputSize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeInputWidth&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBlank&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;stripTags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pattern&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;job_validthrough&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 180,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job_validthrough&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Gültig bis&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeDatetime&amp;quot;,&lt;br /&gt;
        &amp;quot;inputType&amp;quot;: &amp;quot;text&amp;quot;,&lt;br /&gt;
        &amp;quot;htmlType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;dateSelectFormat&amp;quot;: &amp;quot;yMd&amp;quot;,&lt;br /&gt;
        &amp;quot;yearFrom&amp;quot;: 1922,&lt;br /&gt;
        &amp;quot;yearTo&amp;quot;: 2042,&lt;br /&gt;
        &amp;quot;yearLock&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;datepicker&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;timeInputSelect&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateInputFormat&amp;quot;: &amp;quot;Y-m-d&amp;quot;,&lt;br /&gt;
        &amp;quot;size&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 25,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;dateOutputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredAttr&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;dateMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeStep&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMin&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeMax&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;timeInputFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;placeholder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;yearRange&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;defaultToday&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Options für:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_basesalary_unittext&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1=MONTH|Monat&lt;br /&gt;
2=YEAR|Jahr&lt;br /&gt;
3=HOUR|Stunde&lt;br /&gt;
4=WEEK|Woche&lt;br /&gt;
5=DAY|Tag&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_employmenttype&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1=FULL_TIME|Vollzeit&lt;br /&gt;
2=PART_TIME|Teilzeit&lt;br /&gt;
3=CONTRACTOR|Vertrag&lt;br /&gt;
4=TEMPORARY|Zeitarbeit&lt;br /&gt;
5=INTERN|Internship (Trainee etc.)&lt;br /&gt;
6=VOLUNTEER|Volontariat&lt;br /&gt;
7=PER_DIEM|Per diem&lt;br /&gt;
8=OTHER|Andere&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;job_organizationname&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kann genutzt werden wenn man mehrere Organisationen hat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Job Fieldset Page&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
&lt;br /&gt;
Das Feld fasst die anderen Felder in eines zusammen. So kann man sie einfacher handeln.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 177,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Job&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;FieldtypeFieldsetPage&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;: &amp;quot;Daten für ein Jobposting&amp;quot;,&lt;br /&gt;
        &amp;quot;icon&amp;quot;: &amp;quot;wrench&amp;quot;,&lt;br /&gt;
        &amp;quot;template_id&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;parent_id&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;repeaterLoading&amp;quot;: 2,&lt;br /&gt;
        &amp;quot;repeaterMaxItems&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;repeaterMinItems&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;collapsed&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;repeaterFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;job_dateposted&amp;quot;,&lt;br /&gt;
            &amp;quot;job_validthrough&amp;quot;,&lt;br /&gt;
            &amp;quot;job_organizationname&amp;quot;,&lt;br /&gt;
            &amp;quot;job_description&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_minvalue&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_maxvalue&amp;quot;,&lt;br /&gt;
            &amp;quot;job_basesalary_unittext&amp;quot;,&lt;br /&gt;
            &amp;quot;job_streetaddress&amp;quot;,&lt;br /&gt;
            &amp;quot;job_postalcode&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addresslocality&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addressregion&amp;quot;,&lt;br /&gt;
            &amp;quot;job_addresscountry&amp;quot;,&lt;br /&gt;
            &amp;quot;job_employmenttype&amp;quot;,&lt;br /&gt;
            &amp;quot;job_link&amp;quot;,&lt;br /&gt;
            &amp;quot;job_logo&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;showIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeOffset&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeBorder&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;themeColor&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;columnWidth&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;required&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;requiredIf&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;job_dateposted&amp;quot;: {&lt;br /&gt;
                &amp;quot;icon&amp;quot;: &amp;quot;calendar&amp;quot;,&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Datum des Postings. Wenn leer wird das Erstelldatum dieser Seite verwendet.&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_validthrough&amp;quot;: {&lt;br /&gt;
                &amp;quot;icon&amp;quot;: &amp;quot;calendar&amp;quot;,&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Empfohlen. Unbefristet für manche Berufsgruppen erlaubt (z.B. Bedienungen)&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_organizationname&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_description&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_minvalue&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_maxvalue&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_basesalary_unittext&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_streetaddress&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_postalcode&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addresslocality&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addressregion&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_addresscountry&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_employmenttype&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job_link&amp;quot;: {&lt;br /&gt;
                &amp;quot;notes&amp;quot;: &amp;quot;Wenn leer wird diese Seite genutzt.&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;job_logo&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Templates Import ====&lt;br /&gt;
Import Daten (Zulässige Kind/Elternseiten von Hand nachtragen)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;job&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 53,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldgroups_id&amp;quot;: &amp;quot;job&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cache_time&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useRoles&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;editRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;addRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;createRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;rolesPermissions&amp;quot;: [],&lt;br /&gt;
        &amp;quot;noInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;childrenTemplatesID&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;sortfield&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noChildren&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noParents&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childTemplates&amp;quot;: [],&lt;br /&gt;
        &amp;quot;parentTemplates&amp;quot;: [&lt;br /&gt;
            &amp;quot;jobs&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;allowPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;allowChangeUser&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;redirectLogin&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;urlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;https&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrls&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;slashPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;altFilename&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;guestSearchable&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;pageClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childNameFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pageLabelField&amp;quot;: &amp;quot;fa-user-circle-o title&amp;quot;,&lt;br /&gt;
        &amp;quot;noGlobal&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noMove&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noTrash&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noSettings&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noChangeTemplate&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noShortcut&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noUnpublish&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;compile&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;nameContentTab&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noCacheGetVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noCachePostVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;useCacheForUsers&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpire&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpirePages&amp;quot;: [],&lt;br /&gt;
        &amp;quot;cacheExpireSelector&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Stellenangebot&amp;quot;,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;titleNames&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noPrependTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noAppendTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;prependFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;appendFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pagefileSecure&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;tabContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tabChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;nameLabel&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;errorAction&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;connectedFieldID&amp;quot;: null,&lt;br /&gt;
        &amp;quot;ns&amp;quot;: &amp;quot;ProcessWire&amp;quot;,&lt;br /&gt;
        &amp;quot;_exportMode&amp;quot;: true,&lt;br /&gt;
        &amp;quot;roles&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;title&amp;quot;,&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;,&lt;br /&gt;
            &amp;quot;job&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;title&amp;quot;: [],&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;: [],&lt;br /&gt;
            &amp;quot;job&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jobs&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: 55,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;jobs&amp;quot;,&lt;br /&gt;
        &amp;quot;fieldgroups_id&amp;quot;: &amp;quot;jobs&amp;quot;,&lt;br /&gt;
        &amp;quot;flags&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cache_time&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;useRoles&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;editRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;addRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;createRoles&amp;quot;: [],&lt;br /&gt;
        &amp;quot;rolesPermissions&amp;quot;: [],&lt;br /&gt;
        &amp;quot;noInherit&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;childrenTemplatesID&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;sortfield&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noParents&amp;quot;: -1,&lt;br /&gt;
        &amp;quot;childTemplates&amp;quot;: [&lt;br /&gt;
            &amp;quot;job&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;parentTemplates&amp;quot;: [],&lt;br /&gt;
        &amp;quot;allowPageNum&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;allowChangeUser&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;redirectLogin&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;urlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;https&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrls&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;slashPageNum&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;slashUrlSegments&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;altFilename&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;guestSearchable&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;pageClass&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;childNameFormat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pageLabelField&amp;quot;: &amp;quot;fa-users title&amp;quot;,&lt;br /&gt;
        &amp;quot;noGlobal&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noMove&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noTrash&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noSettings&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noChangeTemplate&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noShortcut&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noUnpublish&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noLang&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;compile&amp;quot;: 3,&lt;br /&gt;
        &amp;quot;nameContentTab&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noCacheGetVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;noCachePostVars&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;useCacheForUsers&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpire&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;cacheExpirePages&amp;quot;: [],&lt;br /&gt;
        &amp;quot;cacheExpireSelector&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Stellenangebote&amp;quot;,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;titleNames&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noPrependTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;noAppendTemplateFile&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;prependFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;appendFile&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pagefileSecure&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;tabContent&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;tabChildren&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;nameLabel&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;contentType&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;errorAction&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;connectedFieldID&amp;quot;: null,&lt;br /&gt;
        &amp;quot;ns&amp;quot;: &amp;quot;ProcessWire&amp;quot;,&lt;br /&gt;
        &amp;quot;_exportMode&amp;quot;: true,&lt;br /&gt;
        &amp;quot;roles&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupFields&amp;quot;: [&lt;br /&gt;
            &amp;quot;title&amp;quot;,&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;,&lt;br /&gt;
            &amp;quot;images&amp;quot;,&lt;br /&gt;
            &amp;quot;files&amp;quot;,&lt;br /&gt;
            &amp;quot;menu&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;fieldgroupContexts&amp;quot;: {&lt;br /&gt;
            &amp;quot;title&amp;quot;: [],&lt;br /&gt;
            &amp;quot;layout_blocks&amp;quot;: [],&lt;br /&gt;
            &amp;quot;images&amp;quot;: [],&lt;br /&gt;
            &amp;quot;files&amp;quot;: [],&lt;br /&gt;
            &amp;quot;menu&amp;quot;: []&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Template Jobs ===&lt;br /&gt;
Todo besser als Layout-Block&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// JOBLIST&lt;br /&gt;
$joblist = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobs = pages(&amp;#039;template=job,sort=-published&amp;#039;);&lt;br /&gt;
foreach ($jobs as $item) {&lt;br /&gt;
  $joblist .= &amp;#039;&amp;lt;li class=&amp;quot;joblist-item&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$item-&amp;gt;title.&amp;#039; (&amp;#039;.$item-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title.&amp;#039;)&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
$joblist = &amp;#039;&amp;lt;ul class=&amp;quot;joblist&amp;quot;&amp;gt;&amp;#039;.$joblist.&amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Template Job ===&lt;br /&gt;
Benötigt im Admin Bereich nur das job Feld. In diesem sind alle anderen benötigten Felder bereits enthalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
include_once(&amp;#039;includes/SchemaHelper.php&amp;#039;);&lt;br /&gt;
$sh = new SchemaHelper;&lt;br /&gt;
$jsonld = $sh-&amp;gt;jsonldJobPosting($page);&lt;br /&gt;
&lt;br /&gt;
// BEWERBUNGSFORMULAR WENN GESÜNSCHT&lt;br /&gt;
$contact =  $forms-&amp;gt;render(&amp;#039;bewerbung&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
ob_start();&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;apply&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;&amp;lt;?=$page-&amp;gt;title?&amp;gt;&amp;lt;/h1&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;job-description&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_description?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;&amp;quot;&amp;gt;Arbeitgeber&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title?&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
	&amp;lt;?=$page-&amp;gt;link?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Arbeitsort&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_streetaddress?&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_postalcode?&amp;gt; &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_addresslocality?&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php if ($page-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_maxvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_unittext): ?&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Vergütung&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_minvalue?&amp;gt;€ - &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_maxvalue?&amp;gt;€ &amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php elseif($page-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $page-&amp;gt;job-&amp;gt;job_basesalary_unittext): ?&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;font-heavy&amp;quot;&amp;gt;Vergütung&amp;lt;/div&amp;gt;&lt;br /&gt;
	&amp;lt;div&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_basesalary_minvalue?&amp;gt;€ &amp;lt;?=$page-&amp;gt;unit-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;?php endif ?&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;font-heavy pt-20&amp;quot;&amp;gt;Art der Anstellung&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;pb-30&amp;quot;&amp;gt;&amp;lt;?=$page-&amp;gt;job-&amp;gt;job_employmenttype-&amp;gt;title?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Bewerbungsmöglichkeit --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;apply-form&amp;quot; class=&amp;quot;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2&amp;gt;Bewerbung&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div&amp;gt;&amp;lt;?= $contact ?&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- job ldjson --&amp;gt;&lt;br /&gt;
    &amp;lt;?=$jsonld?&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$content = ob_get_clean();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bewerbungsformular ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;required&amp;quot;: false,&lt;br /&gt;
    &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;roles&amp;quot;: {&lt;br /&gt;
        &amp;quot;form-submit&amp;quot;: [&lt;br /&gt;
            &amp;quot;guest&amp;quot;&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;form-list&amp;quot;: [],&lt;br /&gt;
        &amp;quot;form-edit&amp;quot;: [],&lt;br /&gt;
        &amp;quot;form-delete&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-list&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-edit&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-delete&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-page&amp;quot;: [],&lt;br /&gt;
        &amp;quot;entries-resend&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;flags&amp;quot;: 256,&lt;br /&gt;
    &amp;quot;pluginActions&amp;quot;: [],&lt;br /&gt;
    &amp;quot;framework&amp;quot;: &amp;quot;Uikit3&amp;quot;,&lt;br /&gt;
    &amp;quot;allowPreset&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;skipSessionKey&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;useCookies&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;partialEntryDays&amp;quot;: 14,&lt;br /&gt;
    &amp;quot;spamEntryDays&amp;quot;: 7,&lt;br /&gt;
    &amp;quot;submitText&amp;quot;: &amp;quot;Absenden&amp;quot;,&lt;br /&gt;
    &amp;quot;successMessage&amp;quot;: &amp;quot;Vielen Dank - Ihre Bewerbung wurde versendet.&amp;quot;,&lt;br /&gt;
    &amp;quot;errorMessage&amp;quot;: &amp;quot;Ein Fehler ist aufgetreten. Bitte überprüfen Sie Ihre Eingaben.&amp;quot;,&lt;br /&gt;
    &amp;quot;mobilePx&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;frBasic_noLoad&amp;quot;: [],&lt;br /&gt;
    &amp;quot;frBasic_cssURL&amp;quot;: &amp;quot;/site/modules/FormBuilder/frameworks/basic/main.css&amp;quot;,&lt;br /&gt;
    &amp;quot;frBasic_itemContent&amp;quot;: [&lt;br /&gt;
        &amp;quot;description&amp;quot;,&lt;br /&gt;
        &amp;quot;out&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;,&lt;br /&gt;
        &amp;quot;notes&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;spamFlags&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;listFields&amp;quot;: [],&lt;br /&gt;
    &amp;quot;entryDays&amp;quot;: 0,&lt;br /&gt;
    &amp;quot;emailSubject&amp;quot;: &amp;quot;Bewerbungsformular auf salus-klinik.de&amp;quot;,&lt;br /&gt;
    &amp;quot;responderSubject&amp;quot;: &amp;quot;Auto-Response&amp;quot;,&lt;br /&gt;
    &amp;quot;saveFlags&amp;quot;: 35,&lt;br /&gt;
    &amp;quot;spamWords&amp;quot;: [],&lt;br /&gt;
    &amp;quot;honeypot&amp;quot;: &amp;quot;name_1&amp;quot;,&lt;br /&gt;
    &amp;quot;emailTo&amp;quot;: &amp;quot;post@stephanschlegel.de&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_noLoad&amp;quot;: [&lt;br /&gt;
        &amp;quot;framework&amp;quot;,&lt;br /&gt;
        &amp;quot;jquery&amp;quot;,&lt;br /&gt;
        &amp;quot;jqueryui&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;frUikit3_ukURL&amp;quot;: &amp;quot;/site/modules/FormBuilder/frameworks/uikit3/&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_css&amp;quot;: &amp;quot;uikit.min.css&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_horizontal&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_inlineErrorBelow&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
    &amp;quot;frUikit3_horizHeaderWidth&amp;quot;: 30,&lt;br /&gt;
    &amp;quot;frUikit3_buttonType&amp;quot;: &amp;quot;primary&amp;quot;,&lt;br /&gt;
    &amp;quot;children&amp;quot;: {&lt;br /&gt;
        &amp;quot;name_1&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: false,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name_2&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;e_mail&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Email&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;E-Mail&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 250,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;telefon&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;Text&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Telefon&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;minlength&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;maxlength&amp;quot;: 2048,&lt;br /&gt;
            &amp;quot;showCount&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;bewerbungsunterlagen&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;FormBuilderFile&amp;quot;,&lt;br /&gt;
            &amp;quot;label&amp;quot;: &amp;quot;Bewerbungsunterlagen&amp;quot;,&lt;br /&gt;
            &amp;quot;notes&amp;quot;: &amp;quot;Maximal 3 Dateien á 5MB&amp;quot;,&lt;br /&gt;
            &amp;quot;required&amp;quot;: false,&lt;br /&gt;
            &amp;quot;columnWidth&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;collapsed&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;extensions&amp;quot;: &amp;quot;pdf doc docx xls xlsx gif jpg jpeg png&amp;quot;,&lt;br /&gt;
            &amp;quot;maxFiles&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;maxFileSize&amp;quot;: 5242880&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Layout Block - Job-Liste ===&lt;br /&gt;
Beispiel Salus&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
$sectionClasses = array($page-&amp;gt;_type);&lt;br /&gt;
$containerClasses = array(&amp;#039;ani section&amp;#039;);&lt;br /&gt;
if($page-&amp;gt;bg &amp;amp;&amp;amp; $page-&amp;gt;bg-&amp;gt;value) {&lt;br /&gt;
    $colorClassBorder = $page-&amp;gt;bg-&amp;gt;value;&lt;br /&gt;
    $colorClassContent = $page-&amp;gt;bg-&amp;gt;value;&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
    $colorClassBorder = &amp;#039;bc1&amp;#039;;&lt;br /&gt;
    $colorClassContent = &amp;#039;bc1&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobsMarkup = &amp;#039;&amp;#039;;&lt;br /&gt;
$jobsAccordion = new Box;&lt;br /&gt;
$jobs = pages(&amp;#039;template=job,sort=-published&amp;#039;);&lt;br /&gt;
foreach ($jobs as $item) {&lt;br /&gt;
&lt;br /&gt;
    $jobsMarkup .= &amp;#039;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;bc1 joblist-item&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;a class=&amp;quot;uk-accordion-title uk-padding-small&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;#039;.$item-&amp;gt;title.&amp;#039;&lt;br /&gt;
        &amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-accordion-content uk-padding-small nmt npt&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&amp;#039;.$item-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title.&amp;#039;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Arbeitsort:&amp;lt;/strong&amp;gt; &amp;#039;.$item-&amp;gt;job-&amp;gt;job_addresslocality.&amp;#039;&amp;lt;br&amp;gt;&lt;br /&gt;
          &amp;lt;strong&amp;gt;Art der Anstellung: &amp;lt;/strong&amp;gt;&amp;#039;.$item-&amp;gt;job-&amp;gt;job_employmenttype-&amp;gt;title.&amp;#039;&amp;lt;/p&amp;gt;&lt;br /&gt;
          &amp;lt;p&amp;gt;&amp;lt;a class=&amp;quot;uk-button uk-button-primary&amp;quot; href=&amp;quot;&amp;#039;.$item-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;Zur Stellenbeschreibung&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$jobsAccordion-&amp;gt;addClasses(&amp;#039;accordion uk-accordion nmb&amp;#039;);&lt;br /&gt;
$jobsAccordion-&amp;gt;addAttributes(&amp;#039;uk-accordion=&amp;quot;&amp;quot;&amp;#039;); // i.e. active:0&lt;br /&gt;
$out .= $jobsAccordion-&amp;gt;wrap($jobsMarkup,&amp;#039;ul&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// RANDSPALTE?&lt;br /&gt;
$out = &amp;#039;&lt;br /&gt;
&amp;lt;div class=&amp;quot;uk-grid uk-grid-collapse uk-grid-match&amp;quot; uk-grid&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;uk-visible@m uk-width-1-5 &amp;#039;.$colorClassBorder.&amp;#039;&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-padding-small&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div class=&amp;quot;uk-width-expand@m&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;uk-padding npt npb npr&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;#039;.renderHeadline($page).&amp;#039;&lt;br /&gt;
            &amp;#039;. $out .&amp;#039;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
//$out = renderContainer($page,$out,$containerClasses);&lt;br /&gt;
$out = renderSection($page,$out,$sectionClasses,array(&amp;#039;skipDefaultClasses&amp;#039;=&amp;gt;false));&lt;br /&gt;
return $out;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Funktionalität ===&lt;br /&gt;
==== SchemaHelper ====&lt;br /&gt;
Für Erzeugung der Strukturierten Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
/**&lt;br /&gt;
 * SchemaHelper&lt;br /&gt;
 * Class for structured data&lt;br /&gt;
 * V1.0&lt;br /&gt;
 */&lt;br /&gt;
// @todo outsource some of the nessecary types (i.e. place) in backend use&lt;br /&gt;
// fieldgroups for that maybe s.th. like $place = getFg(&amp;#039;schema_place&amp;#039;)&lt;br /&gt;
class SchemaHelper{&lt;br /&gt;
	// Load the requested schema from the schemas directory and register the class&lt;br /&gt;
	public function jsonldJobPosting ($p) {&lt;br /&gt;
		$jsonld = array();&lt;br /&gt;
		$sanitizer = wire(&amp;#039;sanitizer&amp;#039;);&lt;br /&gt;
		//set unset fields (for not mandatory fields)&lt;br /&gt;
		$p-&amp;gt;job-&amp;gt;job_validthrough = $p-&amp;gt;job-&amp;gt;job_validthrough ? : &amp;#039;&amp;#039;; // todo test&lt;br /&gt;
&lt;br /&gt;
		$jsonld[&amp;quot;@context&amp;quot;] = &amp;quot;http://schema.org/&amp;quot;;&lt;br /&gt;
		$jsonld[&amp;quot;@type&amp;quot;] = &amp;quot;JobPosting&amp;quot;;&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;job_link) $jsonld[&amp;quot;url&amp;quot;] = $p-&amp;gt;job-&amp;gt;job_link;&lt;br /&gt;
		else $jsonld[&amp;quot;url&amp;quot;] = $sanitizer-&amp;gt;url($p-&amp;gt;httpUrl);&lt;br /&gt;
		$jsonld[&amp;quot;datePosted&amp;quot;] = !empty($p-&amp;gt;job-&amp;gt;job_dateposted) ? date(&amp;#039;Y-m-d&amp;#039;, $p-&amp;gt;job-&amp;gt;getUnformatted(&amp;#039;job_dateposted&amp;#039;) ) : date(&amp;#039;Y-m-d&amp;#039;, strtotime($p-&amp;gt;created));&lt;br /&gt;
		$jsonld[&amp;quot;validThrough&amp;quot;] = date(&amp;#039;Y-m-d&amp;#039;, $p-&amp;gt;job-&amp;gt;getUnformatted(&amp;#039;job_validthrough&amp;#039;) );&lt;br /&gt;
		$jsonld[&amp;quot;description&amp;quot;] = $sanitizer-&amp;gt;textarea($p-&amp;gt;job-&amp;gt;job_description);&lt;br /&gt;
		$jsonld[&amp;#039;hiringOrganization&amp;#039;] = array(&lt;br /&gt;
			&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;Organization&amp;quot;,&lt;br /&gt;
			&amp;quot;name&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_organizationname-&amp;gt;title),&lt;br /&gt;
			&amp;quot;sameAs&amp;quot; =&amp;gt; $sanitizer-&amp;gt;url($p-&amp;gt;job-&amp;gt;job_link)&lt;br /&gt;
		);&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;link2)$jsonld[&amp;#039;hiringOrganization&amp;#039;][&amp;#039;logo&amp;#039;] = $p-&amp;gt;job-&amp;gt;link2;&lt;br /&gt;
		$jsonld[&amp;#039;title&amp;#039;] = $sanitizer-&amp;gt;text($p-&amp;gt;title);&lt;br /&gt;
&lt;br /&gt;
		if($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_maxvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_unittext){&lt;br /&gt;
			$jsonld[&amp;#039;baseSalary&amp;#039;] = array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;MonetaryAmount&amp;quot;,&lt;br /&gt;
				&amp;quot;currency&amp;quot; =&amp;gt; &amp;quot;EUR&amp;quot;,&lt;br /&gt;
				&amp;quot;value&amp;quot; =&amp;gt; array(&lt;br /&gt;
					&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;QuantitativeValue&amp;quot;,&lt;br /&gt;
					&amp;quot;minValue&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue),&lt;br /&gt;
					&amp;quot;maxValue&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_maxvalue),&lt;br /&gt;
					&amp;quot;unitText&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;value)&lt;br /&gt;
				)&lt;br /&gt;
			);&lt;br /&gt;
		}else if($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue &amp;amp;&amp;amp; $p-&amp;gt;job-&amp;gt;job_basesalary_unittext){&lt;br /&gt;
			$jsonld[&amp;#039;baseSalary&amp;#039;] = array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;MonetaryAmount&amp;quot;,&lt;br /&gt;
				&amp;quot;currency&amp;quot; =&amp;gt; &amp;quot;EUR&amp;quot;,&lt;br /&gt;
				&amp;quot;value&amp;quot; =&amp;gt; array(&lt;br /&gt;
					&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;QuantitativeValue&amp;quot;,&lt;br /&gt;
					&amp;quot;value&amp;quot; =&amp;gt; $sanitizer-&amp;gt;float($p-&amp;gt;job-&amp;gt;job_basesalary_minvalue),&lt;br /&gt;
					&amp;quot;unitText&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_basesalary_unittext-&amp;gt;value)&lt;br /&gt;
				)&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		$jsonld[&amp;#039;jobLocation&amp;#039;] = array(&lt;br /&gt;
			&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;Place&amp;quot;,&lt;br /&gt;
			&amp;quot;address&amp;quot; =&amp;gt; array(&lt;br /&gt;
				&amp;quot;@type&amp;quot; =&amp;gt; &amp;quot;PostalAddress&amp;quot;,&lt;br /&gt;
				&amp;quot;streetAddress&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_streetaddress),&lt;br /&gt;
				&amp;quot;addressLocality&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addresslocality),&lt;br /&gt;
				&amp;quot;addressRegion&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addressregion),&lt;br /&gt;
				&amp;quot;postalCode&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_postalcode),&lt;br /&gt;
				&amp;quot;addressCountry&amp;quot; =&amp;gt; $sanitizer-&amp;gt;text($p-&amp;gt;job-&amp;gt;job_addresscountry),&lt;br /&gt;
			)&lt;br /&gt;
		);&lt;br /&gt;
		// recommended properties&lt;br /&gt;
&lt;br /&gt;
		if($c = count($p-&amp;gt;job-&amp;gt;job_employmenttype)){&lt;br /&gt;
			$types = array();&lt;br /&gt;
			foreach($p-&amp;gt;job-&amp;gt;job_employmenttype as $type){&lt;br /&gt;
				$types[] = $sanitizer-&amp;gt;text($type-&amp;gt;value);&lt;br /&gt;
			}&lt;br /&gt;
			//var_dump($c);&lt;br /&gt;
			if($c &amp;gt; 1) $jsonld[&amp;#039;employmentType&amp;#039;] = $types;&lt;br /&gt;
			else $jsonld[&amp;#039;employmentType&amp;#039;] = $types[0];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		//$out .= &amp;#039;&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&amp;#039; . json_encode($jsonld) . &amp;#039;&amp;lt;/script&amp;gt;&amp;#039;;&lt;br /&gt;
		$out = &amp;#039;&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&amp;#039; . json_encode($jsonld,JSON_PRETTY_PRINT) . &amp;#039;&amp;lt;/script&amp;gt;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
		return $out;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Microsoft_365&amp;diff=33096</id>
		<title>Microsoft 365</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Microsoft_365&amp;diff=33096"/>
		<updated>2025-06-23T14:25:59Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Telefon und E-Mail als Administrator festlegen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Quickstart ==&lt;br /&gt;
In 2023/2024 hat Microsoft die meisten Dienste unter dem Terminus Microsoft 365 zusammengefasst. Diese Seite soll als Startpunkt für die Suche dienen.&lt;br /&gt;
&lt;br /&gt;
== Office auf dem Desktop installieren ==&lt;br /&gt;
Die Downloads sind oft schwer zu finden. &lt;br /&gt;
&lt;br /&gt;
Hier geht es Stand März 2025: &lt;br /&gt;
* Einloggen auf https://www.microsoft365.com&lt;br /&gt;
* Home-Seite&lt;br /&gt;
* Oben rechts &amp;quot;Installieren und mehr&amp;quot; Button&lt;br /&gt;
&lt;br /&gt;
== Was ist was ==&lt;br /&gt;
=== Admin Center ===&lt;br /&gt;
Zentrale Verwaltung, Billing, Benutzerverwaltung&lt;br /&gt;
&lt;br /&gt;
=== Purview ===&lt;br /&gt;
Compliance Center&lt;br /&gt;
&lt;br /&gt;
=== Azure / Entra ===&lt;br /&gt;
Azure AD heißt jetzt Entra. &lt;br /&gt;
&lt;br /&gt;
=== Exchange ===&lt;br /&gt;
Postfächer etc.&lt;br /&gt;
&lt;br /&gt;
=== Defender ===&lt;br /&gt;
Bedrohungen analysieren und reagieren&lt;br /&gt;
&lt;br /&gt;
== Anmeldung ==&lt;br /&gt;
 https://learn.microsoft.com/de-de/entra/identity/authentication/concept-authentication-methods - Einstieg&lt;br /&gt;
 https://mysignins.microsoft.com/security-info // Self-Service Einstellungen&lt;br /&gt;
&lt;br /&gt;
=== Mehrstufige Authentifizierung (MFA) ===&lt;br /&gt;
 https://www.youtube.com/watch?v=qNndxl7gqVM&lt;br /&gt;
 https://aka.ms/MFASetup - Benutzerregistrierung&lt;br /&gt;
 https://go.microsoft.com/fwlink/?LinkId=627442 Handbuch&lt;br /&gt;
==== Anmelde- / Authentifizierungsmethoden als Administrator festlegen (Telefon, SMS, E-Mail, ...) ====&lt;br /&gt;
Entra Portal &amp;gt; Benutzer &amp;gt; Benutzer wählen &amp;gt; Authentifizierungsmethoden&lt;br /&gt;
&lt;br /&gt;
=== Bedingter Zugriff ===&lt;br /&gt;
=== Kombinierte Anmeldung ===&lt;br /&gt;
Todo&lt;br /&gt;
&lt;br /&gt;
=== Probleme ===&lt;br /&gt;
MFA wird erzwungen, obwohl sie deaktiviert ist.&lt;br /&gt;
Mögliche Gründe:&lt;br /&gt;
* Single Sign On&lt;br /&gt;
* Richtlinien für bedingten Zugriff - in Azure können extra Richtlinien unter bestimmten Bedingungen definiert sein (z.b. Anmeldung außerhalb des Unternehmensnetzwerks).&lt;br /&gt;
* Residuale Situationen (alte Richtlinien)&lt;br /&gt;
* Sicherheits (Compliance) Anforderungen Azure / Entra&lt;br /&gt;
&lt;br /&gt;
== OAuth Anmeldung von externer App nutzen ==&lt;br /&gt;
Generell kann man externe kann man User externer Anwendungen anmelden. Dazu muss man eine App in EntraID registrieren.&lt;br /&gt;
=== ProcessWire User über OAuth ===&lt;br /&gt;
[[ProcessWire - OAuth Anmeldung über Microsoft365]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_schneller_CSV-Export&amp;diff=33095</id>
		<title>ProcessWire - schneller CSV-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_schneller_CSV-Export&amp;diff=33095"/>
		<updated>2025-06-17T07:20:31Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quick &amp;amp; Dirty Template wenn du schnell mal Daten exportieren möchtest. &lt;br /&gt;
# Template mit dem Code unten anlegen&lt;br /&gt;
# Seite mit dem Template erstellen&lt;br /&gt;
# Seite aufrufen (am besten erstmal im Selector die Zahl der Ergebnisse mit limit begrenzen).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * custom-export.php&lt;br /&gt;
 * Template für quick and dirty exporte&lt;br /&gt;
 * Um den selector leichter zu erstellen kannst du im Adminbereich unter Page-&amp;gt;find eine Abfrage bauen.&lt;br /&gt;
 * $selector ist der Selector für die Abfrage&lt;br /&gt;
 * $fields sind die Felder die im CSV-Export ausgegeben werden (müssen Felder sein die zum Abfrageergebnis passen)&lt;br /&gt;
 */&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
// Selector für export von Usern bei fasch angelegter Antwort (wurde danach korrigiert)&lt;br /&gt;
//$selector = &amp;#039;has_parent!=2, template=54|55, selected_answer*=B, pr_question=190720, checkbox=0, limit=0, sort=-modified, include=unpublished&amp;#039;; // hier kommt dein Selector&lt;br /&gt;
//$fields = [&amp;#039;pr_question&amp;#039;, &amp;#039;pr_user.firstname&amp;#039;, &amp;#039;pr_user.lastname&amp;#039;, &amp;#039;pr_user.email&amp;#039;, &amp;#039;selected_answer&amp;#039;, &amp;#039;checkbox&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
// User mit mindestens einer beantworteten Frage&lt;br /&gt;
$selector = &amp;#039;template=3, parent=29, include=all, limit=100, status&amp;lt;9999999, template=3, parent=29, answered_questions!=0, roles=1044, sort=name&amp;#039;;&lt;br /&gt;
$fields = [&amp;#039;name&amp;#039;,&amp;#039;firstname&amp;#039;, &amp;#039;lastname&amp;#039;, &amp;#039;email&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
exportCustomCSV($selector, $fields);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * exportCSV&lt;br /&gt;
 * @param String - the selector&lt;br /&gt;
 * @param Array Feldnamen die exportiert werden.&lt;br /&gt;
 * &lt;br /&gt;
 */&lt;br /&gt;
function exportCustomCSV($selector,$fields) {&lt;br /&gt;
  /**&lt;br /&gt;
   * Exportiert die user_answer-Datensätze als CSV.&lt;br /&gt;
   */&lt;br /&gt;
  $filename = &amp;quot;pw_export_&amp;quot; . date(&amp;quot;Ymd_His&amp;quot;) . &amp;quot;.csv&amp;quot;;&lt;br /&gt;
  header(&amp;#039;Content-Type: text/csv; charset=utf-8&amp;#039;);&lt;br /&gt;
  header(&amp;#039;Content-Disposition: attachment; filename=&amp;#039; . $filename);&lt;br /&gt;
&lt;br /&gt;
  $output = fopen(&amp;#039;php://output&amp;#039;, &amp;#039;w&amp;#039;);&lt;br /&gt;
  &lt;br /&gt;
  // CSV-Kopfzeile&lt;br /&gt;
  $headers = [];&lt;br /&gt;
  foreach($fields as $fieldName) {&lt;br /&gt;
    // Versuche, das Field-Objekt zu holen&lt;br /&gt;
    $f = wire()-&amp;gt;fields-&amp;gt;get($fieldName);&lt;br /&gt;
    if($f) {&lt;br /&gt;
      $headers[] = $f-&amp;gt;label;&lt;br /&gt;
    } else {&lt;br /&gt;
      // Fallback&lt;br /&gt;
      $headers[] = $fieldName;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  $output = fopen(&amp;#039;php://output&amp;#039;, &amp;#039;w&amp;#039;);&lt;br /&gt;
  fputcsv($output, $headers);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // DATEN&lt;br /&gt;
  $items = pages()-&amp;gt;find($selector);&lt;br /&gt;
  foreach($items as $item) {&lt;br /&gt;
    bd($item);&lt;br /&gt;
    $row = [];&lt;br /&gt;
    foreach($fields as $fieldName) {&lt;br /&gt;
      $value = $item-&amp;gt;$fieldName;&lt;br /&gt;
      // Wenn PageArray (z.B. mehrere Referenzen), join Titles&lt;br /&gt;
      if($value instanceof \ProcessWire\PageArray) {&lt;br /&gt;
        $titles = [];&lt;br /&gt;
        foreach($value as $p) $titles[] = $p-&amp;gt;title;&lt;br /&gt;
        $row[] = implode(&amp;#039;|&amp;#039;, $titles);&lt;br /&gt;
      }&lt;br /&gt;
      // Wenn einzelne Page (z.B. eine Referenz), Titel ausgeben&lt;br /&gt;
      elseif($value instanceof \ProcessWire\Page) {&lt;br /&gt;
        $row[] = $value-&amp;gt;title;&lt;br /&gt;
      }&lt;br /&gt;
      // Sonst ganz normal in String casten&lt;br /&gt;
      else {&lt;br /&gt;
        $row[] = (string) $value;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    fputcsv($output, $row);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  //bd($items);&lt;br /&gt;
  fclose($output);&lt;br /&gt;
  exit;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_schneller_CSV-Export&amp;diff=33094</id>
		<title>ProcessWire - schneller CSV-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_schneller_CSV-Export&amp;diff=33094"/>
		<updated>2025-06-17T07:18:34Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „Quick &amp;amp; Dirty Template wenn du schnell mal Daten exportieren möchtest:  &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &amp;lt;?php  namespace ProcessWire;  /**  * custom-export.php…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quick &amp;amp; Dirty Template wenn du schnell mal Daten exportieren möchtest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * custom-export.php&lt;br /&gt;
 * Template für quick and dirty exporte&lt;br /&gt;
 * Um den selector leichter zu erstellen kannst du im Adminbereich unter Page-&amp;gt;find eine Abfrage bauen.&lt;br /&gt;
 * $selector ist der Selector für die Abfrage&lt;br /&gt;
 * $fields sind die Felder die im CSV-Export ausgegeben werden (müssen Felder sein die zum Abfrageergebnis passen)&lt;br /&gt;
 */&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
// Selector für export von Usern bei fasch angelegter Antwort (wurde danach korrigiert)&lt;br /&gt;
//$selector = &amp;#039;has_parent!=2, template=54|55, selected_answer*=B, pr_question=190720, checkbox=0, limit=0, sort=-modified, include=unpublished&amp;#039;; // hier kommt dein Selector&lt;br /&gt;
//$fields = [&amp;#039;pr_question&amp;#039;, &amp;#039;pr_user.firstname&amp;#039;, &amp;#039;pr_user.lastname&amp;#039;, &amp;#039;pr_user.email&amp;#039;, &amp;#039;selected_answer&amp;#039;, &amp;#039;checkbox&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
// User mit mindestens einer beantworteten Frage&lt;br /&gt;
$selector = &amp;#039;template=3, parent=29, include=all, limit=100, status&amp;lt;9999999, template=3, parent=29, answered_questions!=0, roles=1044, sort=name&amp;#039;;&lt;br /&gt;
$fields = [&amp;#039;name&amp;#039;,&amp;#039;firstname&amp;#039;, &amp;#039;lastname&amp;#039;, &amp;#039;email&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
exportCustomCSV($selector, $fields);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * exportCSV&lt;br /&gt;
 * @param String - the selector&lt;br /&gt;
 * @param Array Feldnamen die exportiert werden.&lt;br /&gt;
 * &lt;br /&gt;
 */&lt;br /&gt;
function exportCustomCSV($selector,$fields) {&lt;br /&gt;
  /**&lt;br /&gt;
   * Exportiert die user_answer-Datensätze als CSV.&lt;br /&gt;
   */&lt;br /&gt;
  $filename = &amp;quot;pw_export_&amp;quot; . date(&amp;quot;Ymd_His&amp;quot;) . &amp;quot;.csv&amp;quot;;&lt;br /&gt;
  header(&amp;#039;Content-Type: text/csv; charset=utf-8&amp;#039;);&lt;br /&gt;
  header(&amp;#039;Content-Disposition: attachment; filename=&amp;#039; . $filename);&lt;br /&gt;
&lt;br /&gt;
  $output = fopen(&amp;#039;php://output&amp;#039;, &amp;#039;w&amp;#039;);&lt;br /&gt;
  &lt;br /&gt;
  // CSV-Kopfzeile&lt;br /&gt;
  $headers = [];&lt;br /&gt;
  foreach($fields as $fieldName) {&lt;br /&gt;
    // Versuche, das Field-Objekt zu holen&lt;br /&gt;
    $f = wire()-&amp;gt;fields-&amp;gt;get($fieldName);&lt;br /&gt;
    if($f) {&lt;br /&gt;
      $headers[] = $f-&amp;gt;label;&lt;br /&gt;
    } else {&lt;br /&gt;
      // Fallback&lt;br /&gt;
      $headers[] = $fieldName;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  $output = fopen(&amp;#039;php://output&amp;#039;, &amp;#039;w&amp;#039;);&lt;br /&gt;
  fputcsv($output, $headers);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // DATEN&lt;br /&gt;
  $items = pages()-&amp;gt;find($selector);&lt;br /&gt;
  foreach($items as $item) {&lt;br /&gt;
    bd($item);&lt;br /&gt;
    $row = [];&lt;br /&gt;
    foreach($fields as $fieldName) {&lt;br /&gt;
      $value = $item-&amp;gt;$fieldName;&lt;br /&gt;
      // Wenn PageArray (z.B. mehrere Referenzen), join Titles&lt;br /&gt;
      if($value instanceof \ProcessWire\PageArray) {&lt;br /&gt;
        $titles = [];&lt;br /&gt;
        foreach($value as $p) $titles[] = $p-&amp;gt;title;&lt;br /&gt;
        $row[] = implode(&amp;#039;|&amp;#039;, $titles);&lt;br /&gt;
      }&lt;br /&gt;
      // Wenn einzelne Page (z.B. eine Referenz), Titel ausgeben&lt;br /&gt;
      elseif($value instanceof \ProcessWire\Page) {&lt;br /&gt;
        $row[] = $value-&amp;gt;title;&lt;br /&gt;
      }&lt;br /&gt;
      // Sonst ganz normal in String casten&lt;br /&gt;
      else {&lt;br /&gt;
        $row[] = (string) $value;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    fputcsv($output, $row);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  //bd($items);&lt;br /&gt;
  fclose($output);&lt;br /&gt;
  exit;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Selectors&amp;diff=33093</id>
		<title>ProcessWire - Selectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Selectors&amp;diff=33093"/>
		<updated>2025-06-17T07:17:42Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Schneller CSV-Export von Selector-Ergebnissen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Operatoren ==&lt;br /&gt;
 http://cheatsheet.processwire.com/selectors/selector-operators/&lt;br /&gt;
Selector Operators&lt;br /&gt;
&lt;br /&gt;
    =&lt;br /&gt;
    Equal to (any_field=any_value)&lt;br /&gt;
&lt;br /&gt;
    !=&lt;br /&gt;
    Not equal to (any_field!=any_value)&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;&lt;br /&gt;
    Less than (any_field&lt;br /&gt;
&lt;br /&gt;
    &amp;gt;&lt;br /&gt;
    Greater than any_field&amp;gt;any_value&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;=&lt;br /&gt;
    Less than or equal to (any_field&amp;lt;=any_value)&lt;br /&gt;
&lt;br /&gt;
    &amp;gt;=&lt;br /&gt;
    Greater than or equal to (any_field&amp;gt;=any_value)&lt;br /&gt;
&lt;br /&gt;
    *=&lt;br /&gt;
    Contains the exact word or phrase (any_field*=any_value)&lt;br /&gt;
&lt;br /&gt;
    ~=&lt;br /&gt;
    Contains all the words (any_field~=any_value)&lt;br /&gt;
&lt;br /&gt;
    %=&lt;br /&gt;
    Contains the exact word or phrase (using slower SQL LIKE) [v2.1] (any_field%=any_value)&lt;br /&gt;
&lt;br /&gt;
    ^=&lt;br /&gt;
    Contains the exact word or phrase at the beginning of the field [v2.1] (any_field^=any_value)&lt;br /&gt;
&lt;br /&gt;
    $=&lt;br /&gt;
    Contains the exact word or phrase at the end of the field [v2.1] (any_field$=any_value)&lt;br /&gt;
&lt;br /&gt;
=== Neue Operatoren ab 3.0.160 ===&lt;br /&gt;
List of new operators available as of ProcessWire 3.0.160&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s a list of new operators available as of 3.0.160, along with brief explanation of what each operator does and how it differs from other similar operators.&lt;br /&gt;
&lt;br /&gt;
    Contains words partial (~*=)&lt;br /&gt;
    Like existing match words (~=) operator, except that this one matches partial words as well.&lt;br /&gt;
&lt;br /&gt;
    Contains words live (~~=)&lt;br /&gt;
    Like match words, except that the last word in the query is treated as a partial match.&lt;br /&gt;
&lt;br /&gt;
    Contains words like (~%=)&lt;br /&gt;
    Matches all words in the query, in full or in part.&lt;br /&gt;
&lt;br /&gt;
    Contains words and expand (~+=)&lt;br /&gt;
    Like match words operator, but with the added power of the query expansion feature supported by MySQL fulltext indexes.&lt;br /&gt;
&lt;br /&gt;
    Contains any words (~|=)&lt;br /&gt;
    One or more of the words must match; this is similar to splitting the query with pipe (|) characters, but often easier to use, and better optimized.&lt;br /&gt;
&lt;br /&gt;
    Contains any partial words (~|*=)&lt;br /&gt;
    Similar to the previous operator, except that this one also provides partial matches.&lt;br /&gt;
&lt;br /&gt;
    Contains any words like (~|%=)&lt;br /&gt;
    Similar to the previous two operators, but uses LIKE query behind the scenes instead of the fulltext index.&lt;br /&gt;
&lt;br /&gt;
    Contains phrase and expand (*+=)&lt;br /&gt;
    Variation of the phrase match operator (*=) with added query expansion support.&lt;br /&gt;
&lt;br /&gt;
    Contains match (**=)&lt;br /&gt;
    This operator works much like the MATCH/AGAINST feature of MySQL fulltext indexes.&lt;br /&gt;
&lt;br /&gt;
    Contains match and expand (**+=)&lt;br /&gt;
    Otherwise identical to previous operator, except for the added query expansion.&lt;br /&gt;
&lt;br /&gt;
    Advanced text search (#=)&lt;br /&gt;
    This operator adds support for special characters, such as &amp;quot;+&amp;quot; for &amp;quot;must match&amp;quot;, &amp;quot;-&amp;quot; for &amp;quot;must not match&amp;quot;, and &amp;quot;*&amp;quot; for specifying partial matches.&lt;br /&gt;
&lt;br /&gt;
== Owner Attribut ==&lt;br /&gt;
Nützlich bei &amp;#039;&amp;#039;&amp;#039;Pagereferences&amp;#039;&amp;#039;&amp;#039;, wenn &amp;#039;&amp;#039;&amp;#039;auf die Seite verweisende Seiten&amp;#039;&amp;#039;&amp;#039; gefunden und &amp;#039;&amp;#039;&amp;#039;gleichzeitig gefiltert&amp;#039;&amp;#039;&amp;#039; werden sollen.&lt;br /&gt;
 https://processwire.com/blog/posts/processwire-3.0.95-core-updates/&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$members = $pages-&amp;gt;find(&amp;quot;template=member, age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($members as $m) {&lt;br /&gt;
  $items = $m-&amp;gt;memberships-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD&amp;quot;);&lt;br /&gt;
  foreach($items as $membership) {&lt;br /&gt;
     // add to excel or other export, etc.&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Ineffektiv bei vielen Datensätzen -&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD, memberships.owner.age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($items as $membership) {&lt;br /&gt;
  // add to excel or other export, etc.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Kombinierte Abfragen und Subselektoren ==&lt;br /&gt;
Da man auch Seiten im Selektor übergeben kann, kann man relativ einfach kombinierte Abfragen über &amp;#039;&amp;#039;&amp;#039;mehrere Templates&amp;#039;&amp;#039;&amp;#039;, oder auch über &amp;#039;&amp;#039;&amp;#039;parents&amp;#039;&amp;#039;&amp;#039; etc. machen. Mit Subselektoren kann man das noch abkürzen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Kombinierte Abfrage&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$companies = $pages-&amp;gt;find(&amp;quot;template=company, locations&amp;gt;5, locations.title%=Finland&amp;quot;);&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;template=product, company=$companies&amp;quot;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Mit Subselektoren&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 $items = $pages-&amp;gt;find(&amp;quot;template=product, company=[locations&amp;gt;5, locations.title%=Finland]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
== OR / AND ==&lt;br /&gt;
OR funktioniert über &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Feldwert a oder Feldwert b&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
 firstname=Mike|Steve&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Feldwert a und Feldwert b&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 height&amp;gt;500, height&amp;lt;=1000&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;In Feld a oder in Feld b&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 body|sidebar*=carbonated&lt;br /&gt;
&lt;br /&gt;
=== OR Groups ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;(Bedingung a, Bedingung b),(Bedingung c)&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
Wenn man Klammern nutzt muss nur eine der Klammern zutreffen. &lt;br /&gt;
&lt;br /&gt;
Beispiel &amp;quot;product&amp;quot; Seiten in stock, UND entweder in featured date range, ODER highlighted checkbox checked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;template=product, stock&amp;gt;0, (featured_from&amp;lt;=today, featured_to&amp;gt;=today), (highlighted=1)&amp;quot;); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Klammern kennzeichnen Optionale Bedingungen. &amp;#039;&amp;#039;&amp;#039;Es muss also nur eine der Klammern zutreffen.&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
&lt;br /&gt;
Wenn man mehrere Oder-Gruppen benötigt kann man so vorgehen:&lt;br /&gt;
 foo=(selector1), bar=(selector2), foo=(selector3), bar=(selector4)&lt;br /&gt;
Hier gehören alle foo zusammen und alle bar. Sprich es muss &amp;#039;&amp;#039;&amp;#039;selector1 ODER selector3 UND selector2 ODER selector4&amp;#039;&amp;#039;&amp;#039; erfüllt sein.&lt;br /&gt;
&lt;br /&gt;
 https://processwire.com/docs/selectors/#or-selectors1&lt;br /&gt;
&lt;br /&gt;
=== Selektoren und RepeaterMatrix ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel TV Altötting&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//BEISPIEL: $results = $pages-&amp;gt;find(&amp;quot;template=matrix_page,matrix_main.body%=$q&amp;quot;); // name des matrix items weglassen&lt;br /&gt;
      //$selector = &amp;quot;template=&amp;quot;.implode(&amp;#039;|&amp;#039;,$pageTemplates).&amp;quot;, layout_blocks.body~*=&amp;quot;.$val; // findet einspalter aber keine in &lt;br /&gt;
      //$selector = &amp;quot;template=&amp;quot;.implode(&amp;#039;|&amp;#039;,$pageTemplates).&amp;quot;, layout_blocks.r_grid.body~*=&amp;quot;.$val; // findet mehrspalter aber keine einspalter&lt;br /&gt;
      // dot notation not allowed with or so we have to use or groups or bracket notation:&lt;br /&gt;
      $selector = &amp;quot;template=&amp;quot;.implode(&amp;#039;|&amp;#039;,$pageTemplates).&amp;quot;, (layout_blocks.body~*=&amp;quot;.$val.&amp;quot;),(layout_blocks.text~*=&amp;quot;.$val.&amp;quot;),(layout_blocks.headline~*=&amp;quot;.$val.&amp;quot;),(layout_blocks.r_grid.body~*=&amp;quot;.$val.&amp;quot;)&amp;quot;; // findet mehrspalter aber keine einspalter&lt;br /&gt;
      bd($selector,&amp;quot;selector for content&amp;quot;);&lt;br /&gt;
      $matches = $pages-&amp;gt;find($selector); &lt;br /&gt;
&lt;br /&gt;
      $searchResultMarkup .= &amp;quot;&amp;lt;h5&amp;gt;Suche im Seiteninhalt [$matches-&amp;gt;count]&amp;lt;/h5&amp;gt;&amp;quot;;&lt;br /&gt;
      if($matches-&amp;gt;count) {&lt;br /&gt;
        $searchResultMarkup .= renderNav($matches); &lt;br /&gt;
      } else {&lt;br /&gt;
        $searchResultMarkup .= &amp;quot;&amp;lt;p&amp;gt;Keine Seiteninhalte mit diesem Suchbegriff gefunden.&amp;lt;/p&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Anzahl beschränken mit limit und start ==&lt;br /&gt;
 limit=50 // 50 or fewer results&lt;br /&gt;
 start=50, limit=50 //50 (or less) results starting at the 51st (results 51–100).&lt;br /&gt;
&lt;br /&gt;
If you are using a limit selector with pages, and your template has page-numbers (pagination) turned on, ProcessWire will automatically set the &amp;quot;start&amp;quot; selector according to the current page/pagination number. So when it comes to pagination, you don&amp;#039;t usually have to think about anything other than the &amp;quot;limit&amp;quot; selector.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Array Selectors ==&lt;br /&gt;
https://processwire.com/blog/posts/processwire-3.0.13-selector-upgrades-and-new-form-builder-version/#building-a-selector-string-with-user-input-example&lt;br /&gt;
&lt;br /&gt;
=== Selektoren als assoziative Arrays ===&lt;br /&gt;
&lt;br /&gt;
Anstatt von Selector Strings kann man seit PW 3.0.13 auch Arrays nutzen.:d of a string:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$results = $pages-&amp;gt;find([&lt;br /&gt;
  &amp;#039;template&amp;#039; =&amp;gt; [&amp;#039;basic-page&amp;#039;, &amp;#039;product&amp;#039;],&lt;br /&gt;
  &amp;#039;title|body%=&amp;#039; =&amp;gt; $sanitizer-&amp;gt;text($input-&amp;gt;get(&amp;#039;q&amp;#039;)),&lt;br /&gt;
  &amp;#039;categories&amp;#039; =&amp;gt; $sanitizer-&amp;gt;intArray($input-&amp;gt;get(&amp;#039;categories&amp;#039;)),&lt;br /&gt;
  &amp;#039;sort&amp;#039; =&amp;gt; &amp;#039;-created&amp;#039;&lt;br /&gt;
]); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erläuterung:&lt;br /&gt;
&lt;br /&gt;
Die &amp;#039;&amp;#039;$sanitizer-&amp;gt;selectorValue()&amp;#039;&amp;#039; Methode um Text zu sanitizen der in Selektoren geht ist nicht mehr notwendig. Du solltest immer noch User Input sanitizen, aber man kann sich die sanierung für die Selektoren sparen.&lt;br /&gt;
Werte können Arrays sein. Im Beispiel werden Arrays für &amp;#039;template&amp;#039; and &amp;#039;categories&amp;#039; items genutzt. &lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;=&amp;quot; Operator wird für alle Selektoren Elemente angenommen, solange man nicht einen anderen Operator anhängt. Wie bei &amp;#039;&amp;#039;&amp;#039;title|body%=&amp;#039;&amp;#039;&amp;#039; zu sehen.&lt;br /&gt;
&lt;br /&gt;
=== Selektoren als reguläre Arrays ===&lt;br /&gt;
Man kann auch ein reguläres (nicht assoziatives Array nutzen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$results = $pages-&amp;gt;find([&lt;br /&gt;
  [&amp;#039;template&amp;#039;, [&amp;#039;basic-page&amp;#039;, &amp;#039;product&amp;#039;]],&lt;br /&gt;
  [&amp;#039;title|body&amp;#039;, &amp;#039;%=&amp;#039;, $input-&amp;gt;get(&amp;#039;q&amp;#039;), &amp;#039;text&amp;#039;],&lt;br /&gt;
  [&amp;#039;categories&amp;#039;, &amp;#039;=&amp;#039;, $input-&amp;gt;get(&amp;#039;categories&amp;#039;), &amp;#039;int&amp;#039;],&lt;br /&gt;
  [&amp;#039;sort&amp;#039;, &amp;#039;-created&amp;#039;]&lt;br /&gt;
]); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hier werden die Selektorenteile als Array im Array übergeben. Das Format ist folgendes:f those arrays can use any of the following formats:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    [field, value]&lt;br /&gt;
    [field, operator, value]&lt;br /&gt;
    [field, operator, value, sanitizer]&lt;br /&gt;
    [field, operator, value, whitelist]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  The field element can be specified as a single field name, pipe &amp;quot;|&amp;quot; separated field names, or an array of field name(s).&lt;br /&gt;
*  The operator can be any operator. If none is specified, then equals &amp;quot;=&amp;quot; is assumed (which you can do if only specifying a field and value).&lt;br /&gt;
*  The value can be a string, number or array of either.&lt;br /&gt;
*  The sanitizer can be any $sanitizer method name that you want the value to pass through before being used in the selector.&lt;br /&gt;
*  When a whitelist (array) is specified for the sanitizer, the selector will throw an Exception if the given value (or values) are not present in the whitelist array.&lt;br /&gt;
&lt;br /&gt;
Beide Array Formate (assoziativ, regulär) kann man theoretisch sogar mischen.&lt;br /&gt;
&lt;br /&gt;
== Owner Selector ==&lt;br /&gt;
 https://processwire.com/blog/posts/processwire-3.0.95-core-updates/&lt;br /&gt;
Mit Owner Selektoren kannst du Verknüpfungen die über PageTable pages, Page fields oder Repeater fields realisiert werden effizient durchsuchen, ohne Schleifen zu benutzen.&lt;br /&gt;
&lt;br /&gt;
Es dauert etwas bis man das Konzept verstanden hat aber es ist extrem effektiv.&lt;br /&gt;
&lt;br /&gt;
Eine zeitaufwändige Suche über eine Schleife wie diese:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$members = $pages-&amp;gt;find(&amp;quot;template=member, age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($members as $m) {&lt;br /&gt;
  $items = $m-&amp;gt;memberships-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD&amp;quot;);&lt;br /&gt;
  foreach($items as $membership) {&lt;br /&gt;
     // add to excel or other export, etc.&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
wird dann einfach zu:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;club=&amp;#039;Golf Club X&amp;#039;, mtype=GOLD, memberships.owner.age&amp;gt;50&amp;quot;);&lt;br /&gt;
foreach($items as $membership) {&lt;br /&gt;
  // add to excel or other export, etc.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Anstatt über template=member zuerst alle Members zu durchlaufen und diese dann weiter nach Mitgliedschaften zu filtern geht man den Weg anders herum. Man nimmt das Feld das man sucht und schaut über den owner Selector wo es überall Referenziert wird. Also eine Art Rückwärtssuche.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Datum ===&lt;br /&gt;
Per Default nutzt PW das Datum als Timestamp. Um z.B. alle &lt;br /&gt;
&lt;br /&gt;
For recieving page of today, you would have to create a start and end time range and use them in the selector.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$start = strtotime( date(&amp;#039;Y-m-d&amp;#039;) . &amp;quot; 00:00:00&amp;quot;);&lt;br /&gt;
$end = strtotime( date(&amp;#039;Y-m-d&amp;#039;) . &amp;quot; 23:59:59&amp;quot;);&lt;br /&gt;
$items = $pages-&amp;gt;find(&amp;quot;template=linkmain,publishdate&amp;gt;=$start,publishdate&amp;lt;=$end,sort=-userid&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$startDate = &amp;#039;2023-01-01&amp;#039;;&lt;br /&gt;
$endDate = &amp;#039;2023-03-31&amp;#039;;&lt;br /&gt;
$start = $startDate . &amp;#039; 00:00:00&amp;#039;;&lt;br /&gt;
$end = $endDate . &amp;#039; 23:59:59&amp;#039;;&lt;br /&gt;
$paidInvoices = pages(&amp;quot;template=invoice, invoice_paid=1, invoice_date&amp;gt;=$start, invoice_date&amp;lt;=$end&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Todo Beispiele mit wire()-&amp;gt; Datumsfunktionen&lt;br /&gt;
&lt;br /&gt;
=== Parents ===&lt;br /&gt;
To specify that matches should have a &amp;#039;&amp;#039;&amp;#039;specific parent&amp;#039;&amp;#039;&amp;#039;, specify the parent&amp;#039;s path, object or ID. First is an example of using the parent&amp;#039;s path:&lt;br /&gt;
 https://processwire.com/docs/selectors/#finding2&lt;br /&gt;
 parent=/path/to/parent/&lt;br /&gt;
 parent=$parent&lt;br /&gt;
 parent=123&lt;br /&gt;
 parent=$parent1|$parent2|$parent3&lt;br /&gt;
&lt;br /&gt;
==== Parents bei Repeatern oder RepeaterMatrix ====&lt;br /&gt;
 https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Snippets#Parent_von_Repeater_oder_RepeaterMatrix_finden&lt;br /&gt;
&lt;br /&gt;
=== Sortiere Seiten nach Reihenfolge im Seitenbaum ===&lt;br /&gt;
Das funktioniert mit der Sortierung &amp;quot;sort&amp;quot;.&lt;br /&gt;
 $categories = pages(&amp;#039;template=template_name,sort=sort&amp;#039;);&lt;br /&gt;
=== Große Datenmenge mit findMany() durchsuchen ===&lt;br /&gt;
 [[findMany() - ProcessWire API]]&lt;br /&gt;
&lt;br /&gt;
=== Suche nach Seiten die Verweise auf bestimmte andere Seiten enthalten ===&lt;br /&gt;
https://processwire.com/talk/topic/5414-selector-find-page-reference-help/&lt;br /&gt;
&lt;br /&gt;
Es sollen Seiten gefunden werden die mit einer Page Reference auf eine andere Seite verweisen. Am einfachsten geht das wenn man nicht wie man zuerst vermutet nach der Seiten ID sucht, sondern wenn man direkt nach der Seite sucht&lt;br /&gt;
 team_name=$page&lt;br /&gt;
&lt;br /&gt;
=== Suche nach Phrasen in Daten die in Seitenverweise enthalten sind ===&lt;br /&gt;
https://processwire.com/talk/topic/570-searching-page-reference-fields/&lt;br /&gt;
&lt;br /&gt;
Es sollen Seiten gefunden werden, die Verweise auf andere Seiten enthalten. Beispielsweise enthalten Personen (Eltern) Links zu Notfalladressen die separat angelegt sind. Nun soll Nach Eltern gesucht werden, die eine bestimmte Notfalladresse enthalten. Gesucht wird nach einer Phrase im Notfalladrdessen Namen).&lt;br /&gt;
&lt;br /&gt;
Lösung: Es wird in zwei Schritten gesucht. &lt;br /&gt;
&lt;br /&gt;
1. Suche nach Kontakten mit dem Search Term im body und die dem template emergency-contact entsprechen&lt;br /&gt;
 $contacts = $pages-&amp;gt;find(&amp;quot;body*=&amp;#039;search term&amp;#039;, template=emergency-contact&amp;quot;); &lt;br /&gt;
2. Seiten die diesen Kontakten entsprechen&lt;br /&gt;
 $parents = $pages-&amp;gt;find(&amp;quot;emergency-contacts=$contacts&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Selektoren in Option Fieldtypes ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$optionsfield // return id (string)&lt;br /&gt;
$optionsfield-&amp;gt;id; // return id (int)&lt;br /&gt;
$optionsfield-&amp;gt;title; // return string USE THIS or&lt;br /&gt;
$optionsfield-&amp;gt;value; // return empty string or value (if your option settings like &amp;#039;1=value|title&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// dot syntax in selector string&lt;br /&gt;
$pages-&amp;gt;find(&amp;#039;optionsfield.id=2&amp;#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selektoren für Multiple Options ===&lt;br /&gt;
&lt;br /&gt;
==== Finde Seiten in gewählten Optionen ====&lt;br /&gt;
Nehmen wir an wir haben Seiten mit dem Template tag und ein Template product, das wiederum ein PageReference Feld &amp;#039;tags&amp;#039; hat bei dem man ein oder mehrere Tags auswählen kann.&lt;br /&gt;
&lt;br /&gt;
1. Seiten die eines oder mehr der gewählten Tags haben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $myTags = array();&lt;br /&gt;
    // find product pages which fit all options&lt;br /&gt;
    $tags = array();&lt;br /&gt;
    foreach($page-&amp;gt;tag_selector as $tag) {&lt;br /&gt;
        $tags[] = $tag-&amp;gt;name;&lt;br /&gt;
    }&lt;br /&gt;
    $items = $items-&amp;gt;find(&amp;#039;template=product,tags.name=&amp;#039; . implode(&amp;#039;|&amp;#039;,$tags) );&lt;br /&gt;
    //bd($items);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Seiten die alle gewählten Tags haben oder mindestens einen (mit Schalter)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$or = $page-&amp;gt;opt_1;&lt;br /&gt;
if(count($page-&amp;gt;tag_selector)){&lt;br /&gt;
    $myTags = array();&lt;br /&gt;
    $tags = array();&lt;br /&gt;
    foreach($page-&amp;gt;tag_selector as $tag) {&lt;br /&gt;
        if ($or) $tags[] = $tag-&amp;gt;name;&lt;br /&gt;
        else $tags[] = &amp;#039;tag.name=&amp;#039;.$tag-&amp;gt;name;&lt;br /&gt;
    }&lt;br /&gt;
    if ($or) $items = pages()-&amp;gt;find(&amp;#039;template=product,tags.name=&amp;#039; . implode(&amp;#039;|&amp;#039;,$tags) ); //OR&lt;br /&gt;
    else $items = pages()-&amp;gt;find(&amp;#039;template=product,&amp;#039;.implode(&amp;#039;,&amp;#039;,$tags)); // AND&lt;br /&gt;
    bd($items);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Seiten finden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$skyscrapers = $pages-&amp;gt;find(&amp;quot;template=skyscraper, sort=-modified&amp;quot;);&lt;br /&gt;
foreach($skyscrapers as $skyscraper) {&lt;br /&gt;
    echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;$skyscraper-&amp;gt;url&amp;#039;&amp;gt;$skyscraper-&amp;gt;title&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Rekursiv suchen ====&lt;br /&gt;
 $pages-&amp;gt;find(&amp;quot;parent={$cat-&amp;gt;children}, limit=$limit, sort=-date, sort=title&amp;quot;); // expands to something like &amp;quot;parent=1234|1235|1236|1237|...|1507|1508&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Page Reference auf diese Seite ===&lt;br /&gt;
https://processwire.com/talk/topic/1071-page-fieldtype-two-way-relation/&lt;br /&gt;
 echo $pages-&amp;gt;find(&amp;quot;field1=$page&amp;quot;)-&amp;gt;render();&lt;br /&gt;
If the page isn&amp;#039;t part of the front-end site, then I&amp;#039;ll remove view access from its template. Or if it is part of the front-end, but I don&amp;#039;t want to show the relations, then this:&lt;br /&gt;
&lt;br /&gt;
 if($page-&amp;gt;editable()) echo $pages-&amp;gt;find(&amp;quot;field1=$page&amp;quot;)-&amp;gt;render();&lt;br /&gt;
 &lt;br /&gt;
Though I almost always integrate these relation-revealing pages into the site structure, as it&amp;#039;s rare that this information doesn&amp;#039;t have some value to the site&amp;#039;s users too. This is an example of one that locates all pages referencing it in a field called &amp;#039;country&amp;#039;:&lt;br /&gt;
 https://www.tripsite.com/countries/croatia/&lt;br /&gt;
&lt;br /&gt;
=== Suche in PageReference Feldern ===&lt;br /&gt;
Generell gilt PageReferences verhalten sich gleich wie wenn man auf ein Page-Object zugreifen würde.&lt;br /&gt;
 https://processwire.com/talk/topic/1224-selector-and-page-reference-field/&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel:&amp;#039;&amp;#039;&amp;#039; Finde alle Point of Interest Seiten die eine Referenz auf die Kategorie &amp;quot;Zoo&amp;quot; haben&lt;br /&gt;
* Template &amp;#039;&amp;#039;&amp;#039;poi&amp;#039;&amp;#039;&amp;#039; (Point of Interest)&lt;br /&gt;
** Feld &amp;#039;&amp;#039;&amp;#039;poi_type&amp;#039;&amp;#039;&amp;#039; (PageReference) referenziert auf Seiten mit dem Template type &lt;br /&gt;
* Template &amp;#039;&amp;#039;&amp;#039;type&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
&lt;br /&gt;
Der Filter&lt;br /&gt;
 $poi = $pages-&amp;gt;find(template=poi, poi_type.title=&amp;#039;Zoo&amp;#039;); &lt;br /&gt;
Funktioniert nicht!&lt;br /&gt;
&lt;br /&gt;
Stattdessen &lt;br /&gt;
# holt man zuerst alle type-Seiten mit dem Titel Zoo &lt;br /&gt;
# Dieses PageArray kann man direkt als Filter für eine Suche in den POIs nutzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$pr = $pages-&amp;gt;get(&amp;quot;title=Zoo&amp;quot;);&lt;br /&gt;
$poi = $pages-&amp;gt;find(&amp;quot;template=poi, poi_type=$pr&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel 2&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$prs = $pages-&amp;gt;find(&amp;quot;title=Zoo|Themepark|Museum&amp;quot;); // maybe also use the name or id&lt;br /&gt;
$poi = $pages-&amp;gt;find(&amp;quot;template=poi, poi_type=$prs&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ACHTUNG Hier ist es wichtig im ersten Selektor find zu verwenden. Get würde nur den ersten Treffer ausspucken, während find ein PageArray mit allen Ergebnissen zurückgibt.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel 3&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$invoicesNotSent = $pages-&amp;gt;find(&amp;#039;template=invoice,invoice_sent=false&amp;#039;);&lt;br /&gt;
$selector = &amp;quot;template=order,(invoice=$invoicesNotSent),(padinvoice=)&amp;quot;;&lt;br /&gt;
$ordersWithoutInvoiceOrInvoiceNotSent = $pages-&amp;gt;find( $selector );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Punkt Syntax ===&lt;br /&gt;
 $architects = $pages-&amp;gt;find(&amp;quot;template=architect, city.title=Chicago&amp;quot;); &lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect=$architects&amp;quot;); &lt;br /&gt;
That&amp;#039;s easy enough, but wouldn&amp;#039;t it be nicer if you could just do this?&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.title=Chicago&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.abbr=IL&amp;quot;); &lt;br /&gt;
Broadening further, perhaps we want buildings from all architects in the USA:&lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.country.abbr=USA&amp;quot;);&lt;br /&gt;
Or perhaps both USA and Canada:&lt;br /&gt;
&lt;br /&gt;
 $buildings = $pages-&amp;gt;find(&amp;quot;architect.city.state.country.abbr=USA|CA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== User ===&lt;br /&gt;
 http://cheatsheet.processwire.com/users/users-methods/users-find-selector/&lt;br /&gt;
Find all users whose email address ENDS with processwire.com and create a link to email them&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$items = $users-&amp;gt;find(&amp;quot;email$=processwire.com&amp;quot;);&lt;br /&gt;
foreach($items as $item) {&lt;br /&gt;
    echo &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#039;mailto:{$item-&amp;gt;email}&amp;#039;&amp;gt;{$item-&amp;gt;name}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Find all users who have &amp;quot;fred&amp;quot; anywhere in their name&lt;br /&gt;
&lt;br /&gt;
 $items = $users-&amp;gt;find(&amp;quot;name*=fred&amp;quot;);&lt;br /&gt;
Find all users who have the &amp;quot;superuser&amp;quot; role&lt;br /&gt;
&lt;br /&gt;
 $items = $users-&amp;gt;find(&amp;quot;roles=superuser&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Suche alle Kinder / alle Elternseiten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * get children categories for a category for a product&lt;br /&gt;
 * &lt;br /&gt;
 * Page $p category page&lt;br /&gt;
 * int $maxDepth&lt;br /&gt;
 */&lt;br /&gt;
function getChildren($p, $maxDepth=3){ &lt;br /&gt;
    $children = new PageArray;&lt;br /&gt;
    $children-&amp;gt;add($p); // add parent category&lt;br /&gt;
    if ($p-&amp;gt;hasChildren() &amp;amp;&amp;amp; $maxDepth &amp;gt; 1){&lt;br /&gt;
        $children-&amp;gt;add( $p-&amp;gt;children(&amp;#039;template=category&amp;#039;) );&lt;br /&gt;
        foreach($p-&amp;gt;children as $c){&lt;br /&gt;
            $grandchildren = getChildren($c, $maxDepth-1);&lt;br /&gt;
            $children-&amp;gt;add($grandchildren);&lt;br /&gt;
        }&lt;br /&gt;
        $children-&amp;gt;sort(&amp;#039;title&amp;#039;);&lt;br /&gt;
        return $children;&lt;br /&gt;
    }else return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * get filter Categories for a item this includes all parent categories&lt;br /&gt;
 * @return string use as class for the isotope item&lt;br /&gt;
 * */&lt;br /&gt;
function getFilters($item,$prefix=&amp;#039;cat&amp;#039;){&lt;br /&gt;
    // we need to fetch $item categories + parent categories&lt;br /&gt;
    $filters = array();&lt;br /&gt;
    $allCategories = new Pagearray;&lt;br /&gt;
    $categories = $item-&amp;gt;categories;&lt;br /&gt;
    // for each category add category + parent categories to allCategories&lt;br /&gt;
    foreach($categories as $category){&lt;br /&gt;
        $allCategories-&amp;gt;add( $category );&lt;br /&gt;
        $allCategories-&amp;gt;add( $category-&amp;gt;parents(&amp;#039;template=category&amp;#039;) );&lt;br /&gt;
    }&lt;br /&gt;
    foreach($allCategories as $c){&lt;br /&gt;
        $filters[]= $prefix.$c-&amp;gt;id;&lt;br /&gt;
    }&lt;br /&gt;
    return implode(&amp;#039; &amp;#039;,$filters);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Schneller CSV-Export von Selector-Ergebnissen ===&lt;br /&gt;
 [[ProcessWire - schneller CSV-Export]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=27245</id>
		<title>PrivacyWire - ProcessWire Modul</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=27245"/>
		<updated>2024-11-28T17:28:38Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Testen der Implementierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Modul zum Anzeigen eines Cookie Banners und zum Blockieren von Skripten, Externen Medien etc. Das Modul passt das HTML an&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://processwire.com/modules/privacy-wire/&lt;br /&gt;
 https://processwire.com/talk/topic/23118-privacywire-cookie-management-async-external-asset-loading/&lt;br /&gt;
&lt;br /&gt;
== Quickstart Cookie Consent für ProcessWire ==&lt;br /&gt;
* Modul &amp;#039;&amp;#039;&amp;#039;installieren&amp;#039;&amp;#039;&amp;#039; (PrivacyWire)&lt;br /&gt;
* In der Konfiguration &amp;#039;&amp;#039;&amp;#039;Labels übersetzen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Benötigte &amp;#039;&amp;#039;&amp;#039;Kategorien auswählen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Zuordnung der Kategorien funktioniert über data-category Attribut.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Externe Skripte&amp;#039;&amp;#039;&amp;#039; anpassen&lt;br /&gt;
** type bei skripten mit text/plain (wird bei consent durch javascript ersetzt)&lt;br /&gt;
** src durch data-src ersetzen&lt;br /&gt;
** data-category hinzufügen&lt;br /&gt;
** Normale Skripte: type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&lt;br /&gt;
** Externe Skripte: data-src=&amp;quot;...&amp;quot;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Banner&amp;#039;&amp;#039;&amp;#039; anpassen&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Link zu Cookie Einstellungen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Google Consent V2 Skript&lt;br /&gt;
&lt;br /&gt;
== Externe Skripte anpassen ==&lt;br /&gt;
Beispiele:&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;statistics&amp;quot; data-src=&amp;quot;/path/to/your/statistic/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;/path/to/your/marketing/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;external_media&amp;quot; data-src=&amp;quot;/path/to/your/external-media/script.js&amp;quot;&amp;gt;  &amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;console.log(&amp;quot;Inline scripts are also working!&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!-- Global site tag (gtag.js) - Google Analytics --&amp;gt;&lt;br /&gt;
&amp;lt;script async type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=G-DQPX4V13MY&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;&lt;br /&gt;
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag(&amp;#039;js&amp;#039;, new Date());gtag(&amp;#039;config&amp;#039;, &amp;#039;G-DQPX4V13MY&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Link zu Cookie Einstellungen anzeigen ==&lt;br /&gt;
So gibst du einen Link aus mit dem der User die Cookie Einstellungen erneut setzen kann.&lt;br /&gt;
=== Möglichkeit 1 - Textformatter ===&lt;br /&gt;
Den Textformatter der mit PrivacyWire im Editor einbinden und dann den passenden Tag setzen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 [[privacywire-choose-cookies]]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Möglichkeit 2 - HTML Code ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/a&amp;gt; &amp;lt;!-- als Link --&amp;gt;&lt;br /&gt;
&amp;lt;button class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/button&amp;gt; &amp;lt;!-- als Button --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
Hinweis: Zusätzliche Styles. Standardstyles müssen eingebunden sein.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{&lt;br /&gt;
    background-color: #009999 !important;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
    color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{ &lt;br /&gt;
    background-color: #0e71b1 !important;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
    color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button{&lt;br /&gt;
    cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
.privacywire input{&lt;br /&gt;
    position: relative;&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
    margin-right: 0.5em;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
.privacywire label{&lt;br /&gt;
    color: #fff;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Betonter Accept Button / bessere Abstände / saubere Buttons:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.privacywire{&lt;br /&gt;
    padding: 2em !important;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{ &lt;br /&gt;
    background-color: #17428b !important;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
    color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
.privacywire ul{&lt;br /&gt;
    list-style-type: none;&lt;br /&gt;
}&lt;br /&gt;
.privacywire input{&lt;br /&gt;
    position: relative;&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
    margin-right: 0.5em;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
.privacywire label{&lt;br /&gt;
    color: #fff;;&lt;br /&gt;
}&lt;br /&gt;
.privacywire-page-links{&lt;br /&gt;
    margin-top: 0.5rem;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button{&lt;br /&gt;
    background: #b3b3b3;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
    font-weight: normal;&lt;br /&gt;
    border: none;&lt;br /&gt;
    padding: 12px;&lt;br /&gt;
    border-radius: 0px;&lt;br /&gt;
    cursor: pointer;&lt;br /&gt;
    text-transform: uppercase;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button.allow-all{&lt;br /&gt;
    background: #3fa535;&lt;br /&gt;
    border-color: #3fa535;&lt;br /&gt;
    color: #fff;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SCSS Beispiel&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;scss&amp;quot;&amp;gt;&lt;br /&gt;
// Privacy Banner&lt;br /&gt;
$privacywire-bg-color:#d0c5b8;&lt;br /&gt;
$privacywire-text-color: #000;&lt;br /&gt;
$privacywire-button-text-color: #fff;&lt;br /&gt;
$privacywire-button-allow-text-color: #fff;&lt;br /&gt;
$privacywire-button-bg-color: #b3b3b3;&lt;br /&gt;
$privacywire-button-allow-bg-color: #3fa535;&lt;br /&gt;
#privacywire-wrapper{&lt;br /&gt;
	ul{&lt;br /&gt;
		list-style-type: none;&lt;br /&gt;
	}&lt;br /&gt;
	input{&lt;br /&gt;
		position: relative;&lt;br /&gt;
		opacity: 1;&lt;br /&gt;
		margin-right: 0.5em;&lt;br /&gt;
		color: $privacywire-text-color;&lt;br /&gt;
		opacity: 1;&lt;br /&gt;
	}&lt;br /&gt;
	label{&lt;br /&gt;
		color: $privacywire-text-color;;&lt;br /&gt;
	}&lt;br /&gt;
	.privacywire{&lt;br /&gt;
		z-index: 999!important;&lt;br /&gt;
		padding: 2em !important;&lt;br /&gt;
	}&lt;br /&gt;
	.privacywire-banner,&lt;br /&gt;
	.privacywire-options,&lt;br /&gt;
	.privacywire-message{ &lt;br /&gt;
		background-color: $privacywire-bg-color !important;&lt;br /&gt;
		color: $privacywire-text-color;&lt;br /&gt;
		a{&lt;br /&gt;
			color: $privacywire-text-color !important;&lt;br /&gt;
		}&lt;br /&gt;
		button{&lt;br /&gt;
			background: $privacywire-button-bg-color;&lt;br /&gt;
			color: $privacywire-button-text-color;&lt;br /&gt;
			font-weight: normal;&lt;br /&gt;
			border: none;&lt;br /&gt;
			padding: 12px;&lt;br /&gt;
			border-radius: 0px;&lt;br /&gt;
			cursor: pointer;&lt;br /&gt;
			text-transform: uppercase;&lt;br /&gt;
			&amp;amp;.allow-all{&lt;br /&gt;
				background: $privacywire-button-allow-bg-color;&lt;br /&gt;
				border-color: $privacywire-button-allow-bg-color;&lt;br /&gt;
				color: $privacywire-button-allow-text-color;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
	.privacywire-page-links{&lt;br /&gt;
		margin-top: 0.5rem;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Video Embed Opt-In==&lt;br /&gt;
Im VideoEmbed Plugin kann man die Kategorie auswählen (z.B. external Media)&lt;br /&gt;
&lt;br /&gt;
== Bsp. iFrame mit eigenem Opt Out ==&lt;br /&gt;
Mit dem Attribut data-ask-consent=&amp;quot;1&amp;quot; kann man auch einzelne Elemente freigeben.&lt;br /&gt;
 &amp;lt;iframe data-src=&amp;quot;https://processwire.com/&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-ask-consent=&amp;quot;1&amp;quot; class=&amp;quot;require-consent&amp;quot; frameborder=&amp;quot;0&amp;quot; height=&amp;quot;400&amp;quot; width=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available attributes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Attribute	Info	Description	Type&lt;br /&gt;
class require-consent	optional (required if config option enabled)	If the config option &amp;quot;Detect consent windows by class require-consent instead of data-attribute&amp;quot; is enabled	string&lt;br /&gt;
data-category	required	defines the assigned cookie group for this element	string&lt;br /&gt;
data-type	optional (required for scripts)	replaces the type attribute after giving consent	string&lt;br /&gt;
data-src	optional (required for external scripts, images or iframes)	replaces the src attribute after giving consent	string&lt;br /&gt;
data-srset	optional	replaces the srcset attribute for images after giving consent	string&lt;br /&gt;
data-ask-consent	optional	Replace element with Opt-In-Element	bool 0/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For script tags it is required to add type=&amp;quot;text/plain&amp;quot;, otherwise the script executes directly.&lt;br /&gt;
&lt;br /&gt;
== PrivacyWire - Lokalisieren ==&lt;br /&gt;
Dateien übersetzen oder in Einstellungen von Hand übersetzen. Siehe Webmynet Cloud, da gibt es CSV Dateien mit fertigen Übersetzungen zum Hochladen. Deutsch muss als Defaultsprache festgelegt sein.&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung wird nicht angezeigt ===&lt;br /&gt;
* Schau ob die Defaultsprache Deutsch ist.&lt;br /&gt;
* Wenn du angemeldet bist muss deine Usersprache ebenfalls auf Deutsch stehen.&lt;br /&gt;
&lt;br /&gt;
== Google Consent v2 ==&lt;br /&gt;
=== Links ===&lt;br /&gt;
 [[Google Consent Mode v2]]&lt;br /&gt;
&lt;br /&gt;
=== Integration und Implementierung ===&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Einfügen des Tags&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Der Google Consent Mode Tag muss in den Quellcode der Website eingebunden werden, vorzugsweise im Header.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Einwilligungszustände festlegen&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Festlegung der Einwilligungszustände (z. B. granted oder denied) für verschiedene Cookie-Typen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Konfiguration der Tags&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Konfiguration der Google-Tags (z. B. Google Analytics, Google Ads), um das Verhalten basierend auf den Einwilligungszuständen zu steuern.&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel, wie der Code für den Consent Mode aussehen könnte.&lt;br /&gt;
&lt;br /&gt;
Der Code für das Integrieren kommt so von Google:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Google tag (gtag.js) --&amp;gt;&lt;br /&gt;
&amp;lt;script async src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  window.dataLayer = window.dataLayer || [];&lt;br /&gt;
  function gtag(){dataLayer.push(arguments);}&lt;br /&gt;
  gtag(&amp;#039;js&amp;#039;, new Date());&lt;br /&gt;
&lt;br /&gt;
  gtag(&amp;#039;config&amp;#039;, &amp;#039;GA_MEASUREMENT_ID&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir können beim laden der Webseite Default Einstellungen mitgeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Einfügen des gtag.js-Tags mit Unterstützung für Consent Mode&lt;br /&gt;
&amp;lt;script async src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  window.dataLayer = window.dataLayer || [];&lt;br /&gt;
  function gtag(){dataLayer.push(arguments);}&lt;br /&gt;
  gtag(&amp;#039;consent&amp;#039;, &amp;#039;default&amp;#039;, {&lt;br /&gt;
    &amp;#039;ad_storage&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;analytics_storage&amp;#039;: &amp;#039;denied&amp;#039;&lt;br /&gt;
    &amp;#039;ad_user_data&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;ad_personalization&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;wait_for_update&amp;#039;: 2000 // milliseconds to wait for update&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  gtag(&amp;#039;js&amp;#039;, new Date());&lt;br /&gt;
  gtag(&amp;#039;config&amp;#039;, &amp;#039;GA_MEASUREMENT_ID&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn sich die Einwilligungspräferenzen des Nutzers ändern, kann der Code dynamisch angepasst werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Aktualisieren der Einwilligungspräferenzen basierend auf Nutzerentscheidung&lt;br /&gt;
gtag(&amp;#039;consent&amp;#039;, &amp;#039;update&amp;#039;, {&lt;br /&gt;
  &amp;#039;ad_storage&amp;#039;: &amp;#039;granted&amp;#039;,&lt;br /&gt;
  &amp;#039;analytics_storage&amp;#039;: &amp;#039;granted&amp;#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Google Tag mit PrivacyWire ===&lt;br /&gt;
Wir benötigen einen Weg damit PrivacyWire die oben gezeigte Einwilligungsänderung steuern kann.&lt;br /&gt;
&lt;br /&gt;
Allgemein müssen wir folgendes realsieren:&lt;br /&gt;
&lt;br /&gt;
# Google Tag integrieren (mit v2 Option)&lt;br /&gt;
# Google Tag NICHT mit PrivacyWire aussperren&lt;br /&gt;
# PrivacyWire mit JS Funktion ausstatten, die passenden Signals an Google sendet.&lt;br /&gt;
# Funktionen auslösen bei: &lt;br /&gt;
## User speichert Banner&lt;br /&gt;
## User hat Banner gespeichert und kommt auf die Seite =&amp;gt; Cookies checken und Signale senden.&lt;br /&gt;
# Google Tag defaultmäßig auf keine Cookies erlaubt stellen.&lt;br /&gt;
&lt;br /&gt;
=== Implementierung in PrivacyWire - in depth ===&lt;br /&gt;
Das Wichtigste:&lt;br /&gt;
* PrivacyWire kann eine Funktion aufrufen, nachdem es die User Preferences aktualisiert hat. Du trägst den Namen dieser Funktion einfach in der Konfiguration ein. Z.b. updateConsentFromPrivacyWire. &lt;br /&gt;
* Diese Funktion trägst du z.B. zusätzlich zum Google GTAG Code im Header ein.&lt;br /&gt;
* PrivacyWire legt die Usereinstellungen im LocalStorage ab. Dort kann sich die neue Funktion die Einstellungen holen und an Google weiterreichen.&lt;br /&gt;
Sonst: &lt;br /&gt;
* Im localStorage wird der Schlüssel privacyWire angelegt und ein JSON Objekt mit den Usereinstellungen abgelegt. Der alte Schlüssel wird gelöscht.&lt;br /&gt;
 privacywire:&amp;quot;{&amp;quot;version&amp;quot;:1,&amp;quot;cookieGroups&amp;quot;:{&amp;quot;necessary&amp;quot;:true,&amp;quot;functional&amp;quot;:false,&amp;quot;statistics&amp;quot;:true,&amp;quot;marketing&amp;quot;:false,&amp;quot;external_media&amp;quot;:false}}&amp;quot;&lt;br /&gt;
* Danach wird der Banner ausgeblendet und die Bestätigung angezeigt. Dann wird der Code der betroffenen Skripte etc. upgedatet. Am Ende wird eine Custom Funktion aufgerufen die man selbst erstellen kann.&lt;br /&gt;
* Es gibt den Parameter silent=false der wohl an die custom Function mit übergeben wird. Bedeutung habe ich noch nicht recherchiert.&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel PrivacyWire und Google Consent v2 ===&lt;br /&gt;
Trage in der Konfiguration von PrivacyWire die Funktion &amp;#039;&amp;#039;&amp;#039;updateConsentFromPrivacyWire&amp;#039;&amp;#039;&amp;#039; ein.&lt;br /&gt;
&lt;br /&gt;
Hier folgt der Code für &lt;br /&gt;
* Google Tag Manager (kannst du auch auf der Google Tag Manager Seite kopieren)&lt;br /&gt;
* Google Consent V2 + Default Settings&lt;br /&gt;
* Update Funktion die von PrivacyWire aufgerufen wird und die neuen Preferences an Google sendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!-- Google Tag Manager --&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({&amp;#039;gtm.start&amp;#039;:&lt;br /&gt;
new Date().getTime(),event:&amp;#039;gtm.js&amp;#039;});var f=d.getElementsByTagName(s)[0],&lt;br /&gt;
j=d.createElement(s),dl=l!=&amp;#039;dataLayer&amp;#039;?&amp;#039;&amp;amp;l=&amp;#039;+l:&amp;#039;&amp;#039;;j.async=true;j.src=&lt;br /&gt;
&amp;#039;https://www.googletagmanager.com/gtm.js?id=&amp;#039;+i+dl;f.parentNode.insertBefore(j,f);&lt;br /&gt;
})(window,document,&amp;#039;script&amp;#039;,&amp;#039;dataLayer&amp;#039;,&amp;#039;GTM-ID-HERE&amp;#039;);&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;!-- End Google Tag Manager --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- GOOGLE CONSENT V2 --&amp;gt;&lt;br /&gt;
&amp;lt;script async src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=GTM-ID-HERE&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  window.dataLayer = window.dataLayer || [];&lt;br /&gt;
  function gtag(){dataLayer.push(arguments);}&lt;br /&gt;
  gtag(&amp;#039;consent&amp;#039;, &amp;#039;default&amp;#039;, {&lt;br /&gt;
    &amp;#039;ad_storage&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;analytics_storage&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;ad_user_data&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;ad_personalization&amp;#039;: &amp;#039;denied&amp;#039;,&lt;br /&gt;
    &amp;#039;wait_for_update&amp;#039;: 2000 // milliseconds to wait for update&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  gtag(&amp;#039;js&amp;#039;, new Date());&lt;br /&gt;
  gtag(&amp;#039;config&amp;#039;, &amp;#039;GTM-ID-HERE&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;!-- End GOOGLE CONSENT V2 --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Update user preferences --&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
function updateConsentFromPrivacyWire() {&lt;br /&gt;
  console.log(&amp;#039;update consent from privacy wire...&amp;#039;);&lt;br /&gt;
  const privacyWireData = localStorage.getItem(&amp;#039;privacywire&amp;#039;);&lt;br /&gt;
  if (privacyWireData) {&lt;br /&gt;
    try {&lt;br /&gt;
      const consentData = JSON.parse(privacyWireData);&lt;br /&gt;
      const consentPreferences = {&lt;br /&gt;
        &amp;#039;ad_storage&amp;#039;: consentData.cookieGroups.marketing ? &amp;#039;granted&amp;#039; : &amp;#039;denied&amp;#039;,&lt;br /&gt;
        &amp;#039;analytics_storage&amp;#039;: consentData.cookieGroups.statistics ? &amp;#039;granted&amp;#039; : &amp;#039;denied&amp;#039;,&lt;br /&gt;
        &amp;#039;ad_user_data&amp;#039;: consentData.cookieGroups.marketing ? &amp;#039;granted&amp;#039; : &amp;#039;denied&amp;#039;,&lt;br /&gt;
        &amp;#039;ad_personalization&amp;#039;: consentData.cookieGroups.marketing ? &amp;#039;granted&amp;#039; : &amp;#039;denied&amp;#039;&lt;br /&gt;
      };&lt;br /&gt;
      &lt;br /&gt;
      // Update gogle consent&lt;br /&gt;
      gtag(&amp;#039;consent&amp;#039;, &amp;#039;update&amp;#039;, consentPreferences);&lt;br /&gt;
      console.log(consentPreferences);&lt;br /&gt;
    } catch (e) {&lt;br /&gt;
      console.error(&amp;#039;Error parsing PrivacyWire-Data:&amp;#039;, e);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    console.warn(&amp;#039;No PrivacyWire-Data found in localStorage&amp;#039;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
// Update consent at pageload&lt;br /&gt;
document.addEventListener(&amp;#039;DOMContentLoaded&amp;#039;, updateConsentFromPrivacyWire);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testen der Implementierung ===&lt;br /&gt;
Über tagassistant.google.com&lt;br /&gt;
&lt;br /&gt;
Sollte etwa so ausschauen:&lt;br /&gt;
[[Datei:Google Tagassistant 1.png|gerahmt|links|Testen der Google Consent V2 Einstellung]]&lt;br /&gt;
&lt;br /&gt;
=== Analytics und Conversions ===&lt;br /&gt;
==== Analytics ====&lt;br /&gt;
Google Analytics Tag im GTM erstellen&lt;br /&gt;
&lt;br /&gt;
    Gehe zu deinem Google Tag Manager Konto und öffne den entsprechenden Container.&lt;br /&gt;
    Erstelle ein neues Tag:&lt;br /&gt;
        Klicke auf &amp;quot;Tags&amp;quot; im linken Menü.&lt;br /&gt;
        Klicke auf &amp;quot;Neu&amp;quot; und gib dem Tag einen Namen (z. B. &amp;quot;Google Analytics - Universal Analytics&amp;quot;).&lt;br /&gt;
    Tag-Typ auswählen:&lt;br /&gt;
        Klicke auf &amp;quot;Tag-Konfiguration&amp;quot; und wähle &amp;quot;Google Analytics: Universal Analytics&amp;quot; aus.&lt;br /&gt;
    Tracking-Typ auswählen:&lt;br /&gt;
        Wähle &amp;quot;Seitenaufruf&amp;quot; als Tracking-Typ.&lt;br /&gt;
    Google Analytics Einstellungen konfigurieren:&lt;br /&gt;
        Klicke auf &amp;quot;Neue Variable&amp;quot; unter &amp;quot;Google Analytics-Einstellungen&amp;quot; und erstelle eine neue Variable für deine Google Analytics ID (z. B. &amp;quot;GA-XXXXXX&amp;quot;).&lt;br /&gt;
        Gib deine Google Analytics Tracking-ID ein (UA-XXXXXX-Y).&lt;br /&gt;
        Speichere die Variable.&lt;br /&gt;
    Trigger hinzufügen:&lt;br /&gt;
        Klicke auf &amp;quot;Triggering&amp;quot; und wähle &amp;quot;All Pages&amp;quot; (Alle Seiten) aus.&lt;br /&gt;
    Tag speichern:&lt;br /&gt;
        Speichere das Tag und veröffentliche die Änderungen im GTM.&lt;br /&gt;
==== Conversions ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Werden die Tags für das Conversion Tracking auch über den GTM ausgespielt?&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
ChatGPT&lt;br /&gt;
&lt;br /&gt;
Ja, auch die Tags für das Conversion Tracking können (und sollten) über den Google Tag Manager (GTM) verwaltet werden. Das hat den Vorteil, dass du alle deine Tags zentral an einem Ort verwalten und flexibel auf Einwilligungen reagieren kannst.&lt;br /&gt;
Einrichten von Conversion Tracking im Google Tag Manager&lt;br /&gt;
&lt;br /&gt;
Hier sind die Schritte, um Conversion Tracking Tags im GTM einzurichten:&lt;br /&gt;
1. Conversion Tracking Tag im GTM erstellen&lt;br /&gt;
&lt;br /&gt;
    Öffne dein Google Tag Manager Konto und wähle den entsprechenden Container.&lt;br /&gt;
    Erstelle ein neues Tag:&lt;br /&gt;
        Klicke auf &amp;quot;Tags&amp;quot; im linken Menü.&lt;br /&gt;
        Klicke auf &amp;quot;Neu&amp;quot; und gib dem Tag einen Namen (z. B. &amp;quot;Google Ads Conversion Tracking&amp;quot;).&lt;br /&gt;
    Tag-Typ auswählen:&lt;br /&gt;
        Klicke auf &amp;quot;Tag-Konfiguration&amp;quot; und wähle den entsprechenden Tag-Typ aus, z. B. &amp;quot;Google Ads Conversion Tracking&amp;quot;.&lt;br /&gt;
    Conversion ID und Conversion Label eingeben:&lt;br /&gt;
        Gib die Conversion ID und das Conversion Label ein, die du von deinem Google Ads Konto erhalten hast.&lt;br /&gt;
&lt;br /&gt;
2. Conversion Tracking Trigger hinzufügen&lt;br /&gt;
&lt;br /&gt;
    Trigger hinzufügen:&lt;br /&gt;
        Klicke auf &amp;quot;Triggering&amp;quot; und wähle einen passenden Trigger aus, z. B. &amp;quot;Page View&amp;quot; für alle Seitenaufrufe oder einen benutzerdefinierten Trigger für spezifische Conversion-Ereignisse.&lt;br /&gt;
        Du kannst benutzerdefinierte Trigger für spezifische Conversion-Aktionen wie Formulareinsendungen oder Käufe erstellen.&lt;br /&gt;
&lt;br /&gt;
3. Google Consent Mode und PrivacyWire Einbindung&lt;br /&gt;
&lt;br /&gt;
Stelle sicher, dass du den Google Consent Mode und die PrivacyWire Einbindung gemäß den Einwilligungen der Nutzer aktualisierst.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Einrichten von Conversion Tracking im GTM&lt;br /&gt;
1. Gehe zu deinem GTM-Konto und erstelle ein neues Tag für Conversion Tracking.&lt;br /&gt;
&lt;br /&gt;
    Klicke auf &amp;quot;Tags&amp;quot; und dann auf &amp;quot;Neu&amp;quot;.&lt;br /&gt;
    Wähle &amp;quot;Google Ads Conversion Tracking&amp;quot; als Tag-Typ.&lt;br /&gt;
    Gib deine Conversion ID und dein Conversion Label ein.&lt;br /&gt;
&lt;br /&gt;
2. Erstelle den Trigger für das Conversion Tracking.&lt;br /&gt;
&lt;br /&gt;
    Klicke auf &amp;quot;Trigger&amp;quot; und dann auf &amp;quot;Neu&amp;quot;.&lt;br /&gt;
    Wähle einen Trigger-Typ aus, z. B. &amp;quot;Page View&amp;quot; oder einen benutzerdefinierten Trigger für spezifische Aktionen.&lt;br /&gt;
&lt;br /&gt;
3. Füge den Trigger zum Conversion Tracking Tag hinzu.&lt;br /&gt;
&lt;br /&gt;
    Verknüpfe den Trigger mit deinem Conversion Tracking Tag.&lt;br /&gt;
&lt;br /&gt;
4. Veröffentliche die Änderungen im GTM.&lt;br /&gt;
&lt;br /&gt;
    Klicke auf &amp;quot;Senden&amp;quot; und dann auf &amp;quot;Veröffentlichen&amp;quot;, um die Änderungen zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
Mit dieser Konfiguration werden alle Tags, einschließlich der Conversion Tracking Tags, über den Google Tag Manager verwaltet und basierend auf den Einwilligungen der Nutzer korrekt ausgelöst.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:Google_Tagassistant_1.png&amp;diff=27244</id>
		<title>Datei:Google Tagassistant 1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:Google_Tagassistant_1.png&amp;diff=27244"/>
		<updated>2024-11-28T17:28:26Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Testen der Google Consent V2 Konfiguration im Tagassistant&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:Handpan-Kurd.png&amp;diff=27140</id>
		<title>Datei:Handpan-Kurd.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:Handpan-Kurd.png&amp;diff=27140"/>
		<updated>2024-07-02T16:57:50Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Handpan in Kurd Stimmung&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:Handpan-Amara-Celtic.png&amp;diff=27139</id>
		<title>Datei:Handpan-Amara-Celtic.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:Handpan-Amara-Celtic.png&amp;diff=27139"/>
		<updated>2024-07-02T16:57:16Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Amara Celtic Stimmung&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Musik&amp;diff=27138</id>
		<title>Musik</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Musik&amp;diff=27138"/>
		<updated>2024-07-02T16:56:28Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Musik allgemein ==&lt;br /&gt;
 [[Musik Hardware und Software]]&lt;br /&gt;
 [[Komposition]]&lt;br /&gt;
 [[Musik - Creating Moods / Stimmung erzeugen]]&lt;br /&gt;
 [[Musikproduktion - EQ Einstellungen]]&lt;br /&gt;
&lt;br /&gt;
== Handpan ==&lt;br /&gt;
 [[Handpan - Stimmungen]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Musikproduktion_-_EQ_Einstellungen&amp;diff=27137</id>
		<title>Musikproduktion - EQ Einstellungen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Musikproduktion_-_EQ_Einstellungen&amp;diff=27137"/>
		<updated>2024-07-02T16:49:16Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „EQ Bereiche  rahmenlos“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;EQ Bereiche&lt;br /&gt;
&lt;br /&gt;
[[Datei:EQ-Einstellungen.png|rahmenlos]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:EQ-Einstellungen.png&amp;diff=27136</id>
		<title>Datei:EQ-Einstellungen.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:EQ-Einstellungen.png&amp;diff=27136"/>
		<updated>2024-07-02T16:48:46Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Equilizer Einstellungsbereiche&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Musik&amp;diff=27135</id>
		<title>Musik</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Musik&amp;diff=27135"/>
		<updated>2024-07-02T16:47:44Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; [[Musik Hardware und Software]]&lt;br /&gt;
 [[Komposition]]&lt;br /&gt;
 [[Musik - Creating Moods / Stimmung erzeugen]]&lt;br /&gt;
 [[Musikproduktion - EQ Einstellungen]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=DaVinci_Resolve_-_Color_Grading&amp;diff=27134</id>
		<title>DaVinci Resolve - Color Grading</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=DaVinci_Resolve_-_Color_Grading&amp;diff=27134"/>
		<updated>2024-07-02T16:32:12Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Beispiel Color Grading Nodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.youtube.com/watch?v=FUhLgYfyFkE - DaVinci Resolve Color Tab **&lt;br /&gt;
 [[DaVinci Resolve - Tipps und Tricks]]&lt;br /&gt;
 https://www.youtube.com/watch?v=7YqrgaT1rxQ - Guter Einstieg mit 2 bis 4 Node Strategy&lt;br /&gt;
 [[Video - Color Space und Luminanz Dynamik anpassen]]&lt;br /&gt;
 [[DaVinci Resolve - Color Management, Farbräume, Luminanzdynamik]]&lt;br /&gt;
&lt;br /&gt;
== Hinweis: Color Space und Luminanz-Dynamik ==&lt;br /&gt;
Bevor du loslegst solltest du checken in welchem Farbraum dein Material vorliegt. Dann kannst du die Videoschnittsoftware passend einstellen. Check den Link [[DaVinci Resolve - Color Management, Farbräume, Luminanzdynamik]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Wie geht Color Grading? ==&lt;br /&gt;
Was beinhaltet Color Grading und wie kann man vorgehen. Wichtig ist hier ein sinnvoller Workflow. Man sollte immer zunächst das Material sauber korrigieren und einstellen und erst danach an künstlerische Aspekte oder gar LUTs denken.&lt;br /&gt;
&lt;br /&gt;
=== Color Grading Methodology ===&lt;br /&gt;
Hier die wichtigsten Punkte die man im Grading Workflow berücksichtigen sollte. Je nach Material und Anforderung muss man nicht für jeden Punkt im Detail Arbeit investieren.&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Kontrast&amp;#039;&amp;#039;&amp;#039; anpassen: Kontrast erhöhen/verringern &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Sättigung einstellen&amp;#039;&amp;#039;&amp;#039;: Sättigung steigern oder veringern&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Highlight und Schattenverbesserung&amp;#039;&amp;#039;&amp;#039;: Highlight-Wiederherstellung (Details in überbelichteten Bereichen zurückbringen, indem Lichter wiederhergestellt werden) und Schattenlift (versteckte Details in dunkleren Bereichen des Bildes aufdeckt) &lt;br /&gt;
# Verwende die Farbräder, Kurven (Licht und Farben) oder LUTs, um die &amp;#039;&amp;#039;&amp;#039;Balance von Lichtern, Mitteltönen und Schatten&amp;#039;&amp;#039;&amp;#039; anzupassen &lt;br /&gt;
# HSL (Schatten/Sättigung/Helligkeit) anpassen: Isolieren und anpassen &amp;#039;&amp;#039;&amp;#039;bestimmter Farben&amp;#039;&amp;#039;&amp;#039; im Bild mit den HSL-Steuerelementen &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Split Tone&amp;#039;&amp;#039;&amp;#039; an: Färben Lichter und Schatten unabhängig voneinander mit unterschiedlichen Farben.&lt;br /&gt;
&lt;br /&gt;
=== Werkzeuge ===&lt;br /&gt;
Mit diesen Werkzeugen oder Strategien kannst du Color Grading realisieren.&lt;br /&gt;
* Nimm &amp;#039;&amp;#039;&amp;#039;gezielte Anpassungen&amp;#039;&amp;#039;&amp;#039; am Bild mit Power Windows und Qualifiers vor. &lt;br /&gt;
* Realisiere Änderungen an Farbe, Leuchtdichte und anderen Kriterien indem du &amp;#039;&amp;#039;&amp;#039;Bereiche&amp;#039;&amp;#039;&amp;#039; mithilfe von Keying und Qualifizierern isolierst.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Mischmodi&amp;#039;&amp;#039;&amp;#039;: Experimentiere mit verschiedenen Mischmodi (Normal, Multiplizieren, Bildschirm, Überlagerung, weiches Licht, Hartlicht, Addieren, Subtrahieren, Differenz, HSCL, Ausschluss, benutzerdefiniertes Alpha): Wie Anpassungsebenen, Ebenen und Knoten miteinander gemischt werden &lt;br /&gt;
* Nutze Inspirationsquellen und Referenzen für Farbpaletten z.B.&lt;br /&gt;
 https://shotdeck.com (Kostenpflichtig)&lt;br /&gt;
 https://digitalsynopsis.com/design/cinema-palettes-famous-movie-colors/&lt;br /&gt;
 Suche nach Movie Color Palette&lt;br /&gt;
&lt;br /&gt;
== Color Correction / Balancing ==&lt;br /&gt;
=== Quick CC Method ===&lt;br /&gt;
Eine einfache schnelle Strategie für saubere Farben ist Folgende:&lt;br /&gt;
 Color Tab &amp;gt; Histogramm anschalten&lt;br /&gt;
 Bild mit hoher Dyamik suchen&lt;br /&gt;
 Dynamikkurve &amp;gt; Grenzen auf Lichter und Schatten einstellen&lt;br /&gt;
 Bei Bedarf Schatten mit Kurve wieder mehr Zeichnung holen.&lt;br /&gt;
 Gamma anpassen (dunkler für Cinematic Look, oder heller je nach Wunsch)&lt;br /&gt;
 Gain leicht ins Grün ziehen für mehr Filmic Look.&lt;br /&gt;
&lt;br /&gt;
== Beispiele für Color Grading Workflows ==&lt;br /&gt;
=== Node Strategy ===&lt;br /&gt;
Zum Einstieg eignen sich bestimmte Nodes die man immer wieder in der gleichen Reihenfolge einsetzt. Dabei unterscheidet man die Bereiche Color Correction und Grading. Also zuerst die Korrektur des Footage, dann der Stil. Die Bereiche kann man wiederum in mehrere Teilbereiche unterteilen.&lt;br /&gt;
==== 2 Node Strategy ====&lt;br /&gt;
 1.Color Correction - 2.Color Grading&lt;br /&gt;
&lt;br /&gt;
Bei der Color Correction kann man auch mit der Automatik beginnen. &lt;br /&gt;
==== 4 Node Strategy ====&lt;br /&gt;
Eine feinere Unterteilung wäre folgende:&lt;br /&gt;
&lt;br /&gt;
 1.Color Correction - 2.Gamma Correction - 3.Shadows and Higlights - 4.Color Grading&lt;br /&gt;
Für die Gamma Correction kann man z.B. die Gradientenkurve nehmen. Shadows und Highlights über die Korrekturrädchen.&lt;br /&gt;
&lt;br /&gt;
Auch hier lassen sich wieder alle Bereiche in Teilbereiche unterteilen.&lt;br /&gt;
&lt;br /&gt;
=== Artistic Contrast mit Opposite Color Methode ===&lt;br /&gt;
 https://www.youtube.com/watch?v=zB4va-xVFqM&lt;br /&gt;
&lt;br /&gt;
Die Technik basiert darauf, nur zwei Farben im Bild zu behalten und sicherzustellen, dass sie einen starken Farbkontrast haben.&lt;br /&gt;
Diese Methode eignet sich hervorragend für künstlerische Projekte, bei denen Farbgenauigkeit nicht oberste Priorität hat.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Reduzieren der Farbpalette&amp;#039;&amp;#039;&amp;#039; Beginnen Sie damit, alle Farben außer zwei aus dem Bild zu entfernen. Diese beiden Farben sollten auf gegenüberliegenden Seiten des Farbkreises liegen, um einen starken Kontrast zu erzeugen.&lt;br /&gt;
* Anpassung der &amp;#039;&amp;#039;&amp;#039;Sättigung&amp;#039;&amp;#039;&amp;#039; Da die ausgewählten Farben möglicherweise zu gesättigt sind, ist es ratsam, die Sättigung zu reduzieren, um ein ausgewogeneres Farbbild zu erhalten.&lt;br /&gt;
* Anpassung des &amp;#039;&amp;#039;&amp;#039;Farbtons&amp;#039;&amp;#039;&amp;#039; Falls erforderlich, können Sie den Farbton der ausgewählten Farben anpassen, um sicherzustellen, dass sie harmonisch zueinander passen (Hue Regler). Es ist außerdem sinnvoll bei den folgenden Schritten im Vectroskop die Hauttöne anzeigen zu lassen. Dann kann man die Farben darauf anpassen.&lt;br /&gt;
** Hauttonfarbe erhalen über Hue Regler Rottöneauf &amp;#039;&amp;#039;&amp;#039;Hautton&amp;#039;&amp;#039;&amp;#039; drehen&lt;br /&gt;
** Behandlung von Grün &amp;#039;&amp;#039;&amp;#039;Wenn Ihr Bild viel Grün enthält&amp;#039;&amp;#039;&amp;#039; und Sie diesen Farbton beibehalten möchten, können Sie eine zusätzliche Technik anwenden. Erstellen Sie eine Linie von Farben auf der gegenüberliegenden Seite des Farbkreises, die Grün einschließen. Dadurch können Sie Grün separat steuern, ohne die anderen ausgewählten Farben zu beeinflussen.&lt;br /&gt;
Feinabstimmung Verwenden Sie die eingebauten Werkzeuge, wie den Hue-Controller, um Feinabstimmungen an den ausgewählten Farben vorzunehmen, um das gewünschte Ergebnis zu erzielen.&lt;br /&gt;
Fertigstellung Die endgültige Bildbearbeitung sollte zu einem Bild führen, bei dem die ausgewählten Farben perfekt kontrastieren und harmonieren.&lt;br /&gt;
&lt;br /&gt;
=== Teal Orange Look - Pro Workflow ===&lt;br /&gt;
https://www.youtube.com/watch?v=IDP3j_4icBo&lt;br /&gt;
==== Nodes für Balancing ====&lt;br /&gt;
 Highlights - &lt;br /&gt;
 Printer Lites - Primaries CC -&lt;br /&gt;
 Teal Orange Corr - Teal Orange Look - Teal Orange Adj. -&lt;br /&gt;
 Glow - Grain&lt;br /&gt;
&lt;br /&gt;
=====1. Balancing (Base Grade)=====&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Primaries&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Offset, Contrast, Focus auf Skin etc.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Printer lites&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Offset Color angleichen (dezent vorgehen)&lt;br /&gt;
&lt;br /&gt;
=====2. Grading=====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Teal Orange Look&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Lift (Teal) - Gamma (gegensteuern um Hauttöne wieder herzustellen)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Teal Orange Correction&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Fokus auf &amp;#039;&amp;#039;&amp;#039;Lichter, Schwarz, Hauttöne&amp;#039;&amp;#039;&amp;#039; - dies sind die wichtigen Bereiche die den Look professionell ausschauen lassen. Schatten dürfen nicht gefärbt und übersättigt ausschauen. Hauttöne sollen natürlich ausschauen&lt;br /&gt;
* Shadow &amp;gt; gegen Teal steuern&lt;br /&gt;
* Midtones &amp;gt; mehr Orange in die Hauttöne bringen&lt;br /&gt;
* Highlights falls gefärbt ebenfalls anpassen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Look Adjustment &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Look lebendiger machen.&lt;br /&gt;
* Lift &lt;br /&gt;
* Splines etc...&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Glow&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Glow Effekt&lt;br /&gt;
&lt;br /&gt;
 Composite Type &amp;gt; Softlight&lt;br /&gt;
 Spread &amp;gt; 0&lt;br /&gt;
 Blend &amp;gt; reduzieren damit es nicht zu unnatürlich wirkt.&lt;br /&gt;
&lt;br /&gt;
===== 3. Fine Tuning =====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Highlights&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
 Shift + A (Auswahl anzeigen) &amp;gt; Highlights über Luminance Qualifier auswählen &lt;br /&gt;
 Highlights reduzieren damit Zeichnung da ist und das Teal mehr durchkommt.&lt;br /&gt;
 Fine Tuning z.b. bei den Look Adjustments&lt;br /&gt;
 Mehr Filmic Look &amp;gt; Hue vs Sat &amp;gt; Rottöne etwas runter &amp;gt; evtl. Gelb auch etwas.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Grain&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Am Ende (weil Rechenintensiv)&lt;br /&gt;
 Grain Effekt&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Color Grading Nodes ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:ColorGradingNodes-01.png|rahmenlos]]&lt;br /&gt;
&lt;br /&gt;
== Color Grading Tipps und Tricks ==&lt;br /&gt;
=== LUTs richtig einsetzen ===&lt;br /&gt;
LUTs sind immer für einen bestimmten Color Space gemacht - zumindest wenn Sie nicht erstellt sind um von einem Color Space in den anderen zu transformieren.&lt;br /&gt;
Das bedeutet du musst sie im &amp;#039;&amp;#039;&amp;#039;richtigen Color Space&amp;#039;&amp;#039;&amp;#039; einsetzen, sonst erzielst du nicht das gewünschte Ergebnis. Außerdem ist es wichtig zuerst dein Material zu normalisieren und dann die LUT zu verwenden. In DaVinci Resolve kannst du das mit den Knoten gut organisieren. Beispiel für die mitgelieferten DaVinci Film Looks. &lt;br /&gt;
&lt;br /&gt;
 Input Color Space Transform (ICT) &amp;gt; Farbkorrektur im Working Color Space &amp;gt; Output Color Space Transform (i.d.R to Rec.709)&lt;br /&gt;
 &amp;gt; CST mit Gamma Cineon Film Log (Rest bleibt auf Timeline bzw. Default)&lt;br /&gt;
&lt;br /&gt;
So erhälst du das richtige Gamma für die Stock LUTs. Sinnvoll ist immer der Einsatz am Ende der Kette. Du kannst schon am Anfang (nach der Color Correction) eine Richtung mit dem LUT Node vorgeben und den Look in den Knoten davor nach Wunsch tweaken.&lt;br /&gt;
&lt;br /&gt;
Teste mal ob der LUT Knoten besser vor dem letzten Color Transform funktioniert. Evtl. einfach Color Transforms für den LUT davor und dahinter schalten (ungetestet).&lt;br /&gt;
&lt;br /&gt;
=== Schnelle Grading Tipps ===&lt;br /&gt;
&lt;br /&gt;
==== Blue Shadows ====&lt;br /&gt;
 Add Blue to Shadows (Lift Blue Channel)&lt;br /&gt;
 Reduce Blue in Highlights (Gain Blue Channel)&lt;br /&gt;
 Lum vs Sat &amp;gt; Reduce Saturation in Shadows&lt;br /&gt;
&lt;br /&gt;
==== Rich Colors with Color Space Nodes ====&lt;br /&gt;
 https://www.youtube.com/watch?v=Ze7bRAuIQGg&lt;br /&gt;
Basiert darauf, dass man mit &amp;#039;&amp;#039;&amp;#039;Nodes in verschiedenen Color Spaces&amp;#039;&amp;#039;&amp;#039; unterschiedliche Aspekte gezielt beeinflussen kann.&lt;br /&gt;
 Knoten im HSV CS &amp;gt; Gain &amp;gt; Grün erhöhen&lt;br /&gt;
Der Grünregler regelt jetzt die Sättigung der Farben ohne deren Helligkeit zu verändern. Das kann allerdings Probleme im Blaukanal (vor allem in den Tiefen) erzeugen. Also aufpassen und ggfls &amp;#039;&amp;#039;&amp;#039;Node davor&amp;#039;&amp;#039;&amp;#039; setzen und:&lt;br /&gt;
 Hue vs Sat &amp;gt; Blau Bereich weniger Sättigung&lt;br /&gt;
 Schatten aufhellen&lt;br /&gt;
&lt;br /&gt;
=== Filmic Look mit Desaturate Shadows / Dark Chroma ===&lt;br /&gt;
Problem wenn man für einen Film Look Farben verändert entstehen oft, da die Schatten nach Farbkorrekturen (oder Styles) zu stark gesättigt sind. So kannst du dass beheben:&lt;br /&gt;
&lt;br /&gt;
Möglichkeit 1: In DaVinci via &lt;br /&gt;
 Sat vs Luma Sättigung aus den Schattenziehen&lt;br /&gt;
&lt;br /&gt;
Möglichkeit 2: In DaVinci Knoten auswählen und&lt;br /&gt;
 Color &amp;gt; Presets &amp;gt; Chroma Dark&lt;br /&gt;
Dies erzeugt eine qualified Mask für die Schatten und zieht die Sättigung raus.&lt;br /&gt;
&lt;br /&gt;
Jetzt kannst du vor dem Entfernen der Sättigung einen Knoten setzen in dem du ein Offset für die Farben machen kannst. Das sieht jetzt richtig gut aus, da die Schatten &amp;quot;schattig&amp;quot; bleiben.&lt;br /&gt;
&lt;br /&gt;
=== Hochglanz-Look mit Highlight-Shadow Compression ===&lt;br /&gt;
Ein Look wie in Kochshows oder im Real-Estate Bereich mit kräftigen Farben und sehr durchgezeichneten Lichtern und Schatten bekommst du mit einem einfachen Trick:&lt;br /&gt;
* Scopes am besten Waveform anzeigen un zu sehen was passiert.&lt;br /&gt;
* 1. Node Color Wheels &amp;#039;&amp;#039;&amp;#039;Schatten +100, Highlights -100&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 2. Node &amp;#039;&amp;#039;&amp;#039;Auto Color&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 1. Node &amp;#039;&amp;#039;&amp;#039;Mid Details&amp;#039;&amp;#039;&amp;#039; anpassen, dass keine Halos bei großen Kontrasten mehr da sind. &lt;br /&gt;
* 3. Node bei Bedarf &amp;#039;&amp;#039;&amp;#039;Gamma und Gain&amp;#039;&amp;#039;&amp;#039; etc. anpassen.&lt;br /&gt;
&lt;br /&gt;
=== Color System auf Timeline ===&lt;br /&gt;
DaVinci Resolve kann pro Timeline unterschiedliche Color Systems verwenden. &lt;br /&gt;
&lt;br /&gt;
=== ACES Workflow ===&lt;br /&gt;
ACES ist ein Color Science Setting. Es versucht bei Anpassungen das Verhalten des menschlichen Auges nachzuempfinden. Wenn man z.B. die Helligkeit manipuliert versucht es zu vermeiden das Lichter oder Schatten verloren gehen und komprimiert stattdessen im oberen und unteren Bereich.&lt;br /&gt;
&lt;br /&gt;
Auf diese Weise kann man Color Gradings effektiver vornehmen.&lt;br /&gt;
&lt;br /&gt;
Man kann ACES z.B für die Timeline setzen. Es geht auch über die Project Setting aber so kannst du mit mehreren Timelines verschiedene Dinge ausprobieren.&lt;br /&gt;
&lt;br /&gt;
 Timeline &amp;gt; Rechtsklick &amp;gt; Timelines &amp;gt; Timeline Settings&lt;br /&gt;
 Color Tab &amp;gt; Use Project Settings abhaken&lt;br /&gt;
 Color Science &amp;gt; ACEScct&lt;br /&gt;
 ACES Output Transform Rec.709 (Anzeigemonitor nutzt Rec.709)&lt;br /&gt;
&lt;br /&gt;
Als nächstes &amp;#039;&amp;#039;&amp;#039;ACES Input Transform&amp;#039;&amp;#039;&amp;#039; für alle Clips auswählen&lt;br /&gt;
 Color Tab &amp;gt; Clips auswählen &amp;gt; Rechtsklick &amp;gt; Color Space auswählen&lt;br /&gt;
&lt;br /&gt;
== LUTs ==&lt;br /&gt;
 https://freshluts.com/ - LUTs zum Downloaden&lt;br /&gt;
 https://www.youtube.com/watch?v=Wwwa6eDdLXU - How to install und bessere Settings für LUT Processing/Interpolation&lt;br /&gt;
=== Cineon Film LUTS ===&lt;br /&gt;
DaVinci Resolve hat ein paar gute Film Luts für Rec.709. Aber Vorsicht. Sie sind für Filmscanning gedacht und wirken auf den ersten Blick viel zu dunkel. Man muss den &lt;br /&gt;
 Gamma Output des Knotens &amp;gt; Cineon Film Log stellen.&lt;br /&gt;
&lt;br /&gt;
=== Stärke von LUTs verringern ===&lt;br /&gt;
 Node für LUT OHNE den Output zu verändern&lt;br /&gt;
 Node für Color Space Transform &amp;gt; Gamma Out &amp;gt; Cineon Film Log (VOR den LUT Node)&lt;br /&gt;
 Beide Nodes markieren &amp;gt; Compound Node&lt;br /&gt;
 Key Tab &amp;gt; Gain Regler &amp;gt; Stärke einstellen.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:ColorGradingNodes-01.png&amp;diff=27133</id>
		<title>Datei:ColorGradingNodes-01.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:ColorGradingNodes-01.png&amp;diff=27133"/>
		<updated>2024-07-02T16:31:36Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;DaVinci Color Grading Nodes&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26729</id>
		<title>Swift - Singleton Pattern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26729"/>
		<updated>2023-01-31T17:27:11Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Singletons sind Eigenschaften einer Klasse, die in allen Instanzen der Klasse gleich sind. Wenn man den Wert in einer Instanz ändert, sind auch alle anderen Instanzen betroffen. &lt;br /&gt;
&lt;br /&gt;
Daher kann man sie nutzen, wenn man über alle Instanzen immer auf den gleichen Wert zugreifen will, egal wo sich die Instanz befindet.&lt;br /&gt;
&lt;br /&gt;
Um diese Eigenschaft zu realisieren nutzt das Singleton Pattern eine statische Variable. In dieser Variable wird eine Instanz der Klasse selbst gespeichert.&lt;br /&gt;
&lt;br /&gt;
Normalerweise kann man auf eine static var nur über den Klassennamen zugreifen. Dadurch dass die Klasse sich selbst als Eigenschaft enthält kann man nun auch über die Instanzen auf statische Variablen zugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With the singleton pattern you can share properties through all instances of a class&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 Normally all properties of a class are independent of each other...&lt;br /&gt;
 */&lt;br /&gt;
class Car{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var aCar = Car()&lt;br /&gt;
aCar.color = &amp;quot;blue&amp;quot;&lt;br /&gt;
var bCar = Car()&lt;br /&gt;
// aCar is blue, bCar ist red&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With singleton pattern you create a instance of the class itself&lt;br /&gt;
 as a property of the class&lt;br /&gt;
 */&lt;br /&gt;
class Ship{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
    static let singletonShip = Ship()&lt;br /&gt;
}&lt;br /&gt;
var aShip = Ship.singletonShip&lt;br /&gt;
var bShip = Ship.singletonShip&lt;br /&gt;
// now aShip and bShip hold a reference to the SAME object&lt;br /&gt;
bShip.color = &amp;quot;pink&amp;quot;&lt;br /&gt;
print(aShip.color) // pink&lt;br /&gt;
print(bShip.color) // pink&lt;br /&gt;
&lt;br /&gt;
// Singletons are used in Swift ie&lt;br /&gt;
// UserDefaults.defaults&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26728</id>
		<title>Swift - Singleton Pattern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26728"/>
		<updated>2023-01-31T17:21:39Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Singletons sind Eigenschaften einer Klasse, die in allen Instanzen der Klasse gleich sind. Wenn man den Wert in einer Instanz ändert, sind auch alle anderen Instanzen betroffen. &lt;br /&gt;
&lt;br /&gt;
Daher kann man sie nutzen, wenn man über alle Instanzen immer auf den gleichen Wert zugreifen will, egal wo sich die Instanz befindet.&lt;br /&gt;
&lt;br /&gt;
Um diese Eigenschaft zu realisieren nutzt das Singleton Pattern eine statische Variable. In dieser Variable wird eine Instanz der Klasse selbst gespeichert.&lt;br /&gt;
&lt;br /&gt;
Frage wenn man statt einer Instanz der Klasse selbst eine Instanz einer andern Klasse als statische Variable definiert. Ist das dann auch ein Singleton?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With the singleton pattern you can share properties through all instances of a class&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 Normally all properties of a class are independent of each other...&lt;br /&gt;
 */&lt;br /&gt;
class Car{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var aCar = Car()&lt;br /&gt;
aCar.color = &amp;quot;blue&amp;quot;&lt;br /&gt;
var bCar = Car()&lt;br /&gt;
// aCar is blue, bCar ist red&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With singleton pattern you create a instance of the class itself&lt;br /&gt;
 as a property of the class&lt;br /&gt;
 */&lt;br /&gt;
class Ship{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
    static let singletonShip = Ship()&lt;br /&gt;
}&lt;br /&gt;
var aShip = Ship.singletonShip&lt;br /&gt;
var bShip = Ship.singletonShip&lt;br /&gt;
// now aShip and bShip hold a reference to the SAME object&lt;br /&gt;
bShip.color = &amp;quot;pink&amp;quot;&lt;br /&gt;
print(aShip.color) // pink&lt;br /&gt;
print(bShip.color) // pink&lt;br /&gt;
&lt;br /&gt;
// Singletons are used in Swift ie&lt;br /&gt;
// UserDefaults.defaults&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_static_vars&amp;diff=26727</id>
		<title>Swift - static vars</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_static_vars&amp;diff=26727"/>
		<updated>2023-01-31T17:15:21Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
 [[Swift - Singleton Pattern]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
In Swift kann man eine Klasse oder Struktur mit einer statischen Variablen definieren. &lt;br /&gt;
&lt;br /&gt;
* Der Wert einer static var hat ist &amp;#039;&amp;#039;&amp;#039;für alle Instanzen einer Klasse oder Struktur gleich.&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
* Dies bedeutet, der Wert wird nur einmal initialisiert wird und bleibt &amp;#039;&amp;#039;&amp;#039;für die gesamte Lebensdauer der Anwendung erhalten&amp;#039;&amp;#039;&amp;#039;. Selbst wenn keine Instanz mehr vorhanden ist.&lt;br /&gt;
* Der Wert wird nicht über eine Instanz sondern über die Klasse selbst gelesen oder gesetzt.&lt;br /&gt;
* Um eine static var zu definieren, kann man das Schlüsselwort static vor einer normalen Variablendeklaration verwenden. Hier &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    static var sharedValue = 0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um auf den Wert einer static var zuzugreifen, kann man den Klassennamen und den Variablennamen verwenden. Hier ist ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
MyClass.sharedValue = 10&lt;br /&gt;
print(MyClass.sharedValue) // Ausgabe: 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig zu beachten, dass man eine static var nicht über eine Instanz einer Klasse oder Struktur aufrufen kann. Man muss stattdessen den Klassennamen verwenden.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_static_vars&amp;diff=26726</id>
		<title>Swift - static vars</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_static_vars&amp;diff=26726"/>
		<updated>2023-01-31T17:14:15Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „In Swift kann man eine Klasse oder Struktur mit einer statischen Variablen definieren.   * Der Wert einer static var hat ist &amp;#039;&amp;#039;&amp;#039;für alle Instanzen einer Klass…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In Swift kann man eine Klasse oder Struktur mit einer statischen Variablen definieren. &lt;br /&gt;
&lt;br /&gt;
* Der Wert einer static var hat ist &amp;#039;&amp;#039;&amp;#039;für alle Instanzen einer Klasse oder Struktur gleich.&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
* Dies bedeutet, der Wert wird nur einmal initialisiert wird und bleibt &amp;#039;&amp;#039;&amp;#039;für die gesamte Lebensdauer der Anwendung erhalten&amp;#039;&amp;#039;&amp;#039;. Selbst wenn keine Instanz mehr vorhanden ist.&lt;br /&gt;
* Der Wert wird nicht über eine Instanz sondern über die Klasse selbst gelesen oder gesetzt.&lt;br /&gt;
* Um eine static var zu definieren, kann man das Schlüsselwort static vor einer normalen Variablendeklaration verwenden. Hier &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    static var sharedValue = 0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um auf den Wert einer static var zuzugreifen, kann man den Klassennamen und den Variablennamen verwenden. Hier ist ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
MyClass.sharedValue = 10&lt;br /&gt;
print(MyClass.sharedValue) // Ausgabe: 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig zu beachten, dass man eine static var nicht über eine Instanz einer Klasse oder Struktur aufrufen kann. Man muss stattdessen den Klassennamen verwenden.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_(Programmiersprache)&amp;diff=26725</id>
		<title>Swift (Programmiersprache)</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_(Programmiersprache)&amp;diff=26725"/>
		<updated>2023-01-31T17:04:37Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Funktionen und Eigenschaften */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Programmiersprache im Einsatz in der Apple Welt (MacOs, iOS, WatchOs...)&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[SwiftUI]]&lt;br /&gt;
 https://www.swift.org/ - Dokumentation einfacher Verständlich als die offizielle von Apple&lt;br /&gt;
 https://iosref.com/ - Cheatsheets, Statistiken zu OS Verbreitung und mehr&lt;br /&gt;
&lt;br /&gt;
== Konzepte ==&lt;br /&gt;
=== Einfache Datentypen ===&lt;br /&gt;
 [[Swift - Strings]]&lt;br /&gt;
 [[Swift - Arrays]]&lt;br /&gt;
 [[Swift - Optionals]]&lt;br /&gt;
 [[Swift - Tuples]]&lt;br /&gt;
&lt;br /&gt;
=== Collection Datatypes und komplexe Datentypen ===&lt;br /&gt;
 [[Swift - Dictionaries]]&lt;br /&gt;
 [[Swift - Structures (Struct)]]&lt;br /&gt;
 [[Swift - Classes]]&lt;br /&gt;
&lt;br /&gt;
=== Funktionen und Eigenschaften ===&lt;br /&gt;
 [[Swift - Closures]]&lt;br /&gt;
 [[Swift - Computed Properties]]&lt;br /&gt;
 [[Swift - Internal &amp;amp; External Parameter Names]]&lt;br /&gt;
 [[Swift - weak &amp;amp; strong vars]]&lt;br /&gt;
 [[Swift - static vars]]&lt;br /&gt;
 [[Swift - @state vars]] (nur SwiftUI)&lt;br /&gt;
&lt;br /&gt;
==== Auswahl wichtiger Funktionen ====&lt;br /&gt;
 [[Swift - map/reduce/filter]]&lt;br /&gt;
&lt;br /&gt;
=== Extensions ===&lt;br /&gt;
 [[Swift - Extension]]&lt;br /&gt;
&lt;br /&gt;
== Loops == &lt;br /&gt;
 [[Swift Loops &amp;amp; Animations]]&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
=== URLSession for Networking ===&lt;br /&gt;
 [[Swift - URLSession]]&lt;br /&gt;
&lt;br /&gt;
== Snippets ==&lt;br /&gt;
 [[Swift - Snippets]]&lt;br /&gt;
&lt;br /&gt;
== Frameworks ==&lt;br /&gt;
=== Building a Swift Framework ===&lt;br /&gt;
 [[Building a Swift Framework]]&lt;br /&gt;
&lt;br /&gt;
=== UIKit ===&lt;br /&gt;
UIKit stellt die meisten der gängigen iOS Bedienelemente bereit und ist das wichtigste Modul, wenn es um die Erstellung von iOS Apps geht.&lt;br /&gt;
 [[UIKit Framework]]&lt;br /&gt;
&lt;br /&gt;
=== Cocoapods Dependency Manager ===&lt;br /&gt;
 [http://cocoapods.org cocoapods.org]&lt;br /&gt;
 [[Cocoapods]]&lt;br /&gt;
Cocoapods ein Dependency Manager für Swift and Objective-C Cocoa Projekte. Es gibt hier für viele Zwecke freien Code von Programmierern. Über den Dependency Manager kann man dafür sorgen, dass man stets die aktuelle Version in seinen Projekten hat.&lt;br /&gt;
&lt;br /&gt;
=== Google Firebase ===&lt;br /&gt;
Development platform für Apps, Spiele und Anbindung an Google Dienstleistungen.&lt;br /&gt;
 https://firebase.google.com&amp;amp;&lt;br /&gt;
 [[Swift &amp;amp; Firebase]]&lt;br /&gt;
&lt;br /&gt;
== Assets ==&lt;br /&gt;
=== Dark Mode / Light Mode ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;System Colors&amp;#039;&amp;#039;&amp;#039; verwenden oder &amp;#039;&amp;#039;&amp;#039;Color Sets&amp;#039;&amp;#039;&amp;#039; in den Assets anlegen.&lt;br /&gt;
&lt;br /&gt;
Bilder können ebenfalls mehrere Versionen für Light und Dark bereitgestellt werden.&lt;br /&gt;
 Appearances &amp;gt; Any, Light, Dark&lt;br /&gt;
&lt;br /&gt;
=== Vektor Assets ===&lt;br /&gt;
 Resizing &amp;gt; Preserve Vector Data&lt;br /&gt;
 Scales &amp;gt; Single Scale (es wird nur eine Version benötigt)&lt;br /&gt;
&lt;br /&gt;
=== Custom Assets ===&lt;br /&gt;
 Todo&lt;br /&gt;
&lt;br /&gt;
== Protocols &amp;amp; Delegates ==&lt;br /&gt;
 [[Swift - Protocols]]&lt;br /&gt;
 [[Swift - Decodable &amp;amp; Encodable]]&lt;br /&gt;
 [[Swift - Delegate]]&lt;br /&gt;
&lt;br /&gt;
== Daten speichern ==&lt;br /&gt;
 [[Swift - Möglichkeiten Daten zu speichern]]&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
 [[Swift - Error Handling]]&lt;br /&gt;
&lt;br /&gt;
== Swift - Audio ==&lt;br /&gt;
 [[Swift - Audio Playback]]&lt;br /&gt;
 [[AVAudioPlayerNode]] - geeignet für zeitkritisches Timing&lt;br /&gt;
&lt;br /&gt;
== Swift - Location Data ==&lt;br /&gt;
 [[Swift - CoreLocation]]&lt;br /&gt;
&lt;br /&gt;
== Xcode ==&lt;br /&gt;
 [[Xcode - Tipps &amp;amp; Tricks]]&lt;br /&gt;
&lt;br /&gt;
== Best Practices ==&lt;br /&gt;
=== Constants File ===&lt;br /&gt;
 [[Swift - Constants File]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26724</id>
		<title>Swift - Singleton Pattern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Singleton_Pattern&amp;diff=26724"/>
		<updated>2023-01-31T17:00:49Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Singletons sind Eigenschaften einer Klasse, die in allen Instanzen der Klasse gleich sind. Wenn man den Wert in einer Instanz ändert, sind auch alle anderen Instanzen betroffen. &lt;br /&gt;
&lt;br /&gt;
Daher kann man sie nutzen, wenn man über alle Instanzen immer auf den gleichen Wert zugreifen will, egal wo sich die Instanz befindet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With the singleton pattern you can share properties through all instances of a class&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 Normally all properties of a class are independent of each other...&lt;br /&gt;
 */&lt;br /&gt;
class Car{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var aCar = Car()&lt;br /&gt;
aCar.color = &amp;quot;blue&amp;quot;&lt;br /&gt;
var bCar = Car()&lt;br /&gt;
// aCar is blue, bCar ist red&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 With singleton pattern you create a instance of the class itself&lt;br /&gt;
 as a property of the class&lt;br /&gt;
 */&lt;br /&gt;
class Ship{&lt;br /&gt;
    var color = &amp;quot;red&amp;quot;&lt;br /&gt;
    static let singletonShip = Ship()&lt;br /&gt;
}&lt;br /&gt;
var aShip = Ship.singletonShip&lt;br /&gt;
var bShip = Ship.singletonShip&lt;br /&gt;
// now aShip and bShip hold a reference to the SAME object&lt;br /&gt;
bShip.color = &amp;quot;pink&amp;quot;&lt;br /&gt;
print(aShip.color) // pink&lt;br /&gt;
print(bShip.color) // pink&lt;br /&gt;
&lt;br /&gt;
// Singletons are used in Swift ie&lt;br /&gt;
// UserDefaults.defaults&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26723</id>
		<title>PrivacyWire - ProcessWire Modul</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26723"/>
		<updated>2023-01-30T14:30:03Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* CSS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Modul zum Anzeigen eines Cookie Banners und zum Blockieren von Skripten, Externen Medien etc. Das Modul passt das HTML an&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://processwire.com/modules/privacy-wire/&lt;br /&gt;
 https://processwire.com/talk/topic/23118-privacywire-cookie-management-async-external-asset-loading/&lt;br /&gt;
&lt;br /&gt;
== Quickstart Cookie Consent für ProcessWire ==&lt;br /&gt;
* Modul installieren (PrivacyWire)&lt;br /&gt;
* Labels übersetzen&lt;br /&gt;
* Benötigte Ketegorien auswählen&lt;br /&gt;
** Zuordnung der Kategorien funktioniert über data-category Attribut.&lt;br /&gt;
* Skripte anpassen&lt;br /&gt;
** type bei skripten mit text/plain (wird bei consent durch javascript ersetzt)&lt;br /&gt;
** src durch data-src ersetzen&lt;br /&gt;
** data-category hinzufügen&lt;br /&gt;
** Normale Skripte: type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&lt;br /&gt;
** Externe Skripte: data-src=&amp;quot;...&amp;quot;&lt;br /&gt;
Beispiele:&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;statistics&amp;quot; data-src=&amp;quot;/path/to/your/statistic/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;/path/to/your/marketing/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;external_media&amp;quot; data-src=&amp;quot;/path/to/your/external-media/script.js&amp;quot;&amp;gt;  &amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;console.log(&amp;quot;Inline scripts are also working!&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!-- Global site tag (gtag.js) - Google Analytics --&amp;gt;&lt;br /&gt;
&amp;lt;script async type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=G-DQPX4V13MY&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;&lt;br /&gt;
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag(&amp;#039;js&amp;#039;, new Date());gtag(&amp;#039;config&amp;#039;, &amp;#039;G-DQPX4V13MY&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Cookie Options anzeigen ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[privacywire-choose-cookies]] - Mit Textformatter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/a&amp;gt; - als Link&lt;br /&gt;
&amp;lt;button class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/button&amp;gt;  - als Button&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{&lt;br /&gt;
	background-color: #009999 !important;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
	color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{ &lt;br /&gt;
	background-color: #0e71b1 !important;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
	color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button{&lt;br /&gt;
    cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
.privacywire input{&lt;br /&gt;
    position: relative;&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
	margin-right: 0.5em;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
.privacywire label{&lt;br /&gt;
    color: #fff;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Betonter Accept Button:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{ &lt;br /&gt;
	background-color: #0e71b1 !important;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
	color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button{&lt;br /&gt;
    cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
.privacywire input{&lt;br /&gt;
    position: relative;&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
	margin-right: 0.5em;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
.privacywire label{&lt;br /&gt;
    color: #fff;;&lt;br /&gt;
}&lt;br /&gt;
.privacywire-page-links{&lt;br /&gt;
    margin-top: 0.5rem;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button{&lt;br /&gt;
    background: #b3b3b3;&lt;br /&gt;
	color: white;&lt;br /&gt;
	font-weight: normal;&lt;br /&gt;
	border: none;&lt;br /&gt;
	padding: 4px;&lt;br /&gt;
	border-radius: 4px;&lt;br /&gt;
}&lt;br /&gt;
.privacywire button.allow-all{&lt;br /&gt;
	background: #2dd02d;&lt;br /&gt;
	border-color: #2dd02d;&lt;br /&gt;
    color: white;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Video Embed Opt-In==&lt;br /&gt;
Im VideoEmbed Plugin kann man die Kategorie auswählen (z.B. external Media)&lt;br /&gt;
&lt;br /&gt;
== Bsp. iFrame mit eigenem Opt Out ==&lt;br /&gt;
Mit dem Attribut data-ask-consent=&amp;quot;1&amp;quot; kann man auch einzelne Elemente freigeben.&lt;br /&gt;
 &amp;lt;iframe data-src=&amp;quot;https://processwire.com/&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-ask-consent=&amp;quot;1&amp;quot; class=&amp;quot;require-consent&amp;quot; frameborder=&amp;quot;0&amp;quot; height=&amp;quot;400&amp;quot; width=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available attributes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Attribute	Info	Description	Type&lt;br /&gt;
class require-consent	optional (required if config option enabled)	If the config option &amp;quot;Detect consent windows by class require-consent instead of data-attribute&amp;quot; is enabled	string&lt;br /&gt;
data-category	required	defines the assigned cookie group for this element	string&lt;br /&gt;
data-type	optional (required for scripts)	replaces the type attribute after giving consent	string&lt;br /&gt;
data-src	optional (required for external scripts, images or iframes)	replaces the src attribute after giving consent	string&lt;br /&gt;
data-srset	optional	replaces the srcset attribute for images after giving consent	string&lt;br /&gt;
data-ask-consent	optional	Replace element with Opt-In-Element	bool 0/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For script tags it is required to add type=&amp;quot;text/plain&amp;quot;, otherwise the script executes directly.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26722</id>
		<title>PrivacyWire - ProcessWire Modul</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26722"/>
		<updated>2023-01-30T13:39:14Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Quickstart Cookie Consent für ProcessWire */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Modul zum Anzeigen eines Cookie Banners und zum Blockieren von Skripten, Externen Medien etc. Das Modul passt das HTML an&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://processwire.com/modules/privacy-wire/&lt;br /&gt;
 https://processwire.com/talk/topic/23118-privacywire-cookie-management-async-external-asset-loading/&lt;br /&gt;
&lt;br /&gt;
== Quickstart Cookie Consent für ProcessWire ==&lt;br /&gt;
* Modul installieren (PrivacyWire)&lt;br /&gt;
* Labels übersetzen&lt;br /&gt;
* Benötigte Ketegorien auswählen&lt;br /&gt;
** Zuordnung der Kategorien funktioniert über data-category Attribut.&lt;br /&gt;
* Skripte anpassen&lt;br /&gt;
** type bei skripten mit text/plain (wird bei consent durch javascript ersetzt)&lt;br /&gt;
** src durch data-src ersetzen&lt;br /&gt;
** data-category hinzufügen&lt;br /&gt;
** Normale Skripte: type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&lt;br /&gt;
** Externe Skripte: data-src=&amp;quot;...&amp;quot;&lt;br /&gt;
Beispiele:&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;statistics&amp;quot; data-src=&amp;quot;/path/to/your/statistic/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;/path/to/your/marketing/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;external_media&amp;quot; data-src=&amp;quot;/path/to/your/external-media/script.js&amp;quot;&amp;gt;  &amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;console.log(&amp;quot;Inline scripts are also working!&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!-- Global site tag (gtag.js) - Google Analytics --&amp;gt;&lt;br /&gt;
&amp;lt;script async type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=G-DQPX4V13MY&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;&lt;br /&gt;
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag(&amp;#039;js&amp;#039;, new Date());gtag(&amp;#039;config&amp;#039;, &amp;#039;G-DQPX4V13MY&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Cookie Options anzeigen ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[privacywire-choose-cookies]] - Mit Textformatter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/a&amp;gt; - als Link&lt;br /&gt;
&amp;lt;button class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/button&amp;gt;  - als Button&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{&lt;br /&gt;
	background-color: #009999 !important;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
	color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Video Embed Opt-In==&lt;br /&gt;
Im VideoEmbed Plugin kann man die Kategorie auswählen (z.B. external Media)&lt;br /&gt;
&lt;br /&gt;
== Bsp. iFrame mit eigenem Opt Out ==&lt;br /&gt;
Mit dem Attribut data-ask-consent=&amp;quot;1&amp;quot; kann man auch einzelne Elemente freigeben.&lt;br /&gt;
 &amp;lt;iframe data-src=&amp;quot;https://processwire.com/&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-ask-consent=&amp;quot;1&amp;quot; class=&amp;quot;require-consent&amp;quot; frameborder=&amp;quot;0&amp;quot; height=&amp;quot;400&amp;quot; width=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available attributes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Attribute	Info	Description	Type&lt;br /&gt;
class require-consent	optional (required if config option enabled)	If the config option &amp;quot;Detect consent windows by class require-consent instead of data-attribute&amp;quot; is enabled	string&lt;br /&gt;
data-category	required	defines the assigned cookie group for this element	string&lt;br /&gt;
data-type	optional (required for scripts)	replaces the type attribute after giving consent	string&lt;br /&gt;
data-src	optional (required for external scripts, images or iframes)	replaces the src attribute after giving consent	string&lt;br /&gt;
data-srset	optional	replaces the srcset attribute for images after giving consent	string&lt;br /&gt;
data-ask-consent	optional	Replace element with Opt-In-Element	bool 0/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For script tags it is required to add type=&amp;quot;text/plain&amp;quot;, otherwise the script executes directly.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26721</id>
		<title>PrivacyWire - ProcessWire Modul</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=PrivacyWire_-_ProcessWire_Modul&amp;diff=26721"/>
		<updated>2023-01-30T13:36:54Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Modul zum Anzeigen eines Cookie Banners und zum Blockieren von Skripten, Externen Medien etc. Das Modul passt das HTML an&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://processwire.com/modules/privacy-wire/&lt;br /&gt;
 https://processwire.com/talk/topic/23118-privacywire-cookie-management-async-external-asset-loading/&lt;br /&gt;
&lt;br /&gt;
== Quickstart Cookie Consent für ProcessWire ==&lt;br /&gt;
* Modul installieren (PrivacyWire)&lt;br /&gt;
* Labels übersetzen&lt;br /&gt;
* Benötigte Ketegorien auswählen&lt;br /&gt;
** Zuordnung der Kategorien funktioniert über data-category Attribut.&lt;br /&gt;
* Skripte anpassen z.B.&lt;br /&gt;
** Normale Skripte: type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&lt;br /&gt;
** Externe Skripte: data-src=&amp;quot;...&amp;quot;&lt;br /&gt;
Beispiele:&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;statistics&amp;quot; data-src=&amp;quot;/path/to/your/statistic/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;/path/to/your/marketing/script.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;external_media&amp;quot; data-src=&amp;quot;/path/to/your/external-media/script.js&amp;quot;&amp;gt;  &amp;lt;/script&amp;gt;&lt;br /&gt;
 &amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;console.log(&amp;quot;Inline scripts are also working!&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!-- Global site tag (gtag.js) - Google Analytics --&amp;gt;&lt;br /&gt;
&amp;lt;script async type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-src=&amp;quot;https://www.googletagmanager.com/gtag/js?id=G-DQPX4V13MY&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/plain&amp;quot; data-type=&amp;quot;text/javascript&amp;quot; data-category=&amp;quot;marketing&amp;quot;&amp;gt;&lt;br /&gt;
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag(&amp;#039;js&amp;#039;, new Date());gtag(&amp;#039;config&amp;#039;, &amp;#039;G-DQPX4V13MY&amp;#039;);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Cookie Options anzeigen ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[privacywire-choose-cookies]] - Mit Textformatter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/a&amp;gt; - als Link&lt;br /&gt;
&amp;lt;button class=&amp;quot;privacywire-show-options&amp;quot;&amp;gt;Show Cookie Options&amp;lt;/button&amp;gt;  - als Button&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.pricacywire,&lt;br /&gt;
.privacywire-banner,&lt;br /&gt;
.privacywire-options,&lt;br /&gt;
.privacywire-message{&lt;br /&gt;
	background-color: #009999 !important;&lt;br /&gt;
}&lt;br /&gt;
.pricacywire a,&lt;br /&gt;
.privacywire-banner a,&lt;br /&gt;
.privacywire-options a{&lt;br /&gt;
	color: #fff !important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Video Embed Opt-In==&lt;br /&gt;
Im VideoEmbed Plugin kann man die Kategorie auswählen (z.B. external Media)&lt;br /&gt;
&lt;br /&gt;
== Bsp. iFrame mit eigenem Opt Out ==&lt;br /&gt;
Mit dem Attribut data-ask-consent=&amp;quot;1&amp;quot; kann man auch einzelne Elemente freigeben.&lt;br /&gt;
 &amp;lt;iframe data-src=&amp;quot;https://processwire.com/&amp;quot; data-category=&amp;quot;marketing&amp;quot; data-ask-consent=&amp;quot;1&amp;quot; class=&amp;quot;require-consent&amp;quot; frameborder=&amp;quot;0&amp;quot; height=&amp;quot;400&amp;quot; width=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available attributes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Attribute	Info	Description	Type&lt;br /&gt;
class require-consent	optional (required if config option enabled)	If the config option &amp;quot;Detect consent windows by class require-consent instead of data-attribute&amp;quot; is enabled	string&lt;br /&gt;
data-category	required	defines the assigned cookie group for this element	string&lt;br /&gt;
data-type	optional (required for scripts)	replaces the type attribute after giving consent	string&lt;br /&gt;
data-src	optional (required for external scripts, images or iframes)	replaces the src attribute after giving consent	string&lt;br /&gt;
data-srset	optional	replaces the srcset attribute for images after giving consent	string&lt;br /&gt;
data-ask-consent	optional	Replace element with Opt-In-Element	bool 0/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For script tags it is required to add type=&amp;quot;text/plain&amp;quot;, otherwise the script executes directly.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26720</id>
		<title>Swift - Audio Playback</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26720"/>
		<updated>2023-01-28T11:09:25Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Audio in background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
 [[Swift - Play a Sound]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt untschiedliche Möglichkeiten Audio abzuspielen je nachdem was man möchte.&lt;br /&gt;
&lt;br /&gt;
Jede Möglichkeit ist unterschiedlich aufwändig. Es gibt außerdem Klassen um den Systemmixer zu steuern oder das Verhalten wenn die App in den Hintergrund geht zu beeinflussen.&lt;br /&gt;
&lt;br /&gt;
== Glossar ==&lt;br /&gt;
=== AVFoundation ===&lt;br /&gt;
==== AVAudioSession ====&lt;br /&gt;
AVAudioSession ist ein Singleton-Objekt, das die Audio-Sitzung für Ihre App verwaltet. Es ist verantwortlich für die &amp;#039;&amp;#039;&amp;#039;Konfiguration der Audio-Routen&amp;#039;&amp;#039;&amp;#039;, wie dem Ausgabegerät (z.B. Lautsprecher oder Headset) und für die Verwaltung des Zustands der Audio-Sitzung (z.B. aktiv oder inaktiv). AVAudioSession bietet auch Methoden zur Steuerung der &amp;#039;&amp;#039;&amp;#039;Eigenschaften der Audio-Sitzung&amp;#039;&amp;#039;&amp;#039;, wie der Lautstärke und der Audio-Kategorie.&lt;br /&gt;
&lt;br /&gt;
==== AVAudioPlayerNode ====&lt;br /&gt;
AVAudioPlayerNode wird verwendet, um &amp;#039;&amp;#039;&amp;#039;Audio-Puffer und -Dateien&amp;#039;&amp;#039;&amp;#039; innerhalb eines AVAudioEngine-Graphen &amp;#039;&amp;#039;&amp;#039;abzuspielen&amp;#039;&amp;#039;&amp;#039;. Es kann verwendet werden, um das Abspielen von Audio-Puffern und -Dateien zu planen, die Wiedergabegeschwindigkeit, den Pan und die Lautstärke zu ändern und einen Rückruf bereitzustellen, wenn die Wiedergabe abgeschlossen ist.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Zusammengefasst wird AVAudioSession verwendet, um die Gesamt-Audio-Sitzung für Ihre App zu konfigurieren, während AVAudioPlayerNode verwendet wird, um spezifische Audio-Puffer und -Dateien innerhalb dieser Sitzung abzuspielen.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Audio im Hintergrund abspielen ==&lt;br /&gt;
App für Hintergrundplayback konfigurieren&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;In Info.plist&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;dict&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &amp;lt;key&amp;gt;UIBackgroundModes&amp;lt;/key&amp;gt;&lt;br /&gt;
    &amp;lt;array&amp;gt;&lt;br /&gt;
        &amp;lt;string&amp;gt;audio&amp;lt;/string&amp;gt;&lt;br /&gt;
    &amp;lt;/array&amp;gt;&lt;br /&gt;
&amp;lt;/dict&amp;gt;&lt;br /&gt;
&amp;lt;/plist&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mit AVAudioPlayer ===&lt;br /&gt;
Wenn du die AVAudioPlayer Klasse nutzt stelle die  &amp;#039;&amp;#039;&amp;#039;numberOfLoops property to -1&amp;#039;&amp;#039;&amp;#039; so that the audio will play indefinitely.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
audioPlayer.numberOfLoops = -1&lt;br /&gt;
audioPlayer.play()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Außerdem mußt du in der AVAudioSession die &amp;#039;&amp;#039;&amp;#039;korrekte Kategorie&amp;#039;&amp;#039;&amp;#039; setzen. Die Kategorie legt z.B. fest wie mit welcher Priorität Background Audio behandelt wird, falls ein Anfruf reinkommt etc. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt außerdem auch eine &amp;#039;&amp;#039;&amp;#039;maximale Dauer die das System für Background Audio erlaubt&amp;#039;&amp;#039;&amp;#039;. Die genaue Zeit hängt von verschiedenen Faktoren ab. Unter anderem welche Ressourcen die App benötigt und auf welche Art Audio abgespielt wird. Wenn die App vom System beendet wird ist natürlich Schluss mit Ton.&lt;br /&gt;
&lt;br /&gt;
=== Mit AVAudioEngine ===&lt;br /&gt;
Hier ist das Vorgehen ähnlich - auch hier musst du die AVAudioSession richtig konfigurieren:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
        // Audio session should play in background&lt;br /&gt;
        let audioSession = AVAudioSession.sharedInstance()&lt;br /&gt;
        do {&lt;br /&gt;
            try audioSession.setCategory(.playback)&lt;br /&gt;
            // try AVAudioSession.sharedInstance().setActive(true) // neeeded?&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(&amp;quot;Setting category to AVAudioSessionCategory .playback failed.&amp;quot;)&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Evtl. muss man die Session noch aktivieren. Aber bei meinen Tests war das nicht nötig. Sie wurde automatisch (wahrscheinlich über die AudioEngine) aktiviert (siehe Kommentar im Code.&lt;br /&gt;
&lt;br /&gt;
=== Allgemeine Tipps für Apps im Background ===&lt;br /&gt;
However, you can help the system to save energy by following some best practices:&lt;br /&gt;
&lt;br /&gt;
    Minimize the use of location services, push notifications, and background tasks when your app is not in use.&lt;br /&gt;
    Use the beginBackgroundTaskWithExpirationHandler method to execute any critical tasks before your app is suspended.&lt;br /&gt;
    Avoid using CPU-intensive tasks when your app is in the background, as this can drain the battery.&lt;br /&gt;
    When your app is not in use, release any resources that are not needed, such as images and sounds.&lt;br /&gt;
&lt;br /&gt;
By following these practices, your app will be less likely to consume excessive power and will provide a better user experience by not draining the battery.&lt;br /&gt;
&lt;br /&gt;
It is also possible to suggest to the user to close the app when it&amp;#039;s not in use, or to use low power mode in the settings.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that, as a developer, you don&amp;#039;t have the power to force the app to go to background or to shut down, but by following best practices you can help the system to save energy.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26719</id>
		<title>Swift - Audio Playback</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26719"/>
		<updated>2023-01-28T10:51:01Z</updated>

		<summary type="html">&lt;p&gt;Steff: v1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
 [[Swift - Play a Sound]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt untschiedliche Möglichkeiten Audio abzuspielen je nachdem was man möchte.&lt;br /&gt;
&lt;br /&gt;
Jede Möglichkeit ist unterschiedlich aufwändig. Es gibt außerdem Klassen um den Systemmixer zu steuern oder das Verhalten wenn die App in den Hintergrund geht zu beeinflussen.&lt;br /&gt;
&lt;br /&gt;
== Glossar ==&lt;br /&gt;
=== AVFoundation ===&lt;br /&gt;
==== AVAudioSession ====&lt;br /&gt;
AVAudioSession ist ein Singleton-Objekt, das die Audio-Sitzung für Ihre App verwaltet. Es ist verantwortlich für die &amp;#039;&amp;#039;&amp;#039;Konfiguration der Audio-Routen&amp;#039;&amp;#039;&amp;#039;, wie dem Ausgabegerät (z.B. Lautsprecher oder Headset) und für die Verwaltung des Zustands der Audio-Sitzung (z.B. aktiv oder inaktiv). AVAudioSession bietet auch Methoden zur Steuerung der &amp;#039;&amp;#039;&amp;#039;Eigenschaften der Audio-Sitzung&amp;#039;&amp;#039;&amp;#039;, wie der Lautstärke und der Audio-Kategorie.&lt;br /&gt;
&lt;br /&gt;
==== AVAudioPlayerNode ====&lt;br /&gt;
AVAudioPlayerNode wird verwendet, um &amp;#039;&amp;#039;&amp;#039;Audio-Puffer und -Dateien&amp;#039;&amp;#039;&amp;#039; innerhalb eines AVAudioEngine-Graphen &amp;#039;&amp;#039;&amp;#039;abzuspielen&amp;#039;&amp;#039;&amp;#039;. Es kann verwendet werden, um das Abspielen von Audio-Puffern und -Dateien zu planen, die Wiedergabegeschwindigkeit, den Pan und die Lautstärke zu ändern und einen Rückruf bereitzustellen, wenn die Wiedergabe abgeschlossen ist.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Zusammengefasst wird AVAudioSession verwendet, um die Gesamt-Audio-Sitzung für Ihre App zu konfigurieren, während AVAudioPlayerNode verwendet wird, um spezifische Audio-Puffer und -Dateien innerhalb dieser Sitzung abzuspielen.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Audio in background ==&lt;br /&gt;
App für Hintergrundplayback konfigurieren&lt;br /&gt;
In Info.plist&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;dict&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &amp;lt;key&amp;gt;UIBackgroundModes&amp;lt;/key&amp;gt;&lt;br /&gt;
    &amp;lt;array&amp;gt;&lt;br /&gt;
        &amp;lt;string&amp;gt;audio&amp;lt;/string&amp;gt;&lt;br /&gt;
    &amp;lt;/array&amp;gt;&lt;br /&gt;
&amp;lt;/dict&amp;gt;&lt;br /&gt;
&amp;lt;/plist&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26718</id>
		<title>Swift - Audio Playback</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26718"/>
		<updated>2023-01-28T10:40:11Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
 [[Swift - Play a Sound]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt untschiedliche Möglichkeiten Audio abzuspielen je nachdem was man möchte.&lt;br /&gt;
&lt;br /&gt;
Jede Möglichkeit ist unterschiedlich aufwändig. Es gibt außerdem Klassen um den Systemmixer zu steuern oder das Verhalten wenn die App in den Hintergrund geht zu beeinflussen.&lt;br /&gt;
&lt;br /&gt;
== Glossar ==&lt;br /&gt;
=== AVFoundation ===&lt;br /&gt;
==== AVAudioSession ====&lt;br /&gt;
AVAudioSession ist ein Singleton-Objekt, das die Audio-Sitzung für Ihre App verwaltet. Es ist verantwortlich für die &amp;#039;&amp;#039;&amp;#039;Konfiguration der Audio-Routen&amp;#039;&amp;#039;&amp;#039;, wie dem Ausgabegerät (z.B. Lautsprecher oder Headset) und für die Verwaltung des Zustands der Audio-Sitzung (z.B. aktiv oder inaktiv). AVAudioSession bietet auch Methoden zur Steuerung der &amp;#039;&amp;#039;&amp;#039;Eigenschaften der Audio-Sitzung&amp;#039;&amp;#039;&amp;#039;, wie der Lautstärke und der Audio-Kategorie.&lt;br /&gt;
&lt;br /&gt;
==== AVAudioPlayerNode ====&lt;br /&gt;
AVAudioPlayerNode wird verwendet, um &amp;#039;&amp;#039;&amp;#039;Audio-Puffer und -Dateien&amp;#039;&amp;#039;&amp;#039; innerhalb eines AVAudioEngine-Graphen &amp;#039;&amp;#039;&amp;#039;abzuspielen&amp;#039;&amp;#039;&amp;#039;. Es kann verwendet werden, um das Abspielen von Audio-Puffern und -Dateien zu planen, die Wiedergabegeschwindigkeit, den Pan und die Lautstärke zu ändern und einen Rückruf bereitzustellen, wenn die Wiedergabe abgeschlossen ist.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Zusammengefasst wird AVAudioSession verwendet, um die Gesamt-Audio-Sitzung für Ihre App zu konfigurieren, während AVAudioPlayerNode verwendet wird, um spezifische Audio-Puffer und -Dateien innerhalb dieser Sitzung abzuspielen.&amp;#039;&amp;#039;&amp;#039;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26717</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26717"/>
		<updated>2023-01-28T10:37:24Z</updated>

		<summary type="html">&lt;p&gt;Steff: Einführung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Codable - File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben. Codable hilft dabei zum En- und Dekodieren von Objekten.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|800px|zentriert]]&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26716</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26716"/>
		<updated>2023-01-28T10:36:36Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Einführung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Codable - File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben. Codable hilft dabei zum En- und Dekodieren von Objekten.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|800px|zentriert]]&lt;br /&gt;
&lt;br /&gt;
[[|800px|miniatur]]&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26715</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26715"/>
		<updated>2023-01-28T10:34:26Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Einführung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|800px|zentriert]]&lt;br /&gt;
&lt;br /&gt;
[[|800px|miniatur]]&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26714</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26714"/>
		<updated>2023-01-28T10:33:08Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|rahmenlos|zentriert]]&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26713</id>
		<title>Swift - @state vars</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26713"/>
		<updated>2023-01-28T07:57:52Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Unterstützt UIView ebenfalls @state ? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Hinweis&amp;#039;&amp;#039;&amp;#039;: @state ist nicht für UIView verfügbar sondern für die View Klasse. Nicht verwechseln.&lt;br /&gt;
&lt;br /&gt;
In SwiftUI ist eine @State Variable eine Variable, die verwendet wird, &amp;#039;&amp;#039;&amp;#039;um den Zustand eines View zu speichern&amp;#039;&amp;#039;&amp;#039;. Wenn der Wert einer @State Variable sich ändert, wird die Ansicht &amp;#039;&amp;#039;&amp;#039;automatisch neu gerendert&amp;#039;&amp;#039;&amp;#039;, um den neuen Zustand widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
@State Variablen werden verwendet, um den internen Zustand eines Views zu speichern, wie z.B. den aktuellen Wert eines Textfeldes, das ausgewählte Element in einer Liste oder den auf-/zugeklappten Zustand eines Views. Sie werden auf View-Ebene definiert und können von allen Unteransichten dieses Views aufgerufen und modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Hier ist ein Beispiel dafür, wie man eine @State Variable in einer SwiftUI Ansicht verwendet:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
struct MyView: View {&lt;br /&gt;
    @State private var text = &amp;quot;Hallo Welt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    var body: some View {&lt;br /&gt;
        TextField(&amp;quot;Geben Sie Text ein&amp;quot;, text: $text)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die @State Variable text verwendet, um den aktuellen Text im TextField zu speichern. Wenn der Benutzer im Textfeld etwas eingibt, wird der Wert der text Variable aktualisiert und die Ansicht wird neu gerendert, um den neuen Wert widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig zu beachten, dass @State Eigenschaften nur innerhalb des Objekts, das es deklariert, von self modifiziert werden dürfen und auch nicht zwischen verschiedenen Ansichten geteilt werden können.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;@State Variablen ähneln @ObservedObject und @EnvironmentObject&amp;#039;&amp;#039;&amp;#039;, da sie alle den Zustand einer Ansicht speichern, aber sie haben unterschiedliche Anwendungsfälle. &amp;#039;&amp;#039;&amp;#039;@ObservedObject&amp;#039;&amp;#039;&amp;#039; wird verwendet, um den &amp;#039;&amp;#039;&amp;#039;Zustand eines Objekts zu speichern, das von mehreren Ansichten geteilt wird&amp;#039;&amp;#039;&amp;#039;, während &amp;#039;&amp;#039;&amp;#039;@EnvironmentObject&amp;#039;&amp;#039;&amp;#039; verwendet wird, um den &amp;#039;&amp;#039;&amp;#039;Zustand eines Objekts zu speichern, das im gesamten App geteilt wird.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Unterstützt UIView ebenfalls @state? ==&lt;br /&gt;
&lt;br /&gt;
Nein, @state ist ein Feature von SwiftUI und es ist spezifisch für dieses Framework und ist nicht in UIView verfügbar.&lt;br /&gt;
&lt;br /&gt;
@state ist ein Property Wrapper, der verwendet wird, um den Zustand einer Ansicht im SwiftUI-Framework zu verwalten. Es ermöglicht es Ihnen, eine Eigenschaft als den Zustand der Ansicht zu markieren und sicherzustellen, dass Änderungen an dieser Eigenschaft automatisch die Ansicht aktualisieren.&lt;br /&gt;
&lt;br /&gt;
In UIView wird der Zustand in der Regel durch Eigenschaften verwaltet und Änderungen an diesen Eigenschaften müssen manuell durch Aufru&lt;br /&gt;
dev@stephanschlegel.de&lt;br /&gt;
Kann ich View innerhalb von UIView benutzen?&lt;br /&gt;
&lt;br /&gt;
Ja, es ist möglich, SwiftUI-Ansichten innerhalb von UIViews zu verwenden. Dies kann erreicht werden, indem man einen UIViewRepresentable-Wrapper erstellt, der die SwiftUI-Ansicht in eine UIView kapselt und diese dann in die UIView-Hierarchie einbetten kann.&lt;br /&gt;
&lt;br /&gt;
Hier ist ein Beispiel, wie man eine SwiftUI-Ansicht in eine UIView einbetten kann:&lt;br /&gt;
&lt;br /&gt;
swift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
struct SwiftUIView: View {&lt;br /&gt;
    var body: some View {&lt;br /&gt;
        Text(&amp;quot;Hello, World!&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct SwiftUIViewWrapper: UIViewRepresentable {&lt;br /&gt;
    func makeUIView(context: Context) -&amp;gt; UIView {&lt;br /&gt;
        return UIView()&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    func updateUIView(_ uiView: UIView, context: Context) {&lt;br /&gt;
        let swiftUIView = SwiftUIView()&lt;br /&gt;
        let swiftUIViewController = UIHostingController(rootView: swiftUIView)&lt;br /&gt;
        swiftUIViewController.view.frame = uiView.bounds&lt;br /&gt;
        uiView.addSubview(swiftUIViewController.view)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann kann man diese WrapperView in einer UIViewController oder andere UIView Klasse nutzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
class MyViewController: UIViewController {&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
        let swiftUIViewWrapper = SwiftUIViewWrapper()&lt;br /&gt;
        view.addSubview(swiftUIViewWrapper.view)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Technik ermöglicht es Ihnen, die Vorteile von SwiftUI und UIKit zu nutzen und eine gemischte App zu erstellen.&lt;br /&gt;
&lt;br /&gt;
== Welches sind die Vorteile von SwiftUI und UIKit im Vergleich? ==&lt;br /&gt;
&lt;br /&gt;
SwiftUI und UIKit sind beide Frameworks für die Erstellung von Benutzeroberflächen auf Apple-Plattformen, aber sie haben einige Unterschiede in Bezug auf ihre Funktionalität und Verwendung.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorteile von SwiftUI:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Einfacheres und intuitiveres Design: SwiftUI bietet eine deklarative Syntax, die es Entwicklern erleichtert, die Benutzeroberfläche zu erstellen und zu verwalten. Es erfordert weniger Code, um dieselben Ergebnisse zu erzielen, und bietet eine höhere Abstraktionsebene.&lt;br /&gt;
* Plattformübergreifend: SwiftUI kann für iOS, iPadOS, macOS, watchOS und tvOS verwendet werden, was die Entwicklung von plattformübergreifenden Apps vereinfacht.&lt;br /&gt;
* Automatisierte Aktualisierungen: SwiftUI automatisiert das Aktualisieren der Ansicht, wenn sich die Daten ändern, was die Entwicklung von Apps mit dynamischen Benutzeroberflächen vereinfacht.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorteile von UIKit:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Ausgereifte und erprobte Technologie: UIKit ist das seit langem etablierte Framework für die Erstellung von Benutzeroberflächen auf Apple-Plattformen und hat eine breite Unterstützung und eine große Anzahl von Ressourcen und Dokumentationen.&lt;br /&gt;
* Erweiterbarkeit: UIKit bietet Entwicklern eine breite Palette an vordefinierten UI-Elementen und die Möglichkeit, benutzerdefinierte Steuerelemente zu erstellen, was es ermöglicht, eine breite Palette von Anforderungen an die Benutzeroberfläche zu erfüllen.&lt;br /&gt;
* Rückwärtskompatibilität: Apps, die mit UIKit erstellt wurden, sind rückwärtskompatibel mit älteren Versionen von iOS und können daher auf eine größere Anzahl von Geräten ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt also keine universelle Lösung, sondern es hängt von den Anforderungen und Zielen des Projekts ab, welches Framework am besten geeignet ist. In den meisten Fällen kann man aber mit SwiftUI schneller und einfacher eine App erstellen, aber in bestimmten Fällen ist es nötig die Möglichkeiten von UIKit zu nutzen.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26712</id>
		<title>Swift - @state vars</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26712"/>
		<updated>2023-01-28T07:57:08Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Hinweis&amp;#039;&amp;#039;&amp;#039;: @state ist nicht für UIView verfügbar sondern für die View Klasse. Nicht verwechseln.&lt;br /&gt;
&lt;br /&gt;
In SwiftUI ist eine @State Variable eine Variable, die verwendet wird, &amp;#039;&amp;#039;&amp;#039;um den Zustand eines View zu speichern&amp;#039;&amp;#039;&amp;#039;. Wenn der Wert einer @State Variable sich ändert, wird die Ansicht &amp;#039;&amp;#039;&amp;#039;automatisch neu gerendert&amp;#039;&amp;#039;&amp;#039;, um den neuen Zustand widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
@State Variablen werden verwendet, um den internen Zustand eines Views zu speichern, wie z.B. den aktuellen Wert eines Textfeldes, das ausgewählte Element in einer Liste oder den auf-/zugeklappten Zustand eines Views. Sie werden auf View-Ebene definiert und können von allen Unteransichten dieses Views aufgerufen und modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Hier ist ein Beispiel dafür, wie man eine @State Variable in einer SwiftUI Ansicht verwendet:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
struct MyView: View {&lt;br /&gt;
    @State private var text = &amp;quot;Hallo Welt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    var body: some View {&lt;br /&gt;
        TextField(&amp;quot;Geben Sie Text ein&amp;quot;, text: $text)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die @State Variable text verwendet, um den aktuellen Text im TextField zu speichern. Wenn der Benutzer im Textfeld etwas eingibt, wird der Wert der text Variable aktualisiert und die Ansicht wird neu gerendert, um den neuen Wert widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig zu beachten, dass @State Eigenschaften nur innerhalb des Objekts, das es deklariert, von self modifiziert werden dürfen und auch nicht zwischen verschiedenen Ansichten geteilt werden können.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;@State Variablen ähneln @ObservedObject und @EnvironmentObject&amp;#039;&amp;#039;&amp;#039;, da sie alle den Zustand einer Ansicht speichern, aber sie haben unterschiedliche Anwendungsfälle. &amp;#039;&amp;#039;&amp;#039;@ObservedObject&amp;#039;&amp;#039;&amp;#039; wird verwendet, um den &amp;#039;&amp;#039;&amp;#039;Zustand eines Objekts zu speichern, das von mehreren Ansichten geteilt wird&amp;#039;&amp;#039;&amp;#039;, während &amp;#039;&amp;#039;&amp;#039;@EnvironmentObject&amp;#039;&amp;#039;&amp;#039; verwendet wird, um den &amp;#039;&amp;#039;&amp;#039;Zustand eines Objekts zu speichern, das im gesamten App geteilt wird.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Unterstützt UIView ebenfalls @state ? ==&lt;br /&gt;
&lt;br /&gt;
Nein, @state ist ein Feature von SwiftUI und es ist spezifisch für dieses Framework und ist nicht in UIView verfügbar.&lt;br /&gt;
&lt;br /&gt;
@state ist ein Property Wrapper, der verwendet wird, um den Zustand einer Ansicht im SwiftUI-Framework zu verwalten. Es ermöglicht es Ihnen, eine Eigenschaft als den Zustand der Ansicht zu markieren und sicherzustellen, dass Änderungen an dieser Eigenschaft automatisch die Ansicht aktualisieren.&lt;br /&gt;
&lt;br /&gt;
In UIView wird der Zustand in der Regel durch Eigenschaften verwaltet und Änderungen an diesen Eigenschaften müssen manuell durch Aufru&lt;br /&gt;
dev@stephanschlegel.de&lt;br /&gt;
Kann ich View innerhalb von UIView benutzen?&lt;br /&gt;
&lt;br /&gt;
Ja, es ist möglich, SwiftUI-Ansichten innerhalb von UIViews zu verwenden. Dies kann erreicht werden, indem man einen UIViewRepresentable-Wrapper erstellt, der die SwiftUI-Ansicht in eine UIView kapselt und diese dann in die UIView-Hierarchie einbetten kann.&lt;br /&gt;
&lt;br /&gt;
Hier ist ein Beispiel, wie man eine SwiftUI-Ansicht in eine UIView einbetten kann:&lt;br /&gt;
&lt;br /&gt;
swift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
struct SwiftUIView: View {&lt;br /&gt;
    var body: some View {&lt;br /&gt;
        Text(&amp;quot;Hello, World!&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct SwiftUIViewWrapper: UIViewRepresentable {&lt;br /&gt;
    func makeUIView(context: Context) -&amp;gt; UIView {&lt;br /&gt;
        return UIView()&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    func updateUIView(_ uiView: UIView, context: Context) {&lt;br /&gt;
        let swiftUIView = SwiftUIView()&lt;br /&gt;
        let swiftUIViewController = UIHostingController(rootView: swiftUIView)&lt;br /&gt;
        swiftUIViewController.view.frame = uiView.bounds&lt;br /&gt;
        uiView.addSubview(swiftUIViewController.view)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dann kann man diese WrapperView in einer UIViewController oder andere UIView Klasse nutzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
class MyViewController: UIViewController {&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
        let swiftUIViewWrapper = SwiftUIViewWrapper()&lt;br /&gt;
        view.addSubview(swiftUIViewWrapper.view)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Technik ermöglicht es Ihnen, die Vorteile von SwiftUI und UIKit zu nutzen und eine gemischte App zu erstellen.&lt;br /&gt;
&lt;br /&gt;
== Welches sind die Vorteile von SwiftUI und UIKit im Vergleich? ==&lt;br /&gt;
&lt;br /&gt;
SwiftUI und UIKit sind beide Frameworks für die Erstellung von Benutzeroberflächen auf Apple-Plattformen, aber sie haben einige Unterschiede in Bezug auf ihre Funktionalität und Verwendung.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorteile von SwiftUI:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Einfacheres und intuitiveres Design: SwiftUI bietet eine deklarative Syntax, die es Entwicklern erleichtert, die Benutzeroberfläche zu erstellen und zu verwalten. Es erfordert weniger Code, um dieselben Ergebnisse zu erzielen, und bietet eine höhere Abstraktionsebene.&lt;br /&gt;
* Plattformübergreifend: SwiftUI kann für iOS, iPadOS, macOS, watchOS und tvOS verwendet werden, was die Entwicklung von plattformübergreifenden Apps vereinfacht.&lt;br /&gt;
* Automatisierte Aktualisierungen: SwiftUI automatisiert das Aktualisieren der Ansicht, wenn sich die Daten ändern, was die Entwicklung von Apps mit dynamischen Benutzeroberflächen vereinfacht.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorteile von UIKit:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Ausgereifte und erprobte Technologie: UIKit ist das seit langem etablierte Framework für die Erstellung von Benutzeroberflächen auf Apple-Plattformen und hat eine breite Unterstützung und eine große Anzahl von Ressourcen und Dokumentationen.&lt;br /&gt;
* Erweiterbarkeit: UIKit bietet Entwicklern eine breite Palette an vordefinierten UI-Elementen und die Möglichkeit, benutzerdefinierte Steuerelemente zu erstellen, was es ermöglicht, eine breite Palette von Anforderungen an die Benutzeroberfläche zu erfüllen.&lt;br /&gt;
* Rückwärtskompatibilität: Apps, die mit UIKit erstellt wurden, sind rückwärtskompatibel mit älteren Versionen von iOS und können daher auf eine größere Anzahl von Geräten ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt also keine universelle Lösung, sondern es hängt von den Anforderungen und Zielen des Projekts ab, welches Framework am besten geeignet ist. In den meisten Fällen kann man aber mit SwiftUI schneller und einfacher eine App erstellen, aber in bestimmten Fällen ist es nötig die Möglichkeiten von UIKit zu nutzen.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26711</id>
		<title>Swift - @state vars</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_@state_vars&amp;diff=26711"/>
		<updated>2023-01-27T07:57:13Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „&amp;#039;&amp;#039;&amp;#039;Hinweis&amp;#039;&amp;#039;&amp;#039;: @state ist nicht für UIView verfügbar sondern für die View Klasse. Nicht verwechseln.  In SwiftUI ist eine @State Variable eine Variable, die…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Hinweis&amp;#039;&amp;#039;&amp;#039;: @state ist nicht für UIView verfügbar sondern für die View Klasse. Nicht verwechseln.&lt;br /&gt;
&lt;br /&gt;
In SwiftUI ist eine @State Variable eine Variable, die verwendet wird, &amp;#039;&amp;#039;&amp;#039;um den Zustand eines View zu speichern&amp;#039;&amp;#039;&amp;#039;. Wenn der Wert einer @State Variable sich ändert, wird die Ansicht &amp;#039;&amp;#039;&amp;#039;automatisch neu gerendert&amp;#039;&amp;#039;&amp;#039;, um den neuen Zustand widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
@State Variablen werden verwendet, um den internen Zustand eines Views zu speichern, wie z.B. den aktuellen Wert eines Textfeldes, das ausgewählte Element in einer Liste oder den auf-/zugeklappten Zustand eines Views. Sie werden auf View-Ebene definiert und können von allen Unteransichten dieses Views aufgerufen und modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Hier ist ein Beispiel dafür, wie man eine @State Variable in einer SwiftUI Ansicht verwendet:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;switch&amp;quot;&amp;gt;&lt;br /&gt;
struct MyView: View {&lt;br /&gt;
    @State private var text = &amp;quot;Hallo Welt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    var body: some View {&lt;br /&gt;
        TextField(&amp;quot;Geben Sie Text ein&amp;quot;, text: $text)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die @State Variable text verwendet, um den aktuellen Text im TextField zu speichern. Wenn der Benutzer im Textfeld etwas eingibt, wird der Wert der text Variable aktualisiert und die Ansicht wird neu gerendert, um den neuen Wert widerzuspiegeln.&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig zu beachten, dass @State Eigenschaften nur innerhalb des Objekts, das es deklariert, von self modifiziert werden dürfen und auch nicht zwischen verschiedenen Ansichten geteilt werden können.&lt;br /&gt;
&lt;br /&gt;
@State Variablen ähneln @ObservedObject und @EnvironmentObject, da sie alle den Zustand einer Ansicht speichern, aber sie haben unterschiedliche Anwendungsfälle. @ObservedObject wird verwendet, um den Zustand eines Objekts zu speichern, das von mehreren Ansichten geteilt wird, während @EnvironmentObject verwendet wird, um den Zustand eines Objekts zu speichern, das im gesamten App geteilt wird.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_(Programmiersprache)&amp;diff=26710</id>
		<title>Swift (Programmiersprache)</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_(Programmiersprache)&amp;diff=26710"/>
		<updated>2023-01-27T07:49:35Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Funktionen und Eigenschaften */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Programmiersprache im Einsatz in der Apple Welt (MacOs, iOS, WatchOs...)&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[SwiftUI]]&lt;br /&gt;
 https://www.swift.org/ - Dokumentation einfacher Verständlich als die offizielle von Apple&lt;br /&gt;
 https://iosref.com/ - Cheatsheets, Statistiken zu OS Verbreitung und mehr&lt;br /&gt;
&lt;br /&gt;
== Konzepte ==&lt;br /&gt;
=== Einfache Datentypen ===&lt;br /&gt;
 [[Swift - Strings]]&lt;br /&gt;
 [[Swift - Arrays]]&lt;br /&gt;
 [[Swift - Optionals]]&lt;br /&gt;
 [[Swift - Tuples]]&lt;br /&gt;
&lt;br /&gt;
=== Collection Datatypes und komplexe Datentypen ===&lt;br /&gt;
 [[Swift - Dictionaries]]&lt;br /&gt;
 [[Swift - Structures (Struct)]]&lt;br /&gt;
 [[Swift - Classes]]&lt;br /&gt;
&lt;br /&gt;
=== Funktionen und Eigenschaften ===&lt;br /&gt;
 [[Swift - Closures]]&lt;br /&gt;
 [[Swift - Computed Properties]]&lt;br /&gt;
 [[Swift - Internal &amp;amp; External Parameter Names]]&lt;br /&gt;
 [[Swift - weak &amp;amp; strong vars]]&lt;br /&gt;
 [[Swift - @state vars]]&lt;br /&gt;
&lt;br /&gt;
==== Auswahl wichtiger Funktionen ====&lt;br /&gt;
 [[Swift - map/reduce/filter]]&lt;br /&gt;
&lt;br /&gt;
=== Extensions ===&lt;br /&gt;
 [[Swift - Extension]]&lt;br /&gt;
&lt;br /&gt;
== Loops == &lt;br /&gt;
 [[Swift Loops &amp;amp; Animations]]&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
=== URLSession for Networking ===&lt;br /&gt;
 [[Swift - URLSession]]&lt;br /&gt;
&lt;br /&gt;
== Snippets ==&lt;br /&gt;
 [[Swift - Snippets]]&lt;br /&gt;
&lt;br /&gt;
== Frameworks ==&lt;br /&gt;
=== Building a Swift Framework ===&lt;br /&gt;
 [[Building a Swift Framework]]&lt;br /&gt;
&lt;br /&gt;
=== UIKit ===&lt;br /&gt;
UIKit stellt die meisten der gängigen iOS Bedienelemente bereit und ist das wichtigste Modul, wenn es um die Erstellung von iOS Apps geht.&lt;br /&gt;
 [[UIKit Framework]]&lt;br /&gt;
&lt;br /&gt;
=== Cocoapods Dependency Manager ===&lt;br /&gt;
 [http://cocoapods.org cocoapods.org]&lt;br /&gt;
 [[Cocoapods]]&lt;br /&gt;
Cocoapods ein Dependency Manager für Swift and Objective-C Cocoa Projekte. Es gibt hier für viele Zwecke freien Code von Programmierern. Über den Dependency Manager kann man dafür sorgen, dass man stets die aktuelle Version in seinen Projekten hat.&lt;br /&gt;
&lt;br /&gt;
=== Google Firebase ===&lt;br /&gt;
Development platform für Apps, Spiele und Anbindung an Google Dienstleistungen.&lt;br /&gt;
 https://firebase.google.com&amp;amp;&lt;br /&gt;
 [[Swift &amp;amp; Firebase]]&lt;br /&gt;
&lt;br /&gt;
== Assets ==&lt;br /&gt;
=== Dark Mode / Light Mode ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;System Colors&amp;#039;&amp;#039;&amp;#039; verwenden oder &amp;#039;&amp;#039;&amp;#039;Color Sets&amp;#039;&amp;#039;&amp;#039; in den Assets anlegen.&lt;br /&gt;
&lt;br /&gt;
Bilder können ebenfalls mehrere Versionen für Light und Dark bereitgestellt werden.&lt;br /&gt;
 Appearances &amp;gt; Any, Light, Dark&lt;br /&gt;
&lt;br /&gt;
=== Vektor Assets ===&lt;br /&gt;
 Resizing &amp;gt; Preserve Vector Data&lt;br /&gt;
 Scales &amp;gt; Single Scale (es wird nur eine Version benötigt)&lt;br /&gt;
&lt;br /&gt;
=== Custom Assets ===&lt;br /&gt;
 Todo&lt;br /&gt;
&lt;br /&gt;
== Protocols &amp;amp; Delegates ==&lt;br /&gt;
 [[Swift - Protocols]]&lt;br /&gt;
 [[Swift - Decodable &amp;amp; Encodable]]&lt;br /&gt;
 [[Swift - Delegate]]&lt;br /&gt;
&lt;br /&gt;
== Daten speichern ==&lt;br /&gt;
 [[Swift - Möglichkeiten Daten zu speichern]]&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
 [[Swift - Error Handling]]&lt;br /&gt;
&lt;br /&gt;
== Swift - Audio ==&lt;br /&gt;
 [[Swift - Audio Playback]]&lt;br /&gt;
 [[AVAudioPlayerNode]] - geeignet für zeitkritisches Timing&lt;br /&gt;
&lt;br /&gt;
== Swift - Location Data ==&lt;br /&gt;
 [[Swift - CoreLocation]]&lt;br /&gt;
&lt;br /&gt;
== Xcode ==&lt;br /&gt;
 [[Xcode - Tipps &amp;amp; Tricks]]&lt;br /&gt;
&lt;br /&gt;
== Best Practices ==&lt;br /&gt;
=== Constants File ===&lt;br /&gt;
 [[Swift - Constants File]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26709</id>
		<title>Swift - Audio Playback</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_Audio_Playback&amp;diff=26709"/>
		<updated>2023-01-27T07:47:37Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt untschiedliche Möglichkeiten Audio abzuspielen je nachdem was man möchte.&lt;br /&gt;
&lt;br /&gt;
Jede Möglichkeit ist unterschiedlich aufwändig. Es gibt außerdem Klassen um den Systemmixer zu steuern oder das Verhalten wenn die App in den Hintergrund geht zu beeinflussen.&lt;br /&gt;
&lt;br /&gt;
== Glossar ==&lt;br /&gt;
=== AVFoundation ===&lt;br /&gt;
==== AVAudioSession ====&lt;br /&gt;
AVAudioSession ist ein Singleton-Objekt, das die Audio-Sitzung für Ihre App verwaltet. Es ist verantwortlich für die &amp;#039;&amp;#039;&amp;#039;Konfiguration der Audio-Routen&amp;#039;&amp;#039;&amp;#039;, wie dem Ausgabegerät (z.B. Lautsprecher oder Headset) und für die Verwaltung des Zustands der Audio-Sitzung (z.B. aktiv oder inaktiv). AVAudioSession bietet auch Methoden zur Steuerung der &amp;#039;&amp;#039;&amp;#039;Eigenschaften der Audio-Sitzung&amp;#039;&amp;#039;&amp;#039;, wie der Lautstärke und der Audio-Kategorie.&lt;br /&gt;
&lt;br /&gt;
==== AVAudioPlayerNode ====&lt;br /&gt;
AVAudioPlayerNode wird verwendet, um &amp;#039;&amp;#039;&amp;#039;Audio-Puffer und -Dateien&amp;#039;&amp;#039;&amp;#039; innerhalb eines AVAudioEngine-Graphen &amp;#039;&amp;#039;&amp;#039;abzuspielen&amp;#039;&amp;#039;&amp;#039;. Es kann verwendet werden, um das Abspielen von Audio-Puffern und -Dateien zu planen, die Wiedergabegeschwindigkeit, den Pan und die Lautstärke zu ändern und einen Rückruf bereitzustellen, wenn die Wiedergabe abgeschlossen ist.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Zusammengefasst wird AVAudioSession verwendet, um die Gesamt-Audio-Sitzung für Ihre App zu konfigurieren, während AVAudioPlayerNode verwendet wird, um spezifische Audio-Puffer und -Dateien innerhalb dieser Sitzung abzuspielen.&amp;#039;&amp;#039;&amp;#039;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26708</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26708"/>
		<updated>2023-01-26T19:19:58Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Einführung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|rahmenlos|links]]&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26707</id>
		<title>Swift - Möglichkeiten Daten zu speichern</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Swift_-_M%C3%B6glichkeiten_Daten_zu_speichern&amp;diff=26707"/>
		<updated>2023-01-26T19:19:18Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Swift (Programmiersprache)]]&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Es gibt mehrere Möglichkeiten, Benutzerdaten wie Notizen oder Einkaufslisten in einer iPhone-App, die in Swift geschrieben ist, zu speichern. Einige der populärsten Optionen sind:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;User Defaults:&amp;#039;&amp;#039;&amp;#039; Dies ist eine einfache und einfach zu verwendende Methode zum Speichern von kleinen Mengen an Benutzerdaten. Es speichert Daten im Schlüssel-Wert-Paar-Format und die Daten werden automatisch gespeichert, wenn die App geschlossen wird oder im Hintergrund läuft.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Core Data:&amp;#039;&amp;#039;&amp;#039; Core Data ist ein Framework für objektrelationales Mapping (ORM), mit dem Entwickler auf das Datenmodell der App zugreifen können. Es ist eine leistungsstarke und flexible Lösung zum Speichern und Abrufen großer Datenmengen und bietet Funktionen wie Rückgängig- und Wiederholen-Funktionen, Änderungsverfolgung und Datenvalidierung.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Realm:&amp;#039;&amp;#039;&amp;#039; Realm ist ein von Dritten bereitgestelltes ORM, das Core Data ähnlich ist, aber im Allgemeinen als leichter und schneller gilt.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;File I/O:&amp;#039;&amp;#039;&amp;#039; Dies ist die traditionelle Methode zum Speichern von Daten in iOS-Apps. Entwickler können Daten mithilfe des Foundation-Frameworks von und auf das lokale Dateisystem der App lesen und schreiben.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Cloud Service:&amp;#039;&amp;#039;&amp;#039; Durch die Verwendung von Cloud-Service-Anbietern wie AWS, Firebase oder Firestore kann die Daten auf deren Servern gespeichert werden, anstatt auf dem lokalen Gerät. Dieser Ansatz eignet sich, wenn die Daten unter verschiedenen Benutzern geteilt werden oder auf mehreren Geräten zugänglich sein sollen.&lt;br /&gt;
&lt;br /&gt;
Letztlich hängt die Wahl der Methode zum Speichern von Daten von den spezifischen Anforderungen Ihrer App ab, einschließlich der Menge an zu speichernder Daten, der Komplexität des Datenmodells und den Anforderungen an die Datensynchronisierung und Sicherung.&lt;br /&gt;
[[Datei:Swift-ios-DatenSpeichern.jpg|rahmenlos|links]]&lt;br /&gt;
&lt;br /&gt;
== User Defaults ==&lt;br /&gt;
 [[Swift - UserDefaults]]&lt;br /&gt;
&lt;br /&gt;
In iOS ist UserDefaults eine bequeme Klasse zum Speichern von kleinen Mengen an benutzerspezifischen Daten. Es wird von einer plist-Datei unterstützt, die ein einfaches Schlüssel-Wert-Speicherformat ist.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Speichern von JSON Daten mit File I/O ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 [[Swift JSONEncoder]] &lt;br /&gt;
 [[Swift &amp;amp; JSON]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
struct Setlist: Codable {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song: Codable {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// convert Setlist to json Data&lt;br /&gt;
let setlist = Setlist()&lt;br /&gt;
setlist.addSong(title: &amp;quot;song1&amp;quot;, frequency: 44.1)&lt;br /&gt;
let encoder = JSONEncoder()&lt;br /&gt;
guard let encoded = try? encoder.encode(setlist) else {&lt;br /&gt;
    print(&amp;quot;Encoding Failed&amp;quot;)&lt;br /&gt;
    return&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// write json Data to file&lt;br /&gt;
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!&lt;br /&gt;
let fileURL = documentsURL.appendingPathComponent(&amp;quot;setlist.json&amp;quot;)&lt;br /&gt;
do {&lt;br /&gt;
    try encoded.write(to: fileURL, options: .atomic)&lt;br /&gt;
} catch {&lt;br /&gt;
    print(&amp;quot;Error saving file: \(error)&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei &amp;quot;setlist.json&amp;quot; im Dokumentenverzeichnis des Geräts gespeichert.&lt;br /&gt;
Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.&lt;br /&gt;
&lt;br /&gt;
==== JSON Data Objekt als String ausgeben ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
if let jsonString = String(data: encoded, encoding: .utf8) {&lt;br /&gt;
    print(jsonString)&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Could not convert encoded Data to String&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.&lt;br /&gt;
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.&lt;br /&gt;
&lt;br /&gt;
=== Speichern von Daten mit CoreData ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in Core Data erfordert einige zusätzliche Schritte im Vergleich zu User Defaults, da Core Data ein umfangreicheres Framework ist. Hier ist ein Beispiel dafür, wie dies mit Swift und Core Data erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import CoreData&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var objectID: NSManagedObjectID?&lt;br /&gt;
    &lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let setlistEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SetlistEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
    let setlistMO = NSManagedObject(entity: setlistEntity, insertInto: managedContext)&lt;br /&gt;
    setlistMO.setValue(setlist.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    var songMOs = [NSManagedObject]()&lt;br /&gt;
    for song in setlist.songs {&lt;br /&gt;
        let songEntity = NSEntityDescription.entity(forEntityName: &amp;quot;SongEntity&amp;quot;, in: managedContext)!&lt;br /&gt;
        let songMO = NSManagedObject(entity: songEntity, insertInto: managedContext)&lt;br /&gt;
        songMO.setValue(song.title, forKey: &amp;quot;title&amp;quot;)&lt;br /&gt;
        songMO.setValue(song.frequency, forKey: &amp;quot;frequency&amp;quot;)&lt;br /&gt;
        songMOs.append(songMO)&lt;br /&gt;
    }&lt;br /&gt;
    setlistMO.setValue(NSOrderedSet(array: songMOs), forKey: &amp;quot;songs&amp;quot;)&lt;br /&gt;
    setlist.objectID = setlistMO.objectID&lt;br /&gt;
    do {&lt;br /&gt;
        try managedContext.save()&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not save. \(error), \(error.userInfo)&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrieve&lt;br /&gt;
func fetchSetlist(with objectID: NSManagedObjectID) -&amp;gt; Setlist? {&lt;br /&gt;
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return nil }&lt;br /&gt;
    let managedContext = appDelegate.persistentContainer.viewContext&lt;br /&gt;
    let fetchRequest = NSFetchRequest&amp;lt;NSManagedObject&amp;gt;(entityName: &amp;quot;SetlistEntity&amp;quot;)&lt;br /&gt;
    fetchRequest.predicate = NSPredicate(format: &amp;quot;self == %@&amp;quot;, objectID as CVarArg)&lt;br /&gt;
    do {&lt;br /&gt;
        let setlistMO = try managedContext.fetch(fetchRequest).first&lt;br /&gt;
        guard let title = setlistMO?.value(forKey: &amp;quot;title&amp;quot;) as? String, let songsMO = setlistMO?.value(forKey: &amp;quot;songs&amp;quot;) as? Set&amp;lt;NSManagedObject&amp;gt; else {&lt;br /&gt;
            return nil&lt;br /&gt;
        }&lt;br /&gt;
        var songs = [Song]()&lt;br /&gt;
        forsongMO in songsMO {&lt;br /&gt;
             let title = songMO.value(forKey: &amp;quot;title&amp;quot;) as? String, let frequency = songMO.value(forKey: &amp;quot;frequency&amp;quot;) as? Float else {&lt;br /&gt;
                 continue&lt;br /&gt;
             }&lt;br /&gt;
             songs.append(Song(title: title, frequency: frequency))&lt;br /&gt;
        }&lt;br /&gt;
        var setlist = Setlist(title: title, songs: songs)&lt;br /&gt;
        setlist.objectID = objectID&lt;br /&gt;
        return setlist&lt;br /&gt;
    } catch let error as NSError {&lt;br /&gt;
        print(&amp;quot;Could not fetch. (error), (error.userInfo)&amp;quot;)&lt;br /&gt;
    return nil&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet Core Data, um Instanzen des Structs Setlist zu speichern und abzurufen. Es verwendet NSManagedObjects, um die Entitäten von Setlist und Song im Datenmodell darzustellen und die Beziehungen zwischen ihnen zu verwalten. Bitte beachten Sie, dass es hier nur um ein Beispiel geht und dass Core Data viele weitere Funktionen bietet, die je nach Anwendungsfall sinnvoll sein können.&lt;br /&gt;
&lt;br /&gt;
=== Speichern mit SQLite und FMDB ===&lt;br /&gt;
Das Speichern von Instanzen des Structs Setlist in SQLite erfordert die Verwendung eines Wrapper-Libraries die eine einfachere Anbindung von SQLite Datenbanken in Swift ermöglicht, wie z.B FMDB. Hier ist ein Beispiel dafür, wie dies mit Swift und FMDB (OpenSoure Lib) erreicht werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import FMDB&lt;br /&gt;
&lt;br /&gt;
struct Setlist {&lt;br /&gt;
    var title: String = &amp;quot;Default&amp;quot;&lt;br /&gt;
    var songs = [Song]()&lt;br /&gt;
    var id: Int32?&lt;br /&gt;
    mutating func addSong(title: String, frequency: Float){&lt;br /&gt;
        print(&amp;quot;Setlist::addSong&amp;quot;)&lt;br /&gt;
        songs.append(Song(title:title, frequency: frequency))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Song {&lt;br /&gt;
    let title: String&lt;br /&gt;
    let frequency: Float&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
let databaseQueue = FMDatabaseQueue(url: try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(&amp;quot;db.sqlite&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
func createTable() {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Setlist (id INTEGER PRIMARY KEY, title TEXT);&amp;quot;, values: nil)&lt;br /&gt;
            try db.executeUpdate(&amp;quot;CREATE TABLE Song (id INTEGER PRIMARY KEY, title TEXT, frequency REAL, setlist_id INTEGER, FOREIGN KEY(setlist_id) REFERENCES Setlist(id));&amp;quot;, values: nil)&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Save&lt;br /&gt;
func saveSetlist(_ setlist: Setlist) {&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            try db.executeUpdate(&amp;quot;INSERT INTO Setlist (title) VALUES (?);&amp;quot;, values: [setlist.title])&lt;br /&gt;
            setlist.id = db.lastInsertRowId&lt;br /&gt;
            for song in setlist.songs {&lt;br /&gt;
                try db.executeUpdate(&amp;quot;INSERT INTO Song (title, frequency, setlist_id) VALUES (?, ?, ?);&amp;quot;, values: [song.title, song.frequency,setlist.id])&lt;br /&gt;
            }&lt;br /&gt;
        } catch {&lt;br /&gt;
            print(error)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// To Retrive&lt;br /&gt;
func fetchSetlist(with id: Int32) -&amp;gt; Setlist? {&lt;br /&gt;
    var setlist: Setlist?&lt;br /&gt;
    databaseQueue.inDatabase { db in&lt;br /&gt;
        do {&lt;br /&gt;
            let resultSetlist = try db.executeQuery(&amp;quot;SELECT * FROM Setlist WHERE id = ?&amp;quot;, values: [id])&lt;br /&gt;
            if resultSetlist.next() {&lt;br /&gt;
                setlist = Setlist(title: resultSetlist.string(forColumn: &amp;quot;title&amp;quot;)!)&lt;br /&gt;
                setlist!.id = id&lt;br /&gt;
                let resultSongs = try db.executeQuery(&amp;quot;SELECT * FROM Song WHERE setlist_id = ?&amp;quot;, values: [id])&lt;br /&gt;
                while resultSongs.next() {&lt;br /&gt;
                    let song = Song(title: resultSongs.string(forColumn: &amp;quot;title&amp;quot;)!,frequency: resultSongs.double(forColumn: &amp;quot;frequency&amp;quot;))&lt;br /&gt;
                    setlist!.songs.append(song)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            resultSetlist.close()&lt;br /&gt;
         } catch {&lt;br /&gt;
             print(error)&lt;br /&gt;
         }&lt;br /&gt;
    }&lt;br /&gt;
    return setlist&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dieses Beispiel verwendet FMDB, um eine Verbindung zur SQLite-Datenbank herzustellen und Abfragen auszuführen, um Instanzen des Structs Setlist zu speichern und abzurufen. Beachten Sie, dass die Beispielstrukturen und die Datenbanktabellen beide eine ID-Eigenschaft haben, um die Beziehungen zwischen Setlist und Song zu verwalten.&lt;br /&gt;
Es gibt auch andere Bibliotheken wie SQLite.swift die auch SQLite in Swift erleichtern.&lt;br /&gt;
Ich empfehle Ihnen, sich mit den Best Practices für die Verwendung von SQLite in iOS-Apps vertraut zu machen, um sicherzustellen, dass Ihre Anwendung sicher und performant ist.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Datei:Swift-ios-DatenSpeichern.jpg&amp;diff=26706</id>
		<title>Datei:Swift-ios-DatenSpeichern.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Datei:Swift-ios-DatenSpeichern.jpg&amp;diff=26706"/>
		<updated>2023-01-26T19:18:57Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Möglichkeiten in iOS Daten zu persistieren.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=SPF_(Sender_Policy_Framework)&amp;diff=26249</id>
		<title>SPF (Sender Policy Framework)</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=SPF_(Sender_Policy_Framework)&amp;diff=26249"/>
		<updated>2022-09-20T08:00:49Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SPF wird von vielen IT-lern als in der Praxis unwirksam angesehen. Wenn man Weiterleitungen über Newsletterdienstleister oder auch manuelle in der Praxis einbezieht, kann man praktisch nicht mehr hart blockieren (-all). Es kann allerdings als Beweis dafür gelten, das die Mail original ist, wenn sie tatsächlich über den Original-Server versendet wurde. Das ist aber nur dann sinnvoll, wenn dem Empfänger der Absender bekannt ist. Als reiner Schutz gegen Spam funktioniert das nicht, da auch ein Spammer sich eine Domain mit SPF Eintrag billig und Anonym zulegen kann.&lt;br /&gt;
&lt;br /&gt;
Alternative [[DKIM]]&lt;br /&gt;
&lt;br /&gt;
Siehe auch&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://wiki.stephanschlegel.de/index.php?title=E-Mail_Probleme_beheben#Beispiele&lt;br /&gt;
 https://all-inkl.com/wichtig/anleitungen/kas/tools/dns-werkzeuge/spf_482.html&lt;br /&gt;
 https://www.youtube.com/watch?v=T1d7wTgBi28&lt;br /&gt;
 https://switchie.ch/was-bedeutet-spf-sender-policy-framework/# (Quelle dieses Artikels / Zugriff: 2018-01)&lt;br /&gt;
&lt;br /&gt;
== Beispiel erklärt ==&lt;br /&gt;
=== Problem ===&lt;br /&gt;
Absender können gefälscht werden. Es darf jeder alles verschicken.&lt;br /&gt;
=== Lösung ???===&lt;br /&gt;
TXT (SPF) DNS Eintrag gibt vor wer versenden darf.&lt;br /&gt;
 heinlein-support.de. IN TXT &amp;quot;v=spf1 ip4:213.203.238.0/25 ip4:195.10.208.0/24 mx include:jpberlin.de ?all&amp;quot;&lt;br /&gt;
Hier wird quasi hinterlegt wer versenden darf&lt;br /&gt;
 v=spf1 -&amp;gt; Version (SPF-Record Version 1)&lt;br /&gt;
 ip4:xxx:xxx:xxx:xxx/xx -&amp;gt; IP Bereich&lt;br /&gt;
 include:... -&amp;gt; Ein SPF-Reord einer anderen Domain wird included&lt;br /&gt;
 mx -&amp;gt; Server die auch als MX-Recrds definiert sind dürfen verschicken&lt;br /&gt;
 ?all -&amp;gt; Keine Aussage was andere Server dürfen (-all = kein anderer Server darf versenden, +all = alle anderen dürfen sind dann halt nicht verifiziert)&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
* Die Einstellung TXT statt SPF ist wichtig, da TXT seit rfc7208 der einzig standardkonforme Record für SPF ist! Der dedizierte SPF-Record ist damit obsolet und wird daher nicht breitflächig unterstützt. &lt;br /&gt;
&lt;br /&gt;
== Übersicht von switcher.ch ==&lt;br /&gt;
SPF (Sender Policy Framework) ist ein Protokoll, mit dem ein Halter einer DOMAIN festlegen kann, welche IP-Adressen E-Mails im Namen seiner DOMAINs verschicken dürfen und steht für „Sender Policy Framework“. Wenn jemand also eine E-Mail erhält, die behauptet von der DOMAIN ihr-unternehmen.ch versendet worden zu sein, so kann man mittels SPF prüfen, ob dies wirklich der Fall ist. Wenn die entsprechende IP-Adresse nicht durch den SPF-Eintrag autorisiert wurde, so ist die Wahrscheinlichkeit sehr gross, dass die versendete E-Mail ohne Zustimmung des Halter der DOMAIN verschickt wurde. Die Deutung dieser Information liegt letztlich immer im Verantwortungsbereich des Empfängers, ein fehlgeschlagener SPF-Test ist jedoch definitiv ein sehr deutliches Indiz für Spam.&lt;br /&gt;
&lt;br /&gt;
== So funktioniert es ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktionalität von SPF setzt zwei Bedingungen voraus:&lt;br /&gt;
&lt;br /&gt;
    Jeder Halter des DOMAINs sollte einen korrekten SPF-Eintrag für seine DOMAIN haben, um eine möglichst grosse Flächenabdeckung von SPF gewährleisten zu können.&lt;br /&gt;
    Mailserver müssen die SPF-Prüfung durchführen.&lt;br /&gt;
&lt;br /&gt;
Die Erstellung eines SPF-Eintrages für die DOMAIN kann  problemlos über das Benutzerkonto vorgenommen werden. Der zweite Teil ist jedoch der kompliziertere Teil. Es gibt zwar immer mehr Mailserverbetreiber, die anfangen, SPF-Einträge zu prüfen, von einer flächendeckenden Installation kann jedoch momentan noch bei weitem keine Rede sein.&lt;br /&gt;
&lt;br /&gt;
Trotz allem ist es sehr empfehlenswert, einen SPF-Eintrag für jede DOMAIN zu hinterlegen. Die Verbreitung von SPF nimmt stetig zu. Je mehr DOMAINs SPF-Einträge haben, umso schneller werden auch die Mailserver beginnen, diese Einträge auszuwerten!&lt;br /&gt;
&lt;br /&gt;
Unter den folgenden Links können Sie weitere Informationen zum Thema SPF in Erfahrung bringen:&lt;br /&gt;
&lt;br /&gt;
    http://www.openspf.org&lt;br /&gt;
    http://www.baschny.de/spf/&lt;br /&gt;
&lt;br /&gt;
=== Kann SPF Spam verhindern ? ===&lt;br /&gt;
&lt;br /&gt;
Auch SPF ist leider kein Allheilmittel gegen Spam. Indirekt kann SPF jedoch sehr viel hierzu beitragen. E-Mails werden mittels „Simple Mail Transfer Protocol“ (SMTP) versendet. Bei diesem Protokoll handelt es sich um einen mehr als 20 Jahre alten Standard, der aus einer Zeit stammt, in der es noch keinen Spam gab und man sich „gegenseitig vertrauen“ konnte. Deshalb verfügt das SMTP-Protokoll auch über kein Verfahren, E-Mails versendende Rechner entsprechend zu authentifizieren.&lt;br /&gt;
&lt;br /&gt;
Genau an dieser Stelle setzt „SPF“ an: Bei Definition eines SPF-Eintrages für eine DOMAIN kann einwandfrei festgestellt werden, ob ein Rechner, von dem eine E-Mail versendet wurde, auch tatsächlich für die entsprechende DOMAIN autorisiert ist.&lt;br /&gt;
&lt;br /&gt;
Dies heisst also, dass der SPF-Eintrag für Ihre DOMAIN keine Wirkung hat auf E-Mails die Sie empfangen. Der SPF-Eintrag ist für E-Mails, die Sie versenden. Wenn ein Empfänger eine E-Mail von Ihnen erhält und Ihre DOMAIN einen SPF-Eintrag besitzt, so kann der Empfänger dieser E-Mail prüfen, ob die E-Mail tatsächlich von Ihnen versendet wurde.&lt;br /&gt;
Kann ich überprüfen, ob mein SPF-Eintrag funktioniert ?&lt;br /&gt;
&lt;br /&gt;
Ja, das ist möglich. Hier können Sie die Funktionalität des SPF-Eintrags überprüfen.&lt;br /&gt;
Wie lautet der SPF-Eintrag, wenn ich MAIL von switchplus nutze ?&lt;br /&gt;
&lt;br /&gt;
Der SPF-Eintrag für das Versenden über die switchplus E-Mailkonten lautet:&lt;br /&gt;
&lt;br /&gt;
 v=spf1 a mx include:spf.switchplus-mail.ch ~all&lt;br /&gt;
&lt;br /&gt;
Bitte kopieren Sie diesen mit genau dieser Syntax in die Eingabemaske und speichern Sie die Änderung.&lt;br /&gt;
&lt;br /&gt;
Im unserem GUI können Sie „nur“ einen SPF-Record eintragen (es kann also kein zweiter SPF-Record erstellt werden). Sollten zwei Einträge gesetzt werden müssen, können Sie den SPF-Eintrag wie nachfolgendes Beispiel zeigt ergänzen (hier wird z.B. eine zusätzliche IP-Adresse hinzugefügt):&lt;br /&gt;
v=spf1 a mx include:spf.switchplus-mail.ch ip4:xxx.xxx.xxx.xxx ~all&lt;br /&gt;
&lt;br /&gt;
=== Wie erstelle ich einen SPF-Eintrag für eine DOMAIN ? ===&lt;br /&gt;
&lt;br /&gt;
Um für eine bestimmte DOMAIN einen SPF-Eintrag zu erstellen, gehen Sie bitte wie folgt vor:&lt;br /&gt;
&lt;br /&gt;
    Loggen Sie sich auf www.switchplus.ch in Ihr Benutzerkonto ein, klicken Sie links in der Navigationsleiste auf „Grundkonfiguration“. Gehen Sie anschliessend rechts am Zeilenende der jeweiligen DOMAIN auf das Editierungssymbol und wählen Sie „Nameserver editieren“. In der Folge-Maske finden Sie alle Records. Klicken Sie nun unten links auf „Eintrag hinzufügen“ und wählen Sie nun beim neu erschienenem Eintrag den Typ „SPF“. Klicken Sie danach auf das nun erschienene Auflistungs-Symbol rechts.&lt;br /&gt;
&lt;br /&gt;
Folgende Konfigurationsmöglichkeiten stehen über die Eingabemaske (Auflistungs-Symbol) zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
    1. Meine Webseiten verschicken E-Mails, z.B. über Formmailskripte oder als Teil der installierten Programme wie Forum, Shoplösung etc.&lt;br /&gt;
    Geben Sie hier bitte an, ob E-Mails von Ihrer DOMAIN auch über Formmailer, Shopsoftware o.ä. Anwendungen verschickt werden. So können Sie bestimmen, ob die IP-Adresse des Webservers in den SPF-Eintrag aufgenommen werden soll.&lt;br /&gt;
&lt;br /&gt;
    2. Wenn ich E-Mails verschicke, verwende ich die SMTP-Server von switchplus&lt;br /&gt;
    Definieren Sie hier, ob Sie beim Versand von E-Mails die Mailserver von switchplus verwenden. Sofern Sie keinen eigenen Mailserver in Ihrem Hause betreiben, ist hier standardmässig die Einstellung „JA“ vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
    2a. Wenn Sie Frage 2 mit „Nein“ beantwortet haben:&lt;br /&gt;
    Die folgende IP-Adresse versendet E-Mails für meine DOMAIN:&lt;br /&gt;
    Bitte so eingeben: 123.46.78.0 oder 123.43.12.0/24&lt;br /&gt;
    Sofern Sie für den Versand von E-Mails nicht die Mailserver von switchplus verwenden und bei der vorhergehenden Option „NEIN“ gewählt haben, so können Sie hier die IP-Adressen angeben, über welche Ihre E-Mails versendet werden.&lt;br /&gt;
&lt;br /&gt;
    3. Von anderen IP-Adressen werden niemals E-Mails für meine DOMAIN verschickt.&lt;br /&gt;
    Hier können Sie bestimmen, ob neben den über die obigen Konfigurationsmöglichkeiten angegebenen Mailservern noch weitere Mailserver für den Versand Ihrer E-Mails zuständig sind.&lt;br /&gt;
&lt;br /&gt;
    Klicken Sie auf „speichern“, um den SPF-Eintrag für Ihre DOMAIN einzutragen und zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
===Wie kann ein bestehender SPF-Eintrag geändert werden ? ===&lt;br /&gt;
&lt;br /&gt;
Loggen Sie sich auf www.switchplus.ch in Ihr Benutzerkonto ein und klicken Sie links in der Navigationsleiste auf „Grundkonfiguration“. Gehen Sie anschliessend rechts am Zeilenende der jeweiligen DOMAIN auf das Editierungssymbol und wählen Sie „Nameserver editieren“. In der Folge-Maske finden Sie alle Records. Beim bestehenden SPF-Record können Sie nun die gewünschten Einstellungen vornehmen in dem Sie auf das Auflistungs-Symbol klicken.&lt;br /&gt;
Der SPF-Assistent erzeugt einen korrekten SPF-Eintrag, den Sie nach Belieben ändern können. Sie sollten dies jedoch nur dann machen, wenn Sie SPF und seine Parameter wirklich kennen. Der SPF-Eintrag wird aber immer auf Korrektheit überprüft. Sollten Sie daher Fehler bei der individuellen Eingabe machen, werden Sie über die Fehler informiert und der Eintrag wird nicht aktiviert.&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Hanna_Code_(Module)&amp;diff=26248</id>
		<title>ProcessWire - Hanna Code (Module)</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ProcessWire_-_Hanna_Code_(Module)&amp;diff=26248"/>
		<updated>2022-09-16T06:35:42Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TextformatterHannaCode&lt;br /&gt;
&lt;br /&gt;
Easily insert any complex HTML, Javascript or PHP output in your ProcessWire content by creating your own Hanna code tags.&lt;br /&gt;
 https://github.com/ryancramerdesign/ProcessHannaCode#using-hanna-code-from-the-api&lt;br /&gt;
&lt;br /&gt;
== Hanna Code Snippets ==&lt;br /&gt;
=== Image from RepeaterMatrix or Repeater ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// include a image from the parent page&lt;br /&gt;
if (!function_exists(&amp;#039;getImagePage&amp;#039;)) {&lt;br /&gt;
    &lt;br /&gt;
    function getImagePage($myPage, $level=1){&lt;br /&gt;
        // if in repeater or repeaterMatrix find the first parent ProcessWire\Page Page&lt;br /&gt;
        $maxLevel=5;&lt;br /&gt;
        if( get_class($myPage) == &amp;#039;ProcessWire\RepeaterMatrixPage&amp;#039; || get_class($myPage) == &amp;#039;ProcessWire\RepeaterPage&amp;#039;) {&lt;br /&gt;
            $level +=1;&lt;br /&gt;
            if($level &amp;gt; $maxLevel) return false;&lt;br /&gt;
            $forPage = $myPage-&amp;gt;getForPage();&lt;br /&gt;
            //var_dump( $myPage-&amp;gt;getForPage());&lt;br /&gt;
            //echo(&amp;quot;&amp;lt;p&amp;gt;next Level: &amp;quot;.get_class($forPage).&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;);&lt;br /&gt;
            return $myPage = getImagePage($forPage);&lt;br /&gt;
           &lt;br /&gt;
        }else if( get_class($myPage) == &amp;#039;ProcessWire\Page&amp;#039;){&lt;br /&gt;
            &lt;br /&gt;
            return $myPage;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
$imagePage = getImagePage($page);&lt;br /&gt;
$images = $imagePage-&amp;gt;images;&lt;br /&gt;
$imgTag = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
if($images){&lt;br /&gt;
    if(isset($file)){&lt;br /&gt;
        isset($width) ? $image =  $images-&amp;gt;get($file)-&amp;gt;width($width) : $image = $images-&amp;gt;get($file);&lt;br /&gt;
        $imgTag .= &amp;quot;&amp;lt;img src=&amp;#039;$image-&amp;gt;url&amp;#039;&amp;quot;; &lt;br /&gt;
        if(isset($width)) $imgTag .= &amp;quot; width=&amp;#039;$width&amp;#039;&amp;quot;;&lt;br /&gt;
        if(isset($class)) $imgTag .= &amp;quot; class=&amp;#039;$class&amp;#039;&amp;quot;;&lt;br /&gt;
        if(isset($style)) $imgTag .= &amp;quot; style=&amp;#039;$style&amp;#039;&amp;quot;;&lt;br /&gt;
        $imgTag .= &amp;#039;&amp;gt;&amp;#039;;&lt;br /&gt;
        $out = $imgTag;&lt;br /&gt;
    }else{&lt;br /&gt;
        $out .= &amp;quot;&amp;lt;p&amp;gt;Gib einen Bildnamen an z.B.&amp;lt;/p&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach($images as $image){&lt;br /&gt;
            $out .= &amp;#039;&amp;lt;p&amp;gt;[[image file=&amp;quot;&amp;#039;.$image-&amp;gt;name.&amp;#039;&amp;quot;]]&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}else{&lt;br /&gt;
   $out .= &amp;#039;&amp;lt;p&amp;gt;Keine Bilder auf der Seite gefunden&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
echo $out;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Templates ===&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 echo(urls()-&amp;gt;templates);&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
Von chargercube - todo security / video field statt dateifeld&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// include a image from the parent page&lt;br /&gt;
if (!function_exists(&amp;#039;getImagePage&amp;#039;)) {&lt;br /&gt;
    &lt;br /&gt;
    function getImagePage($myPage, $level=1){&lt;br /&gt;
        // if in repeater or repeaterMatrix find the first parent ProcessWire\Page Page&lt;br /&gt;
        $maxLevel=5;&lt;br /&gt;
        if( get_class($myPage) == &amp;#039;ProcessWire\RepeaterMatrixPage&amp;#039; || get_class($myPage) == &amp;#039;ProcessWire\RepeaterPage&amp;#039;) {&lt;br /&gt;
            $level +=1;&lt;br /&gt;
            if($level &amp;gt; $maxLevel) return false;&lt;br /&gt;
            $forPage = $myPage-&amp;gt;getForPage();&lt;br /&gt;
            //var_dump( $myPage-&amp;gt;getForPage());&lt;br /&gt;
            //echo(&amp;quot;&amp;lt;p&amp;gt;next Level: &amp;quot;.get_class($forPage).&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;);&lt;br /&gt;
            return $myPage = getImagePage($forPage);&lt;br /&gt;
           &lt;br /&gt;
        }else if( get_class($myPage) == &amp;#039;ProcessWire\Page&amp;#039;){&lt;br /&gt;
            &lt;br /&gt;
            return $myPage;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
$imagePage = getImagePage($page);&lt;br /&gt;
//var_dump($imagePage-&amp;gt;name);&lt;br /&gt;
$files = $imagePage-&amp;gt;files;&lt;br /&gt;
$videoTag = &amp;#039;&amp;#039;;&lt;br /&gt;
$videoValid = false;&lt;br /&gt;
$styles = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
if($files){&lt;br /&gt;
    if(isset($file)){&lt;br /&gt;
        $file = $files-&amp;gt;get($file); // we need the file object not the file name&lt;br /&gt;
        if(isset($width)) $styles = &amp;#039;width: &amp;#039;.$width.&amp;#039;; max-width: 100%; height: auto;&amp;#039;; &lt;br /&gt;
        else $styles = &amp;#039;width: 100%; height: auto;&amp;#039;;&lt;br /&gt;
        if($file){&lt;br /&gt;
            $videoValid = true;&lt;br /&gt;
            $videoTag .= &amp;#039;&lt;br /&gt;
            &amp;lt;video style=&amp;quot;&amp;#039;.$styles.&amp;#039;&amp;quot; preload=&amp;quot;preload&amp;quot; playsinline=&amp;quot;&amp;quot; controls=&amp;quot;&amp;quot; uk-video=&amp;quot;autoplay: false&amp;quot; aria-hidden=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;source src=&amp;quot;&amp;#039;.$file-&amp;gt;url.&amp;#039;&amp;quot; type=&amp;quot;video/mp4&amp;quot;&amp;gt;&lt;br /&gt;
                Ihr Browser unterstützt kein Video Tag&lt;br /&gt;
            &amp;lt;/video&amp;gt;&lt;br /&gt;
            &amp;#039;;&lt;br /&gt;
            $out = $videoTag;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if(!$videoValid){&lt;br /&gt;
        $out .= &amp;quot;&amp;lt;p&amp;gt;Gib einen Dateinamen an. Dateien auf dieser Seite:.&amp;lt;/p&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach($files as $file){&lt;br /&gt;
            $out .= &amp;#039;&amp;lt;p&amp;gt;[[video file=&amp;quot;&amp;#039;.$file-&amp;gt;name.&amp;#039;&amp;quot;]]&amp;lt;/p&amp;gt;&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}else{&lt;br /&gt;
   $out .= &amp;#039;&amp;lt;p&amp;gt;Keine Dateie auf der Seite gefunden&amp;lt;/p&amp;gt;&amp;#039;; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo $out;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Heading ===&lt;br /&gt;
Genbänkle&lt;br /&gt;
&lt;br /&gt;
Attributes&lt;br /&gt;
 tag=h2&lt;br /&gt;
 heading&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
echo($heading);&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Next Events ===&lt;br /&gt;
Genbänkle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$today = strtotime(date(&amp;#039;Y-m-d&amp;#039;));&lt;br /&gt;
$eventPage = $pages-&amp;gt;get(&amp;#039;/termine/&amp;#039;);&lt;br /&gt;
$mySelector = &amp;quot;template=event,limit=2,sort=event_date,event_date&amp;gt;=$today&amp;quot;;&lt;br /&gt;
$events = $pages-&amp;gt;find($mySelector);&lt;br /&gt;
$eventListMarkup = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
foreach($events as $event){&lt;br /&gt;
    $eventListMarkup .= &amp;#039;&amp;lt;div class=&amp;quot;date uk-text-muted&amp;quot;&amp;gt;&amp;#039;.$event-&amp;gt;event_date.&amp;#039;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
    $eventListMarkup .= &amp;#039;&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039;.$event-&amp;gt;url().&amp;#039;&amp;quot;&amp;gt;&amp;#039;.$event-&amp;gt;title.&amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;#039;;    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo $eventListMarkup;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Childnavigation ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
$out = &amp;#039;&amp;#039;;&lt;br /&gt;
($attr[&amp;#039;parent&amp;#039;]) ? $parent = $pages-&amp;gt;get($attr[&amp;#039;parent&amp;#039;]) : $parent = $page;&lt;br /&gt;
$children = $parent-&amp;gt;children();&lt;br /&gt;
$out .= &amp;#039;&amp;lt;ul class=&amp;quot;childnav&amp;quot;&amp;gt;&amp;#039;;&lt;br /&gt;
foreach ($children as $child){&lt;br /&gt;
    $out .= &amp;#039;&amp;lt;li class=&amp;quot;nav-item&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;nav-link&amp;quot; href=&amp;quot;&amp;#039;.$child-&amp;gt;url.&amp;#039;&amp;quot;&amp;gt;&amp;#039;. $child-&amp;gt;title . &amp;#039;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
}&lt;br /&gt;
$out .= &amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
echo $out;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Social Media Icons über Repeater ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php namespace ProcessWire;&lt;br /&gt;
&lt;br /&gt;
// SOCIALMEDIA&lt;br /&gt;
$socialmedia = &amp;#039;&amp;#039;;&lt;br /&gt;
$p = $pages-&amp;gt;get(&amp;#039;/site-configuration/&amp;#039;);&lt;br /&gt;
//bd($p-&amp;gt;r_socialicons);&lt;br /&gt;
foreach($p-&amp;gt;r_socialicons as $item){&lt;br /&gt;
    if($item-&amp;gt;link){&lt;br /&gt;
	    $socialmedia .= &amp;#039;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039;.$item-&amp;gt;link.&amp;#039;&amp;quot; target=&amp;quot;_blank&amp;quot; description=&amp;quot;&amp;#039;.$item-&amp;gt;text.&amp;#039;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;&amp;#039;.$item-&amp;gt;single_image-&amp;gt;width(48)-&amp;gt;url.&amp;#039;&amp;quot; uk-tooltip=&amp;quot;&amp;#039;.$item-&amp;gt;text.&amp;#039;&amp;quot; alt=&amp;quot;&amp;#039;.$item-&amp;gt;text.&amp;#039;&amp;quot; title=&amp;quot;&amp;#039;.$item-&amp;gt;text.&amp;#039;&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
return &amp;#039;&amp;lt;ul class=&amp;quot;nav socialicons uk-flex uk-flex-center@m nmb&amp;quot;&amp;gt;&amp;#039;.$socialmedia.&amp;#039;&amp;lt;/ul&amp;gt;&amp;#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26247</id>
		<title>Puppeteer - NodeJS Scraping</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26247"/>
		<updated>2022-09-12T18:46:06Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Puppeteer ==&lt;br /&gt;
Puppeteer Hauptseite.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://pptr.dev/&lt;br /&gt;
 https://www.youtube.com/watch?v=CngYXf9aeg8&amp;amp;list=PLGreOtbNU07rDURvnQpDaT3XokxlranUQ&lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
 https://advancedweb.hu/how-to-speed-up-puppeteer-scraping-with-parallelization/&lt;br /&gt;
 https://jsoverson.medium.com/using-chrome-devtools-protocol-with-puppeteer-737a1300bac0 *&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
 https://www.youtube.com/watch?v=Sag-Hz9jJNg&lt;br /&gt;
Voraussetzung: VisualStudioCode, NodeJS installiert&lt;br /&gt;
&lt;br /&gt;
Ordner erstellen und NodeJS Projekt starten&lt;br /&gt;
&lt;br /&gt;
Terminal&lt;br /&gt;
 npm init -y&lt;br /&gt;
 npm install puppeteer&lt;br /&gt;
&lt;br /&gt;
Installiert auch Chromium. Schau mal in die package.json&lt;br /&gt;
&lt;br /&gt;
Als Basis kommt fast immer ein Konstrukt ähnlich dem folgenden zum Einsatz. Im Wesentlichen passiert folgendes:&lt;br /&gt;
&lt;br /&gt;
index.js erstellen. Puppeteer laden mit asynchroner Funktion. Diese Funktion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;); //pup&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // open a new browser - headless (default) or with displaying&lt;br /&gt;
  const page = await browser.newPage();  // open a new tab&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;); // navigate to a url&lt;br /&gt;
  // do s.th.&lt;br /&gt;
  await browser.close(); // close the browser&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel Screenshot von Seite anfertigen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
  await page.screenshot({path: &amp;quot;screenshot.png&amp;quot;})&lt;br /&gt;
&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Starten mit&lt;br /&gt;
 node index.js&lt;br /&gt;
&lt;br /&gt;
== Beispiel Skripte ==&lt;br /&gt;
Hinweis: Da die Skripte in diesem Setup keine ES Module sind, gab es bei mir Probleme in Node wenn man die Strichpunkte weglässt.&lt;br /&gt;
&lt;br /&gt;
=== DOM Elemente scrapen mit evaluate ===&lt;br /&gt;
Zum Scrapen bietet sich die evaluate Funk&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;)&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  const grabSlogan = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const slogan = document.querySelector(&amp;quot;.uk-text-lead&amp;quot;)&lt;br /&gt;
    //return slogan.innerHTML // with html tags&lt;br /&gt;
    return slogan.innerText // only the text&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  console.log(grabSlogan)&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// grab multiple elements&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//... wie oben&lt;br /&gt;
  const grabList = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const listTags = document.querySelectorAll(&amp;quot;.uk-nav-default li&amp;quot;)&lt;br /&gt;
    let listItems = []&lt;br /&gt;
    listTags.forEach((tag) =&amp;gt; {&lt;br /&gt;
      listItems.push(tag.innerText)&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
    return listItems&lt;br /&gt;
  })&lt;br /&gt;
  console.log(grabList)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Komplexere DOM-Zugriffe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const grab = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    let arrElements = [];&lt;br /&gt;
    const quotes = document.querySelectorAll(&amp;quot;.quote&amp;quot;);&lt;br /&gt;
    quotes.forEach( (quote) =&amp;gt; {&lt;br /&gt;
      const quoteSpans = quote.querySelectorAll(&amp;quot;span&amp;quot;);&lt;br /&gt;
      const quoteText = quoteSpans[0].innerHTML;&lt;br /&gt;
      const quoteAuthor = quoteSpans[1].querySelector(&amp;quot;small&amp;quot;).innerHTML;&lt;br /&gt;
      arrElements.push({&amp;#039;quote&amp;#039;: quoteText, &amp;#039;author&amp;#039;: quoteAuthor});&lt;br /&gt;
    });&lt;br /&gt;
    return arrElements;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  console.log(grab);&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User actions simulieren ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  await page.click(&amp;#039;a[href=&amp;quot;/login&amp;quot;]&amp;#039;); // click login link&lt;br /&gt;
  await page.type(&amp;#039;#username&amp;#039;,&amp;#039;myUserName&amp;#039;,{delay:300});&lt;br /&gt;
  await page.type(&amp;#039;#password&amp;#039;,&amp;#039;mySecret&amp;#039;);&lt;br /&gt;
  await page.click(&amp;#039;input[type=&amp;quot;submit&amp;quot;]&amp;#039;);&lt;br /&gt;
  //await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Computed Styles von DOM Elementen auslesen ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Styles eines DOM Elements&amp;#039;&amp;#039;&amp;#039; finden. Hier nutzen wir mal die $eval Funktion. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const myStyles = await page.$eval(&amp;#039;body&amp;#039;, el =&amp;gt; getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;)&lt;br /&gt;
  );&lt;br /&gt;
  console.log(myStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Handle Functions sind nicht so performant aber eher menschenähnlich. Bei einem Klick würde der Browser tatsächlich die Maus bewegen statt einfach einen Klick Event zu senden.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Evaluate Version&amp;#039;&amp;#039;&amp;#039; - besser zu debuggen Unterschiede in der Ausführung. Siehe: https://stackoverflow.com/questions/55664420/page-evaluate-vs-puppeteer-methods&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;body&amp;#039;);&lt;br /&gt;
    const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;);&lt;br /&gt;
    return myStyle&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;So kann man alle Styles auslesen:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;p&amp;#039;);&lt;br /&gt;
    //const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;); // get a specific style&lt;br /&gt;
    const stylesObject = getComputedStyle(el);&lt;br /&gt;
    const myStyles = {};&lt;br /&gt;
    for (const prop in stylesObject) {&lt;br /&gt;
      if(stylesObject.hasOwnProperty(prop)){ // filter out &lt;br /&gt;
        myStyles[prop] = stylesObject[prop];&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    //return myStyle;&lt;br /&gt;
    return myStyles;&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PDF generieren ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // print pdf&lt;br /&gt;
  await page.pdf({&lt;br /&gt;
    path: &amp;quot;myWebsite.pdf&amp;quot;, // mandatory - rest ist optional&lt;br /&gt;
    format: &amp;#039;A4&amp;#039;, // default is letter&lt;br /&gt;
    margin: {&lt;br /&gt;
      top: &amp;#039;100px&amp;#039;,&lt;br /&gt;
      bottom: &amp;#039;100px&amp;#039;&lt;br /&gt;
    },&lt;br /&gt;
    printBackground: true,&lt;br /&gt;
    displayHeaderFooter: true,&lt;br /&gt;
    headerTemplate: `&amp;lt;p style=&amp;quot;font-size: 10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`,&lt;br /&gt;
    footerTemplate: `&amp;lt;p style=&amp;quot;font-size:10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;pageNumber&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; of &amp;lt;span class=&amp;quot;totalPages&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Crawl multiple pages ===&lt;br /&gt;
 https://stackoverflow.com/questions/46293216/crawling-multiple-urls-in-a-loop-using-puppeteer&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.setDefaultNavigationTimeout(0); // prevent timeout after 30s.&lt;br /&gt;
//...&lt;br /&gt;
urls = [&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;...]&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i &amp;lt; urls.length; i++) {&lt;br /&gt;
    const url = urls[i];&lt;br /&gt;
    await page.goto(`${url}`);&lt;br /&gt;
    await page.waitForNavigation({ waitUntil: &amp;#039;networkidle2&amp;#039; });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Input- und Output-Files ===&lt;br /&gt;
 https://github.com/Zrce/puppeteer-coverage-report-test/blob/master/index.js&lt;br /&gt;
 https://stackoverflow.com/questions/59981135/puppeteer-iterate-over-a-csv-file-and-screenshot-for-each-row&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;CSV Datei mit URLs abarbeiten - seriell/parallel&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
[[Puppeteer - CSV Datei sequentiell / parallel a abarbeiten (Beispiel)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zertifikate und Puppeteer ===&lt;br /&gt;
 [[Puppeteer - Zertifikate handeln]]&lt;br /&gt;
&lt;br /&gt;
=== Network Request Control ===&lt;br /&gt;
 https://github.com/puppeteer/puppeteer/blob/main/examples/block-images.js&lt;br /&gt;
 [[Puppeteer - RequestInterception]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26246</id>
		<title>Puppeteer - RequestInterception</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26246"/>
		<updated>2022-09-12T18:34:44Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Snippets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der RequestInterceptor klinkt sich quasi ein, wenn die ganzen Resourcen der Webpage nachgeladen werden. So kann man direkt eingreifen. Der Ladevorgang der Resourcen geht erst weiter, wenn request.continue() oder request.abort() aufgerufen wird.&lt;br /&gt;
== Snippets ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.on(&amp;#039;request&amp;#039;, (request) =&amp;gt; {&lt;br /&gt;
        if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url)) {&lt;br /&gt;
          request.abort();&lt;br /&gt;
        } else if (request.url.startsWith(defaults.URL_INSTAGRAM_GRAPHQL_QUERY)) {&lt;br /&gt;
          query_id = request.url.split(&amp;#039;=&amp;#039;)[1].split(&amp;#039;&amp;amp;&amp;#039;)[0];&lt;br /&gt;
        } else {&lt;br /&gt;
          request.continue();&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&amp;#039;use strict&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
const puppeteer = require(&amp;#039;puppeteer&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch();&lt;br /&gt;
  const page = await browser.newPage();&lt;br /&gt;
  await page.setRequestInterception(true);&lt;br /&gt;
  page.on(&amp;#039;request&amp;#039;, request =&amp;gt; {&lt;br /&gt;
    if (request.resourceType() === &amp;#039;image&amp;#039;) {&lt;br /&gt;
      request.abort();&lt;br /&gt;
    } else {&lt;br /&gt;
      request.continue();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  await page.goto(&amp;#039;https://news.google.com/news/&amp;#039;);&lt;br /&gt;
  await page.screenshot({path: &amp;#039;news.png&amp;#039;, fullPage: true});&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
})();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26245</id>
		<title>Puppeteer - RequestInterception</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26245"/>
		<updated>2022-09-12T18:34:01Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Snippets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der RequestInterceptor klinkt sich quasi ein, wenn die ganzen Resourcen der Webpage nachgeladen werden. So kann man direkt eingreifen. Der Ladevorgang der Resourcen geht erst weiter, wenn request.continue() oder request.abort() aufgerufen wird.&lt;br /&gt;
== Snippets ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.on(&amp;#039;request&amp;#039;, (request) =&amp;gt; {&lt;br /&gt;
        if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url)) {&lt;br /&gt;
          request.abort();&lt;br /&gt;
        } else if (request.url.startsWith(defaults.URL_INSTAGRAM_GRAPHQL_QUERY)) {&lt;br /&gt;
          query_id = request.url.split(&amp;#039;=&amp;#039;)[1].split(&amp;#039;&amp;amp;&amp;#039;)[0];&lt;br /&gt;
        } else {&lt;br /&gt;
          request.continue();&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.on(&amp;#039;request&amp;#039;, (request) =&amp;gt; {&lt;br /&gt;
        if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url)) {&lt;br /&gt;
          request.abort();&lt;br /&gt;
        } else if (request.url.startsWith(defaults.URL_INSTAGRAM_GRAPHQL_QUERY)) {&lt;br /&gt;
          query_id = request.url.split(&amp;#039;=&amp;#039;)[1].split(&amp;#039;&amp;amp;&amp;#039;)[0];&lt;br /&gt;
        } else {&lt;br /&gt;
          request.continue();&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26244</id>
		<title>Puppeteer - RequestInterception</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_RequestInterception&amp;diff=26244"/>
		<updated>2022-09-12T18:23:34Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „== Snippets == &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt; page.on(&amp;#039;request&amp;#039;, (request) =&amp;gt; {         if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url)) {           r…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Snippets ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.on(&amp;#039;request&amp;#039;, (request) =&amp;gt; {&lt;br /&gt;
        if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url)) {&lt;br /&gt;
          request.abort();&lt;br /&gt;
        } else if (request.url.startsWith(defaults.URL_INSTAGRAM_GRAPHQL_QUERY)) {&lt;br /&gt;
          query_id = request.url.split(&amp;#039;=&amp;#039;)[1].split(&amp;#039;&amp;amp;&amp;#039;)[0];&lt;br /&gt;
        } else {&lt;br /&gt;
          request.continue();&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26243</id>
		<title>Puppeteer - NodeJS Scraping</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26243"/>
		<updated>2022-09-12T18:23:03Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Network Request Control */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Puppeteer ==&lt;br /&gt;
Puppeteer Hauptseite.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://pptr.dev/&lt;br /&gt;
 https://www.youtube.com/watch?v=CngYXf9aeg8&amp;amp;list=PLGreOtbNU07rDURvnQpDaT3XokxlranUQ&lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
 https://advancedweb.hu/how-to-speed-up-puppeteer-scraping-with-parallelization/&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
 https://www.youtube.com/watch?v=Sag-Hz9jJNg&lt;br /&gt;
Voraussetzung: VisualStudioCode, NodeJS installiert&lt;br /&gt;
&lt;br /&gt;
Ordner erstellen und NodeJS Projekt starten&lt;br /&gt;
&lt;br /&gt;
Terminal&lt;br /&gt;
 npm init -y&lt;br /&gt;
 npm install puppeteer&lt;br /&gt;
&lt;br /&gt;
Installiert auch Chromium. Schau mal in die package.json&lt;br /&gt;
&lt;br /&gt;
Als Basis kommt fast immer ein Konstrukt ähnlich dem folgenden zum Einsatz. Im Wesentlichen passiert folgendes:&lt;br /&gt;
&lt;br /&gt;
index.js erstellen. Puppeteer laden mit asynchroner Funktion. Diese Funktion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;); //pup&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // open a new browser - headless (default) or with displaying&lt;br /&gt;
  const page = await browser.newPage();  // open a new tab&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;); // navigate to a url&lt;br /&gt;
  // do s.th.&lt;br /&gt;
  await browser.close(); // close the browser&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel Screenshot von Seite anfertigen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
  await page.screenshot({path: &amp;quot;screenshot.png&amp;quot;})&lt;br /&gt;
&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Starten mit&lt;br /&gt;
 node index.js&lt;br /&gt;
&lt;br /&gt;
== Beispiel Skripte ==&lt;br /&gt;
Hinweis: Da die Skripte in diesem Setup keine ES Module sind, gab es bei mir Probleme in Node wenn man die Strichpunkte weglässt.&lt;br /&gt;
&lt;br /&gt;
=== DOM Elemente scrapen mit evaluate ===&lt;br /&gt;
Zum Scrapen bietet sich die evaluate Funk&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;)&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  const grabSlogan = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const slogan = document.querySelector(&amp;quot;.uk-text-lead&amp;quot;)&lt;br /&gt;
    //return slogan.innerHTML // with html tags&lt;br /&gt;
    return slogan.innerText // only the text&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  console.log(grabSlogan)&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// grab multiple elements&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//... wie oben&lt;br /&gt;
  const grabList = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const listTags = document.querySelectorAll(&amp;quot;.uk-nav-default li&amp;quot;)&lt;br /&gt;
    let listItems = []&lt;br /&gt;
    listTags.forEach((tag) =&amp;gt; {&lt;br /&gt;
      listItems.push(tag.innerText)&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
    return listItems&lt;br /&gt;
  })&lt;br /&gt;
  console.log(grabList)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Komplexere DOM-Zugriffe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const grab = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    let arrElements = [];&lt;br /&gt;
    const quotes = document.querySelectorAll(&amp;quot;.quote&amp;quot;);&lt;br /&gt;
    quotes.forEach( (quote) =&amp;gt; {&lt;br /&gt;
      const quoteSpans = quote.querySelectorAll(&amp;quot;span&amp;quot;);&lt;br /&gt;
      const quoteText = quoteSpans[0].innerHTML;&lt;br /&gt;
      const quoteAuthor = quoteSpans[1].querySelector(&amp;quot;small&amp;quot;).innerHTML;&lt;br /&gt;
      arrElements.push({&amp;#039;quote&amp;#039;: quoteText, &amp;#039;author&amp;#039;: quoteAuthor});&lt;br /&gt;
    });&lt;br /&gt;
    return arrElements;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  console.log(grab);&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User actions simulieren ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  await page.click(&amp;#039;a[href=&amp;quot;/login&amp;quot;]&amp;#039;); // click login link&lt;br /&gt;
  await page.type(&amp;#039;#username&amp;#039;,&amp;#039;myUserName&amp;#039;,{delay:300});&lt;br /&gt;
  await page.type(&amp;#039;#password&amp;#039;,&amp;#039;mySecret&amp;#039;);&lt;br /&gt;
  await page.click(&amp;#039;input[type=&amp;quot;submit&amp;quot;]&amp;#039;);&lt;br /&gt;
  //await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Computed Styles von DOM Elementen auslesen ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Styles eines DOM Elements&amp;#039;&amp;#039;&amp;#039; finden. Hier nutzen wir mal die $eval Funktion. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const myStyles = await page.$eval(&amp;#039;body&amp;#039;, el =&amp;gt; getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;)&lt;br /&gt;
  );&lt;br /&gt;
  console.log(myStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Handle Functions sind nicht so performant aber eher menschenähnlich. Bei einem Klick würde der Browser tatsächlich die Maus bewegen statt einfach einen Klick Event zu senden.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Evaluate Version&amp;#039;&amp;#039;&amp;#039; - besser zu debuggen Unterschiede in der Ausführung. Siehe: https://stackoverflow.com/questions/55664420/page-evaluate-vs-puppeteer-methods&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;body&amp;#039;);&lt;br /&gt;
    const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;);&lt;br /&gt;
    return myStyle&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;So kann man alle Styles auslesen:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;p&amp;#039;);&lt;br /&gt;
    //const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;); // get a specific style&lt;br /&gt;
    const stylesObject = getComputedStyle(el);&lt;br /&gt;
    const myStyles = {};&lt;br /&gt;
    for (const prop in stylesObject) {&lt;br /&gt;
      if(stylesObject.hasOwnProperty(prop)){ // filter out &lt;br /&gt;
        myStyles[prop] = stylesObject[prop];&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    //return myStyle;&lt;br /&gt;
    return myStyles;&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PDF generieren ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // print pdf&lt;br /&gt;
  await page.pdf({&lt;br /&gt;
    path: &amp;quot;myWebsite.pdf&amp;quot;, // mandatory - rest ist optional&lt;br /&gt;
    format: &amp;#039;A4&amp;#039;, // default is letter&lt;br /&gt;
    margin: {&lt;br /&gt;
      top: &amp;#039;100px&amp;#039;,&lt;br /&gt;
      bottom: &amp;#039;100px&amp;#039;&lt;br /&gt;
    },&lt;br /&gt;
    printBackground: true,&lt;br /&gt;
    displayHeaderFooter: true,&lt;br /&gt;
    headerTemplate: `&amp;lt;p style=&amp;quot;font-size: 10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`,&lt;br /&gt;
    footerTemplate: `&amp;lt;p style=&amp;quot;font-size:10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;pageNumber&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; of &amp;lt;span class=&amp;quot;totalPages&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Crawl multiple pages ===&lt;br /&gt;
 https://stackoverflow.com/questions/46293216/crawling-multiple-urls-in-a-loop-using-puppeteer&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.setDefaultNavigationTimeout(0); // prevent timeout after 30s.&lt;br /&gt;
//...&lt;br /&gt;
urls = [&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;...]&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i &amp;lt; urls.length; i++) {&lt;br /&gt;
    const url = urls[i];&lt;br /&gt;
    await page.goto(`${url}`);&lt;br /&gt;
    await page.waitForNavigation({ waitUntil: &amp;#039;networkidle2&amp;#039; });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Input- und Output-Files ===&lt;br /&gt;
 https://github.com/Zrce/puppeteer-coverage-report-test/blob/master/index.js&lt;br /&gt;
 https://stackoverflow.com/questions/59981135/puppeteer-iterate-over-a-csv-file-and-screenshot-for-each-row&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;CSV Datei mit URLs abarbeiten - seriell/parallel&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
[[Puppeteer - CSV Datei sequentiell / parallel a abarbeiten (Beispiel)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zertifikate und Puppeteer ===&lt;br /&gt;
 [[Puppeteer - Zertifikate handeln]]&lt;br /&gt;
&lt;br /&gt;
=== Network Request Control ===&lt;br /&gt;
 https://github.com/puppeteer/puppeteer/blob/main/examples/block-images.js&lt;br /&gt;
 [[Puppeteer - RequestInterception]]&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_Zertifikate_handeln&amp;diff=26242</id>
		<title>Puppeteer - Zertifikate handeln</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_Zertifikate_handeln&amp;diff=26242"/>
		<updated>2022-09-12T18:09:42Z</updated>

		<summary type="html">&lt;p&gt;Steff: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; https://thedavidbarton.github.io/blog/cert-expiry-puppeteer/&lt;br /&gt;
== Snippets ==&lt;br /&gt;
Zertifikatsdetails holen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const browser = await puppeteer.launch();&lt;br /&gt;
&lt;br /&gt;
const page = await browser.newPage();&lt;br /&gt;
&lt;br /&gt;
const pageUrl = &amp;#039;https://example.com/&amp;#039;&lt;br /&gt;
const response = await page.goto(pageUrl, {waitUntil: &amp;#039;networkidle0&amp;#039;})&lt;br /&gt;
const securityDetails = await response.securityDetails()&lt;br /&gt;
&lt;br /&gt;
console.log(securityDetails)&lt;br /&gt;
console.log(securityDetails.protocol())&lt;br /&gt;
&lt;br /&gt;
await browser.close();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26241</id>
		<title>Puppeteer - NodeJS Scraping</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_NodeJS_Scraping&amp;diff=26241"/>
		<updated>2022-09-12T18:08:59Z</updated>

		<summary type="html">&lt;p&gt;Steff: /* Zertifikate und Puppeteer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Puppeteer ==&lt;br /&gt;
Puppeteer Hauptseite.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://pptr.dev/&lt;br /&gt;
 https://www.youtube.com/watch?v=CngYXf9aeg8&amp;amp;list=PLGreOtbNU07rDURvnQpDaT3XokxlranUQ&lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
 https://advancedweb.hu/how-to-speed-up-puppeteer-scraping-with-parallelization/&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
 https://www.youtube.com/watch?v=Sag-Hz9jJNg&lt;br /&gt;
Voraussetzung: VisualStudioCode, NodeJS installiert&lt;br /&gt;
&lt;br /&gt;
Ordner erstellen und NodeJS Projekt starten&lt;br /&gt;
&lt;br /&gt;
Terminal&lt;br /&gt;
 npm init -y&lt;br /&gt;
 npm install puppeteer&lt;br /&gt;
&lt;br /&gt;
Installiert auch Chromium. Schau mal in die package.json&lt;br /&gt;
&lt;br /&gt;
Als Basis kommt fast immer ein Konstrukt ähnlich dem folgenden zum Einsatz. Im Wesentlichen passiert folgendes:&lt;br /&gt;
&lt;br /&gt;
index.js erstellen. Puppeteer laden mit asynchroner Funktion. Diese Funktion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;); //pup&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // open a new browser - headless (default) or with displaying&lt;br /&gt;
  const page = await browser.newPage();  // open a new tab&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;); // navigate to a url&lt;br /&gt;
  // do s.th.&lt;br /&gt;
  await browser.close(); // close the browser&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel Screenshot von Seite anfertigen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
  await page.screenshot({path: &amp;quot;screenshot.png&amp;quot;})&lt;br /&gt;
&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Starten mit&lt;br /&gt;
 node index.js&lt;br /&gt;
&lt;br /&gt;
== Beispiel Skripte ==&lt;br /&gt;
Hinweis: Da die Skripte in diesem Setup keine ES Module sind, gab es bei mir Probleme in Node wenn man die Strichpunkte weglässt.&lt;br /&gt;
&lt;br /&gt;
=== DOM Elemente scrapen mit evaluate ===&lt;br /&gt;
Zum Scrapen bietet sich die evaluate Funk&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;)&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}) // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage() // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  const grabSlogan = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const slogan = document.querySelector(&amp;quot;.uk-text-lead&amp;quot;)&lt;br /&gt;
    //return slogan.innerHTML // with html tags&lt;br /&gt;
    return slogan.innerText // only the text&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  console.log(grabSlogan)&lt;br /&gt;
  await browser.close()&lt;br /&gt;
}) ()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// grab multiple elements&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//... wie oben&lt;br /&gt;
  const grabList = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    const listTags = document.querySelectorAll(&amp;quot;.uk-nav-default li&amp;quot;)&lt;br /&gt;
    let listItems = []&lt;br /&gt;
    listTags.forEach((tag) =&amp;gt; {&lt;br /&gt;
      listItems.push(tag.innerText)&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
    return listItems&lt;br /&gt;
  })&lt;br /&gt;
  console.log(grabList)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Komplexere DOM-Zugriffe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const grab = await page.evaluate( () =&amp;gt; {&lt;br /&gt;
    let arrElements = [];&lt;br /&gt;
    const quotes = document.querySelectorAll(&amp;quot;.quote&amp;quot;);&lt;br /&gt;
    quotes.forEach( (quote) =&amp;gt; {&lt;br /&gt;
      const quoteSpans = quote.querySelectorAll(&amp;quot;span&amp;quot;);&lt;br /&gt;
      const quoteText = quoteSpans[0].innerHTML;&lt;br /&gt;
      const quoteAuthor = quoteSpans[1].querySelector(&amp;quot;small&amp;quot;).innerHTML;&lt;br /&gt;
      arrElements.push({&amp;#039;quote&amp;#039;: quoteText, &amp;#039;author&amp;#039;: quoteAuthor});&lt;br /&gt;
    });&lt;br /&gt;
    return arrElements;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  console.log(grab);&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User actions simulieren ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: false}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://quotes.toscrape.com/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  await page.click(&amp;#039;a[href=&amp;quot;/login&amp;quot;]&amp;#039;); // click login link&lt;br /&gt;
  await page.type(&amp;#039;#username&amp;#039;,&amp;#039;myUserName&amp;#039;,{delay:300});&lt;br /&gt;
  await page.type(&amp;#039;#password&amp;#039;,&amp;#039;mySecret&amp;#039;);&lt;br /&gt;
  await page.click(&amp;#039;input[type=&amp;quot;submit&amp;quot;]&amp;#039;);&lt;br /&gt;
  //await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Computed Styles von DOM Elementen auslesen ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Styles eines DOM Elements&amp;#039;&amp;#039;&amp;#039; finden. Hier nutzen wir mal die $eval Funktion. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const myStyles = await page.$eval(&amp;#039;body&amp;#039;, el =&amp;gt; getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;)&lt;br /&gt;
  );&lt;br /&gt;
  console.log(myStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Handle Functions sind nicht so performant aber eher menschenähnlich. Bei einem Klick würde der Browser tatsächlich die Maus bewegen statt einfach einen Klick Event zu senden.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Evaluate Version&amp;#039;&amp;#039;&amp;#039; - besser zu debuggen Unterschiede in der Ausführung. Siehe: https://stackoverflow.com/questions/55664420/page-evaluate-vs-puppeteer-methods&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;body&amp;#039;);&lt;br /&gt;
    const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;);&lt;br /&gt;
    return myStyle&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;So kann man alle Styles auslesen:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // get styles of element&lt;br /&gt;
  const getStyles = await page.evaluate( () =&amp;gt;{&lt;br /&gt;
    const el = document.querySelector(&amp;#039;p&amp;#039;);&lt;br /&gt;
    //const myStyle = getComputedStyle(el).getPropertyValue(&amp;#039;font-family&amp;#039;); // get a specific style&lt;br /&gt;
    const stylesObject = getComputedStyle(el);&lt;br /&gt;
    const myStyles = {};&lt;br /&gt;
    for (const prop in stylesObject) {&lt;br /&gt;
      if(stylesObject.hasOwnProperty(prop)){ // filter out &lt;br /&gt;
        myStyles[prop] = stylesObject[prop];&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    //return myStyle;&lt;br /&gt;
    return myStyles;&lt;br /&gt;
  });&lt;br /&gt;
  console.log(getStyles);&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PDF generieren ===&lt;br /&gt;
Siehe auch &lt;br /&gt;
 https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const puppeteer = require(&amp;quot;puppeteer&amp;quot;);&lt;br /&gt;
(async () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
  const browser = await puppeteer.launch({headless: true}); // launch can launch headless or with displaying&lt;br /&gt;
  const page = await browser.newPage(); // open new tab in browser&lt;br /&gt;
  await page.goto(&amp;quot;https://schlegel.media/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // print pdf&lt;br /&gt;
  await page.pdf({&lt;br /&gt;
    path: &amp;quot;myWebsite.pdf&amp;quot;, // mandatory - rest ist optional&lt;br /&gt;
    format: &amp;#039;A4&amp;#039;, // default is letter&lt;br /&gt;
    margin: {&lt;br /&gt;
      top: &amp;#039;100px&amp;#039;,&lt;br /&gt;
      bottom: &amp;#039;100px&amp;#039;&lt;br /&gt;
    },&lt;br /&gt;
    printBackground: true,&lt;br /&gt;
    displayHeaderFooter: true,&lt;br /&gt;
    headerTemplate: `&amp;lt;p style=&amp;quot;font-size: 10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`,&lt;br /&gt;
    footerTemplate: `&amp;lt;p style=&amp;quot;font-size:10px; font-family: Arial, Helvetica, sans-serif; margin: 0 auto;&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;pageNumber&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; of &amp;lt;span class=&amp;quot;totalPages&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;`&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
  await browser.close();&lt;br /&gt;
}) ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Crawl multiple pages ===&lt;br /&gt;
 https://stackoverflow.com/questions/46293216/crawling-multiple-urls-in-a-loop-using-puppeteer&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
page.setDefaultNavigationTimeout(0); // prevent timeout after 30s.&lt;br /&gt;
//...&lt;br /&gt;
urls = [&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;,&amp;#039;url&amp;#039;...]&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i &amp;lt; urls.length; i++) {&lt;br /&gt;
    const url = urls[i];&lt;br /&gt;
    await page.goto(`${url}`);&lt;br /&gt;
    await page.waitForNavigation({ waitUntil: &amp;#039;networkidle2&amp;#039; });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Input- und Output-Files ===&lt;br /&gt;
 https://github.com/Zrce/puppeteer-coverage-report-test/blob/master/index.js&lt;br /&gt;
 https://stackoverflow.com/questions/59981135/puppeteer-iterate-over-a-csv-file-and-screenshot-for-each-row&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;CSV Datei mit URLs abarbeiten - seriell/parallel&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
[[Puppeteer - CSV Datei sequentiell / parallel a abarbeiten (Beispiel)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zertifikate und Puppeteer ===&lt;br /&gt;
 [[Puppeteer - Zertifikate handeln]]&lt;br /&gt;
&lt;br /&gt;
=== Network Request Control ===&lt;br /&gt;
 https://github.com/puppeteer/puppeteer/blob/main/examples/block-images.js&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_Zertifikate_handeln&amp;diff=26240</id>
		<title>Puppeteer - Zertifikate handeln</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Puppeteer_-_Zertifikate_handeln&amp;diff=26240"/>
		<updated>2022-09-12T12:57:32Z</updated>

		<summary type="html">&lt;p&gt;Steff: Die Seite wurde neu angelegt: „ == Snippets == Zertifikatsdetails holen  &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt; const browser = await puppeteer.launch();  const page = await browser.newPage();…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Snippets ==&lt;br /&gt;
Zertifikatsdetails holen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const browser = await puppeteer.launch();&lt;br /&gt;
&lt;br /&gt;
const page = await browser.newPage();&lt;br /&gt;
&lt;br /&gt;
const pageUrl = &amp;#039;https://example.com/&amp;#039;&lt;br /&gt;
const response = await page.goto(pageUrl, {waitUntil: &amp;#039;networkidle0&amp;#039;})&lt;br /&gt;
const securityDetails = await response.securityDetails()&lt;br /&gt;
&lt;br /&gt;
console.log(securityDetails)&lt;br /&gt;
console.log(securityDetails.protocol())&lt;br /&gt;
&lt;br /&gt;
await browser.close();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Steff</name></author>
	</entry>
</feed>